From 99af42e3aaefd289aca8f67a5d62eb3c4356306b Mon Sep 17 00:00:00 2001 From: nageshy Date: Fri, 25 Jul 2025 15:40:37 +0530 Subject: [PATCH 01/12] initial update --- callautomation-lobbycall-sample/.gitignore | 30 ++ callautomation-lobbycall-sample/README.md | 55 +++ callautomation-lobbycall-sample/package.json | 29 ++ callautomation-lobbycall-sample/src/app.ts | 447 ++++++++++++++++++ .../src/webpage/index.html | 164 +++++++ callautomation-lobbycall-sample/tsconfig.json | 13 + 6 files changed, 738 insertions(+) create mode 100644 callautomation-lobbycall-sample/.gitignore create mode 100644 callautomation-lobbycall-sample/README.md create mode 100644 callautomation-lobbycall-sample/package.json create mode 100644 callautomation-lobbycall-sample/src/app.ts create mode 100644 callautomation-lobbycall-sample/src/webpage/index.html create mode 100644 callautomation-lobbycall-sample/tsconfig.json diff --git a/callautomation-lobbycall-sample/.gitignore b/callautomation-lobbycall-sample/.gitignore new file mode 100644 index 00000000..1f45ab17 --- /dev/null +++ b/callautomation-lobbycall-sample/.gitignore @@ -0,0 +1,30 @@ +# Ignore node_modules directory +node_modules/ + +# Ignore environment variables file +.env + +# Ignore build output directory +dist/ +build/ +public/assets/ + +# Ignore IDE/Editor-specific files +.vscode/ +.vs +.idea/ + +# Ignore user-specific configuration files +.npmrc +.gitconfig + +# Ignore log files +*.log + +# Ignore OS-generated files +.DS_Store +Thumbs.db + +# Ignore package lock files +package-lock.json +yarn.lock \ No newline at end of file diff --git a/callautomation-lobbycall-sample/README.md b/callautomation-lobbycall-sample/README.md new file mode 100644 index 00000000..13082a3d --- /dev/null +++ b/callautomation-lobbycall-sample/README.md @@ -0,0 +1,55 @@ + +|page_type|languages|products +|---|---|---| +|sample|
Typescript
|
azureazure-communication-services
| + +# Lobbay Call Sample using Call Automation SDK + +In this quickstart sample, we cover how you can use the Call Automation SDK to perform lobby calls using Azure Communication Services (ACS) calls. This involves creating and managing several outgoing calls simultaneously and dynamically moving participants between these active calls. + +## Prerequisites + +- Create an Azure account with an active subscription. For details, see [Create an account for free](https://azure.microsoft.com/free/) +- [Visual Studio Code](https://code.visualstudio.com/download) installed +- [Node.js](https://nodejs.org/en/download) installed +- Create an Azure Communication Services resource. For details, see [Create an Azure Communication Resource](https://docs.microsoft.com/azure/communication-services/quickstarts/create-communication-resource). You will need to record your resource **connection string** for this sample. +- Get a phone number for your new Azure Communication Services resource. For details, see [Get a phone number](https://learn.microsoft.com/azure/communication-services/quickstarts/telephony/get-phone-number?tabs=windows&pivots=programming-language-csharp) + +## Before running the sample for the first time + +1. Open an instance of PowerShell, Windows Terminal, Command Prompt or equivalent and navigate to the directory that you would like to clone the sample to. +2. git clone `https://github.com/Azure-Samples/communication-services-javascript-quickstarts.git`. +3. cd into the `callautomation-lobbycall-sample` folder. +4. From the root of the above folder, and with node installed, run `npm install` + +### Setup and host your Azure DevTunnel + +[Azure DevTunnels](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/get-started?tabs=windows) is an Azure service that enables you to share local web services hosted on the internet. Use the commands below to connect your local development environment to the public internet. This creates a tunnel with a persistent endpoint URL and which allows anonymous access. We will then use this endpoint to notify your application of calling events from the ACS Call Automation service. + +```bash +devtunnel create --allow-anonymous +devtunnel port create -p 8080 +devtunnel host +``` + +### Configuring application + +Create/Open the `.env` file to configure the following settings + +1. `PORT`: Assign constant 8080 +2. `CONNECTION_STRING`: Azure Communication Service resource's connection string. +3. `ACS_INBOUND_PHONE_NUMBER`: Inbound Phone number associated with the Azure Communication Service resource. For e.g. "+1425XXXAAAA" +4. `ACS_OUTBOUND_PHONE_NUMBER`: Outbound Phone number associated with the Azure Communication Service resource. For e.g. "+1425XXXAAAA" +5. `USER_PHONE_NUMBER`: User phone number to add in the call. For e.g. "+1425XXXAAAA" +6. `ACS_TEST_IDENTITY_2`: An ACS Communication Identifier to add in the call. +7. `ACS_TEST_IDENTITY_3`: Another ACS Communication Identifier to add in the call. +8. `CALLBACK_URI`: Base url of the app. (For local development replace the dev tunnel url) +9. `COGNITIVE_SERVICES_ENDPOINT` : Cognitive service endpoint. + +### Run app locally + +1. Open a new Powershell window, cd into the `callautomation-lobbycall-sample` folder and run `npm run dev` +2. Browser should pop up with the below page. If not navigate it to `http://localhost:8080/` +3. Follow the steps. + + diff --git a/callautomation-lobbycall-sample/package.json b/callautomation-lobbycall-sample/package.json new file mode 100644 index 00000000..57a994cf --- /dev/null +++ b/callautomation-lobbycall-sample/package.json @@ -0,0 +1,29 @@ +{ + "name": "callautomation_lobbycall", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "build": "tsc", + "dev": "nodemon ./src/app.ts" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@azure/communication-call-automation": "^1.5.0", + "@azure/communication-common": "^2.2.0", + "@azure/communication-identity": "^1.3.1", + "@azure/communication-rooms": "^1.1.1", + "@azure/eventgrid": "^4.12.0", + "@types/express": "^4.17.17", + "@types/node": "^20.2.1", + "dotenv": "^16.0.3", + "express": "^4.18.2" + }, + "devDependencies": { + "nodemon": "^2.0.22", + "ts-node": "^10.9.1", + "typescript": "^5.0.4" + } +} diff --git a/callautomation-lobbycall-sample/src/app.ts b/callautomation-lobbycall-sample/src/app.ts new file mode 100644 index 00000000..679efc58 --- /dev/null +++ b/callautomation-lobbycall-sample/src/app.ts @@ -0,0 +1,447 @@ +import { config } from 'dotenv'; +import express, { Application } from 'express'; +import { CommunicationUserIdentifier, PhoneNumberIdentifier } from "@azure/communication-common"; +import { + CallAutomationClient, + CallInvite, + AnswerCallOptions, + MoveParticipantsOptions +} from "@azure/communication-call-automation"; + +config(); + +const PORT = process.env.PORT; +const app: Application = express(); +app.use(express.static('webpage')); +app.use(express.urlencoded({ extended: true })); +app.use(express.json()); + +let callConnectionId1: string; +let callConnectionId2: string; +let callConnectionId3: string; +let acsInboundPhoneNumber: string; +let acsOutboundPhoneNumber: string; +let userPhoneNumber: string; +let acsTestIdentity2: string; +let acsTestIdentity3: string; +let acsClient: CallAutomationClient; +let lastWorkflowCallType: string; +let callerId1: string; +let callerId2: string; +let callerId3: string; +let calleeId1: string; +let calleeId2: string; +let calleeId3: string; +const callbackUriHost = process.env.CALLBACK_URI || ""; +const connectionString = process.env.CONNECTION_STRING || "" +const endpoint = process.env.PMA_ENDPOINT || "" + +async function createAcsClient() { + callConnectionId1 = ""; + callConnectionId2 = ""; + callConnectionId3 = ""; + acsInboundPhoneNumber = process.env.ACS_INBOUND_PHONE_NUMBER || ""; + acsOutboundPhoneNumber = process.env.ACS_OUTBOUND_PHONE_NUMBER || ""; + userPhoneNumber = process.env.USER_PHONE_NUMBER || ""; + acsTestIdentity2 = process.env.ACS_TEST_IDENTITY_2 || ""; + acsTestIdentity3 = process.env.ACS_TEST_IDENTITY_3 || ""; + lastWorkflowCallType = ""; + callerId1 = ""; + callerId2 = ""; + callerId3 = ""; + calleeId1 = ""; + calleeId2 = ""; + calleeId3 = ""; + // acsClient = new CallAutomationClient(endpoint, connectionString); + acsClient = new CallAutomationClient(connectionString); + console.log("Initialized ACS Client."); +} + +app.get('/userCallToCallAutomation', async (req, res) => { + console.log("--------- UserCallToCallAutomation - Call 1 API Endpoint -------------------"); + try { + const callbackUri = new URL('/api/callbacks', callbackUriHost).toString(); + const callee : PhoneNumberIdentifier = { + phoneNumber: acsInboundPhoneNumber + }; + const callInvite : CallInvite = { + targetParticipant: callee, + sourceCallIdNumber: { + phoneNumber: userPhoneNumber, + }, + }; + const options = { + callIntelligenceOptions: { + cognitiveServicesEndpoint: process.env.COGNITIVE_SERVICES_ENDPOINT + }, + operationContext: 'CallOne' + }; + var createCallResult = await acsClient.createCall(callInvite, callbackUri, options); + callConnectionId1 = createCallResult.callConnectionProperties.callConnectionId; + callerId1 = userPhoneNumber; + calleeId1 = acsInboundPhoneNumber; + + console.log("=== Call From User to Call Automation ==="); + console.log(`Created call from ${userPhoneNumber} to ${acsOutboundPhoneNumber}`); + console.log(`Connection ID: ${callConnectionId1}`); + console.log("=== END WORKFLOW INITIATION ==="); + } catch (err) { + console.error('Error creating call:', err); + } + res.redirect('/'); +}); + +app.get('/createCall2', async (req, res) => { + console.log('--------- createCall2 - Call 2 API Endpoint " -------------------'); + try { + const callbackUri = new URL('/api/callbacks', callbackUriHost).toString(); + const callee : PhoneNumberIdentifier = { + phoneNumber: acsOutboundPhoneNumber + }; + const callInvite : CallInvite = { + targetParticipant: callee, + sourceCallIdNumber: { + phoneNumber: acsInboundPhoneNumber, + }, + }; + const options = { + callIntelligenceOptions: { + cognitiveServicesEndpoint: process.env.COGNITIVE_SERVICES_ENDPOINT + }, + operationContext: 'CallTwo' + }; + var createCallResult = await acsClient.createCall(callInvite, callbackUri, options); + callConnectionId2 = createCallResult.callConnectionProperties.callConnectionId; + // Track this as Call 2 + lastWorkflowCallType = "CallTwo"; + callerId2 = acsInboundPhoneNumber; + calleeId2 = acsOutboundPhoneNumber; + + console.log('=== CALL TWO WORKFLOW INITIATED ==='); + console.log(`Created call from ${acsInboundPhoneNumber} to ${acsOutboundPhoneNumber}`); + console.log(`Connection ID: ${callConnectionId2}`); + console.log(`This call should trigger MoveParticipantEvent (Scenario 2) which will redirect to ACS user ${acsTestIdentity2}`); + console.log('Operation Context: CallTwo'); + console.log('=== END WORKFLOW INITIATION ==='); + } catch (err) { + console.error('Error creating call:', err); + } + res.redirect('/'); +}); + +app.get('/createCall3', async (req, res) => { + console.log('--------- createCall3 - Call 3 API Endpoint " -------------------'); + try { + const callbackUri = new URL('/api/callbacks', callbackUriHost).toString(); + const callee : PhoneNumberIdentifier = { + phoneNumber: acsOutboundPhoneNumber + }; + const callInvite : CallInvite = { + targetParticipant: callee, + sourceCallIdNumber: { + phoneNumber: acsInboundPhoneNumber, + }, + }; + const options = { + callIntelligenceOptions: { + cognitiveServicesEndpoint: process.env.COGNITIVE_SERVICES_ENDPOINT + }, + operationContext: 'CallThree' + }; + var createCallResult = await acsClient.createCall(callInvite, callbackUri, options); + callConnectionId3 = createCallResult.callConnectionProperties.callConnectionId; + // Track this as Call 2 + lastWorkflowCallType = "CallThree"; + callerId3 = acsInboundPhoneNumber; + calleeId3 = acsOutboundPhoneNumber; + + console.log('=== CALL THREE WORKFLOW INITIATED ==='); + console.log(`Created call from ${acsInboundPhoneNumber} to ${acsOutboundPhoneNumber}`); + console.log(`Connection ID: ${callConnectionId3}`); + console.log(`This call should trigger MoveParticipantEvent (Scenario 3) which will redirect to ACS user ${acsTestIdentity3}`); + console.log('Operation Context: CallThree'); + console.log('=== END WORKFLOW INITIATION ==='); + } catch (err) { + console.error('Error creating call:', err); + } + res.redirect('/'); +}); + +app.get('/moveParticipant2', async (req, res) => { + console.log('--------- MoveParticipant API End Point -------------------'); + + try { + const request = req.body; + console.log('=== MANUAL MOVE PARTICIPANT REQUESTED ==='); + console.log(`Source Connection ID: ${callConnectionId2}`); + console.log(`Target Connection ID: ${callConnectionId1}`); + console.log(`Participant to Move: ${acsOutboundPhoneNumber}`); + + // Get the target connection (where we want to move participants to) + const targetConnection = acsClient.getCallConnection(callConnectionId1); + + // Get participants from source connection for reference (optional) + const sourceConnection = acsClient.getCallConnection(callConnectionId2); + + // Create participant identifier based on the input + let participantToMove; + if (acsOutboundPhoneNumber.startsWith('+')) { + // Phone number + participantToMove = { phoneNumber: acsOutboundPhoneNumber }; + console.log(`Moving phone number participant: ${acsOutboundPhoneNumber}`); + } else if (acsOutboundPhoneNumber.startsWith('8:acs:')) { + // ACS Communication User + participantToMove = { communicationUserId: acsOutboundPhoneNumber }; + console.log(`Moving ACS user participant: ${acsOutboundPhoneNumber}`); + } else { + console.log("Invalid participant format. Use phone number (+1234567890) or ACS user ID (8:acs:...)"); + } + + // Prepare move participants options + const options : MoveParticipantsOptions = { + operationContext: "MoveParticipant2" + }; + + // Call the ACS SDK to move participants + await targetConnection.moveParticipants([participantToMove], callConnectionId2, options); + callConnectionId2 = ""; + callerId2 = ""; + calleeId2 = ""; + calleeId1 = acsTestIdentity2; + + // For demonstration, assume success + console.log('Move Participants operation completed successfully'); + console.log(`Moved ${acsTestIdentity2} from ${callConnectionId2} to ${callConnectionId1}`); + console.log('=== MOVE PARTICIPANTS OPERATION COMPLETE ==='); + } catch (err) { + console.error(`Error in manual move participant operation: ${err.message}`); + } + res.redirect('/'); +}); + +app.get('/moveParticipant3', async (req, res) => { + console.log('--------- MoveParticipant API End Point -------------------'); + + try { + const request = req.body; + console.log('=== MANUAL MOVE PARTICIPANT REQUESTED ==='); + console.log(`Source Connection ID: ${callConnectionId3}`); + console.log(`Target Connection ID: ${callConnectionId1}`); + console.log(`Participant to Move: ${acsOutboundPhoneNumber}`); + + // Get the target connection (where we want to move participants to) + const targetConnection = acsClient.getCallConnection(callConnectionId1); + + // Get participants from source connection for reference (optional) + const sourceConnection = acsClient.getCallConnection(callConnectionId3); + + // Create participant identifier based on the input + let participantToMove; + if (acsOutboundPhoneNumber.startsWith('+')) { + // Phone number + participantToMove = { phoneNumber: acsOutboundPhoneNumber }; + console.log(`Moving phone number participant: ${acsOutboundPhoneNumber}`); + } else if (acsOutboundPhoneNumber.startsWith('8:acs:')) { + // ACS Communication User + participantToMove = { communicationUserId: acsOutboundPhoneNumber }; + console.log(`Moving ACS user participant: ${acsOutboundPhoneNumber}`); + } else { + console.log("Invalid participant format. Use phone number (+1234567890) or ACS user ID (8:acs:...)"); + } + + // Prepare move participants options + const options : MoveParticipantsOptions = { + operationContext: "MoveParticipant3" + }; + + // Call the ACS SDK to move participants + await targetConnection.moveParticipants([participantToMove], callConnectionId3, options); + callConnectionId3 = ""; + callerId3 = ""; + calleeId3 = ""; + calleeId1 = acsTestIdentity3; + + // For demonstration, assume success + console.log('Move Participants operation completed successfully'); + console.log(`Moved ${acsTestIdentity3} from ${callConnectionId3} to ${callConnectionId1}`); + console.log('=== MOVE PARTICIPANTS OPERATION COMPLETE ==='); + } catch (err) { + console.error(`Error in manual move participant operation: ${err.message}`); + } + res.redirect('/'); +}); + +app.get('/terminateCalls', async (req, res) => { + console.log(`calls 1: ${callConnectionId1}, 2: ${callConnectionId2}, 3: ${callConnectionId3}`); + if (callConnectionId1) { + try { + console.log(`Terminating Call 1 with ID: ${callConnectionId1}`); + const callConnection1 = acsClient.getCallConnection(callConnectionId1); + await callConnection1.hangUp(true); + } catch (error) { + console.error(`Error terminating Call 1: ${error.message}`); + } + } + if (callConnectionId2) { + try { + console.log(`Terminating Call 2 with ID: ${callConnectionId2}`); + const callConnection2 = acsClient.getCallConnection(callConnectionId2); + await callConnection2.hangUp(true); + } catch (error) { + console.error(`Error terminating Call 2: ${error.message}`); + } + } + if (callConnectionId3) { + try { + console.log(`Terminating Call 3 with ID: ${callConnectionId3}`); + const callConnection3 = acsClient.getCallConnection(callConnectionId3); + await callConnection3.hangUp(true); + } catch (error) { + console.error(`Error terminating Call 3: ${error.message}`); + } + } + console.log("Calls hung up successfully."); + callConnectionId1 = ""; + callConnectionId2 = ""; + callConnectionId3 = ""; + callerId1 = ""; + callerId2 = ""; + callerId3 = ""; + calleeId1 = ""; + calleeId2 = ""; + calleeId3 = ""; + res.redirect('/'); +}); + +app.post('/api/moveParticipantEvent', async (req, res) => { + console.log('--------- /api/moveParticipantEvent -------------------'); + const event = req.body[0]; + const eventData = event.data; + if (event.eventType === "Microsoft.EventGrid.SubscriptionValidationEvent") { + console.log("SubscriptionValidation event"); + res.status(200).json({ + validationResponse: eventData.validationCode, + }); + return; + } + + // ACS Incoming Call event + if (event.eventType === 'Microsoft.Communication.IncomingCall') { + const fromCallerId = eventData.from.rawId; + const toCallerId = eventData.to.rawId; + + console.log(`From Caller Id: ${fromCallerId}`); + console.log(`To Caller Id : ${toCallerId}`); + + // Scenario 1: User calls from their phone number to ACS inbound number + if (fromCallerId.includes(userPhoneNumber)) { + console.log('=== SCENARIO 1: USER INCOMING CALL ==='); + + const callbackUri = new URL('/api/callbacks', callbackUriHost).toString(); + const options : AnswerCallOptions = { + operationContext: "CallOne" + }; + + //console.log(`Incoming call context: ${eventData.incomingCallContext}`); + var answerCallResult = await acsClient.answerCall(eventData.incomingCallContext, callbackUri, options); + callConnectionId1 = answerCallResult.callConnectionProperties.callConnectionId; + + console.log(`User Call Answered - CallConnectionId: ${callConnectionId1}`); + console.log(`Correlation Id: ${eventData.correlationId}`); + console.log('Operation Context: CallOne'); + console.log('=== END SCENARIO 1 ==='); + } + // Scenario 2: ACS inbound number calls ACS outbound number (workflow triggered) + else if (fromCallerId.includes(acsInboundPhoneNumber)) { + console.log('=== SCENARIO 2: WORKFLOW CALL TO BE REDIRECTED ==='); + console.log(`Last Workflow Call Type: ${lastWorkflowCallType}`); + + // Check which type of workflow call this is and redirect accordingly + let redirectTarget; + if (lastWorkflowCallType === 'CallTwo') { + // Redirect the call to ACS User Identity 2 + redirectTarget = acsTestIdentity2; + const callee : CommunicationUserIdentifier = { + communicationUserId: redirectTarget + }; + const callInvite : CallInvite = { + targetParticipant: callee + }; + //console.log(`Incoming call context: ${eventData.incomingCallContext}`); + var redirectCallResult = await acsClient.redirectCall(eventData.incomingCallContext, callInvite); + console.log('PROCESSING CALL TWO - Redirecting to ACS User Identity 2'); + } else if (lastWorkflowCallType === 'CallThree') { + // Redirect the call to ACS User Identity 3 + redirectTarget = acsTestIdentity3; + const callee : CommunicationUserIdentifier = { + communicationUserId: redirectTarget + }; + const callInvite : CallInvite = { + targetParticipant: callee + }; + //console.log(`Incoming call context: ${eventData.incomingCallContext}`); + var redirectCallResult = await acsClient.redirectCall(eventData.incomingCallContext, callInvite); + console.log('PROCESSING CALL THREE - Redirecting to ACS User Identity 3'); + } + console.log('=== END SCENARIO 2 ==='); + } + } + res.status(200).send(); +}); + +app.post('/api/callbacks', async (req, res) => { + console.log('--------- /api/callbacks -------------------'); + const event = req.body[0]; + const eventData = event.data; + // For demonstration, log the event type and IDs + console.log(`Received call event: ${event.type}`); + console.log(`Correlation id:-> ${eventData.correlationId}`) + if (event.type === "Microsoft.Communication.CallConnected") { + console.log('\n--------- CallConnected Event Block -------------------'); + switch (eventData.operationContext) { + case 'CallOne': + //callConnectionId1 = callConnectionId; + console.log('=== CALL ONE CONNECTED ==='); + console.log('User call connected'); + console.log('=== END CALL ONE CONNECTED ==='); + break; + case 'CallTwo': + //callConnectionId2 = callConnectionId; + calleeId2 = acsTestIdentity2; + console.log('=== CALL TWO CONNECTED ==='); + console.log('User call connected'); + console.log('=== END CALL TWO CONNECTED ==='); + break; + case 'CallThree': + //callConnectionId3 = callConnectionId; + calleeId3 = acsTestIdentity3; + console.log('=== CALL THREE CONNECTED ==='); + console.log('User call connected'); + console.log('=== END CALL THREE CONNECTED ==='); + break; + } + } else if (event.type === 'Microsoft.Communication.CallDisconnected') { + console.log(`Call disconnected: ${eventData.callConnectionId}`); + } else { + // Log other events but don't process them for Move Participants scenario + console.log(`Received event: ${event.type} - No action needed for Move Participants scenario`); + } + res.status(200).send(); +}); + +app.get('/call-data', (req, res) => { + console.log("Call Data Endpoint Hit"); + console.log(`call 1: ${callConnectionId1}, call 2: ${callConnectionId2}, call 3: ${callConnectionId3}`); + res.json({ callConnectionId1, callConnectionId2, callConnectionId3, callerId1, callerId2, callerId3, calleeId1, calleeId2, calleeId3 }); +}); + +// GET endpoint to serve the webpage +app.get('/', (req, res) => { + res.sendFile('index.html', { root: 'src/webpage' }); +}); + +// Start the server +app.listen(PORT, async () => { + console.log(`Server is listening on port ${PORT}`); + await createAcsClient(); +}); diff --git a/callautomation-lobbycall-sample/src/webpage/index.html b/callautomation-lobbycall-sample/src/webpage/index.html new file mode 100644 index 00000000..30f53350 --- /dev/null +++ b/callautomation-lobbycall-sample/src/webpage/index.html @@ -0,0 +1,164 @@ + + + + + Azure Communication Services Quickstart + + + + +

Lobby Call Sample

+
+ + + + + + + + + +
Call ConnectionsCall Details
+
+
STEP 0. Assign Environment Variables
+
Configure environment variables in the .env file
+
+

+

STEP 1. Configure Webhook
+
Configure Event Grid webhook to point to /api/MoveParticipantEvent endpoint
+

+

+

STEP 2. Make a Call
+
Make a call from User Phone Number to ACS Inbound Phone Number by clicking on this button
+ +

+

+

STEP 3a. Create Call 2
+
Create a Call for ACS Test Identity 2 by clicking on this button and answer it manually from Web Client App
+ +

+

+

STEP 3b. Create Call 3
+
Create a Call for ACS Test Identity 3 by clicking on this button and answer it manually from Web Client App
+ +

+

+

STEP 4a. Move Call
+
Move Call for ACS Test Identity 2 to Initial Call
+ +

+

+

STEP 4b. Move Call
+
Move Call for ACS Test Identity 3 to Initial Call
+ +

+

+

STEP 5. Terminate Calls
+
Terminate all Calls created so far
+ +

+
+
+
Call Connection 1
+
Call Connection Id: Loading call Id...
+
Caller Id: Loading caller Id...
+
Callee Id: Loading callee Id...
+
+

+

Call Connection 2
+
Call Connection Id: Loading call Id...
+
Caller Id: Loading caller Id...
+
Callee Id: Loading callee Id...
+

+

+

Call Connection 3
+
Call Connection Id: Loading call Id...
+
Caller Id: Loading caller Id...
+
Callee Id: Loading callee Id...
+

+
+
+ + + + \ No newline at end of file diff --git a/callautomation-lobbycall-sample/tsconfig.json b/callautomation-lobbycall-sample/tsconfig.json new file mode 100644 index 00000000..c67252ac --- /dev/null +++ b/callautomation-lobbycall-sample/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "ES2015", + "module": "commonjs", + "outDir": "./dist", + "rootDir": "./src", + "moduleResolution": "node", + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["./src"] +} \ No newline at end of file From 1a4c75901cb9234148bd609053a8dcdeb7ce19eb Mon Sep 17 00:00:00 2001 From: nageshy Date: Sat, 26 Jul 2025 11:01:24 +0530 Subject: [PATCH 02/12] initial update --- callautomation-lobbycall-sample/README.md | 14 +- callautomation-lobbycall-sample/src/app.ts | 578 +++++++++------------ 2 files changed, 248 insertions(+), 344 deletions(-) diff --git a/callautomation-lobbycall-sample/README.md b/callautomation-lobbycall-sample/README.md index 13082a3d..22595677 100644 --- a/callautomation-lobbycall-sample/README.md +++ b/callautomation-lobbycall-sample/README.md @@ -38,18 +38,14 @@ Create/Open the `.env` file to configure the following settings 1. `PORT`: Assign constant 8080 2. `CONNECTION_STRING`: Azure Communication Service resource's connection string. -3. `ACS_INBOUND_PHONE_NUMBER`: Inbound Phone number associated with the Azure Communication Service resource. For e.g. "+1425XXXAAAA" -4. `ACS_OUTBOUND_PHONE_NUMBER`: Outbound Phone number associated with the Azure Communication Service resource. For e.g. "+1425XXXAAAA" -5. `USER_PHONE_NUMBER`: User phone number to add in the call. For e.g. "+1425XXXAAAA" -6. `ACS_TEST_IDENTITY_2`: An ACS Communication Identifier to add in the call. -7. `ACS_TEST_IDENTITY_3`: Another ACS Communication Identifier to add in the call. -8. `CALLBACK_URI`: Base url of the app. (For local development replace the dev tunnel url) -9. `COGNITIVE_SERVICES_ENDPOINT` : Cognitive service endpoint. +3. `COGNITIVE_SERVICES_ENDPOINT` : Cognitive service endpoint. +4. `CALLBACK_URI`: Base url of the app. (For local development replace the dev tunnel url) +5. `PMA_ENDPOINT`: PMA endpoint url +6. `ACS_GENERATED_ID`: ACS Generated Id +7. `SOCKET_TOKEN`: Web Socket Token Key ### Run app locally 1. Open a new Powershell window, cd into the `callautomation-lobbycall-sample` folder and run `npm run dev` 2. Browser should pop up with the below page. If not navigate it to `http://localhost:8080/` 3. Follow the steps. - - diff --git a/callautomation-lobbycall-sample/src/app.ts b/callautomation-lobbycall-sample/src/app.ts index 679efc58..1200eba5 100644 --- a/callautomation-lobbycall-sample/src/app.ts +++ b/callautomation-lobbycall-sample/src/app.ts @@ -16,304 +16,222 @@ app.use(express.static('webpage')); app.use(express.urlencoded({ extended: true })); app.use(express.json()); -let callConnectionId1: string; -let callConnectionId2: string; -let callConnectionId3: string; -let acsInboundPhoneNumber: string; -let acsOutboundPhoneNumber: string; -let userPhoneNumber: string; -let acsTestIdentity2: string; -let acsTestIdentity3: string; +let lobbyCallConnectionId: string; +let targetCallConnectionId: string; +let acsGeneratedId: string; let acsClient: CallAutomationClient; -let lastWorkflowCallType: string; -let callerId1: string; -let callerId2: string; -let callerId3: string; -let calleeId1: string; -let calleeId2: string; -let calleeId3: string; +let lobbyCallerId: string; const callbackUriHost = process.env.CALLBACK_URI || ""; const connectionString = process.env.CONNECTION_STRING || "" const endpoint = process.env.PMA_ENDPOINT || "" +let webSocket = null; async function createAcsClient() { - callConnectionId1 = ""; - callConnectionId2 = ""; - callConnectionId3 = ""; - acsInboundPhoneNumber = process.env.ACS_INBOUND_PHONE_NUMBER || ""; - acsOutboundPhoneNumber = process.env.ACS_OUTBOUND_PHONE_NUMBER || ""; - userPhoneNumber = process.env.USER_PHONE_NUMBER || ""; - acsTestIdentity2 = process.env.ACS_TEST_IDENTITY_2 || ""; - acsTestIdentity3 = process.env.ACS_TEST_IDENTITY_3 || ""; - lastWorkflowCallType = ""; - callerId1 = ""; - callerId2 = ""; - callerId3 = ""; - calleeId1 = ""; - calleeId2 = ""; - calleeId3 = ""; + lobbyCallConnectionId = ""; + targetCallConnectionId = ""; + acsGeneratedId = process.env.ACS_GENERATED_ID || ""; + lobbyCallerId = ""; // acsClient = new CallAutomationClient(endpoint, connectionString); acsClient = new CallAutomationClient(connectionString); console.log("Initialized ACS Client."); } -app.get('/userCallToCallAutomation', async (req, res) => { - console.log("--------- UserCallToCallAutomation - Call 1 API Endpoint -------------------"); - try { - const callbackUri = new URL('/api/callbacks', callbackUriHost).toString(); - const callee : PhoneNumberIdentifier = { - phoneNumber: acsInboundPhoneNumber - }; - const callInvite : CallInvite = { - targetParticipant: callee, - sourceCallIdNumber: { - phoneNumber: userPhoneNumber, - }, - }; - const options = { - callIntelligenceOptions: { - cognitiveServicesEndpoint: process.env.COGNITIVE_SERVICES_ENDPOINT - }, - operationContext: 'CallOne' - }; - var createCallResult = await acsClient.createCall(callInvite, callbackUri, options); - callConnectionId1 = createCallResult.callConnectionProperties.callConnectionId; - callerId1 = userPhoneNumber; - calleeId1 = acsInboundPhoneNumber; - - console.log("=== Call From User to Call Automation ==="); - console.log(`Created call from ${userPhoneNumber} to ${acsOutboundPhoneNumber}`); - console.log(`Connection ID: ${callConnectionId1}`); - console.log("=== END WORKFLOW INITIATION ==="); - } catch (err) { - console.error('Error creating call:', err); +const http = require('http'); +const WebSocket = require('ws'); +const server = http.createServer(app); + +// WebSocket server setup +const wss = new WebSocket.Server({ noServer: true }); + +server.on('upgrade', (request, socket, head) => { + // Only accept connections to the correct path + const url = request.url || ''; + if (url === `/ws/${process.env.SOCKET_TOKEN}`) { + wss.handleUpgrade(request, socket, head, function done(ws) { + wss.emit('connection', ws, request); + }); + } else { + socket.destroy(); } - res.redirect('/'); }); -app.get('/createCall2', async (req, res) => { - console.log('--------- createCall2 - Call 2 API Endpoint " -------------------'); - try { - const callbackUri = new URL('/api/callbacks', callbackUriHost).toString(); - const callee : PhoneNumberIdentifier = { - phoneNumber: acsOutboundPhoneNumber - }; - const callInvite : CallInvite = { - targetParticipant: callee, - sourceCallIdNumber: { - phoneNumber: acsInboundPhoneNumber, - }, - }; - const options = { - callIntelligenceOptions: { - cognitiveServicesEndpoint: process.env.COGNITIVE_SERVICES_ENDPOINT - }, - operationContext: 'CallTwo' - }; - var createCallResult = await acsClient.createCall(callInvite, callbackUri, options); - callConnectionId2 = createCallResult.callConnectionProperties.callConnectionId; - // Track this as Call 2 - lastWorkflowCallType = "CallTwo"; - callerId2 = acsInboundPhoneNumber; - calleeId2 = acsOutboundPhoneNumber; - - console.log('=== CALL TWO WORKFLOW INITIATED ==='); - console.log(`Created call from ${acsInboundPhoneNumber} to ${acsOutboundPhoneNumber}`); - console.log(`Connection ID: ${callConnectionId2}`); - console.log(`This call should trigger MoveParticipantEvent (Scenario 2) which will redirect to ACS user ${acsTestIdentity2}`); - console.log('Operation Context: CallTwo'); - console.log('=== END WORKFLOW INITIATION ==='); - } catch (err) { - console.error('Error creating call:', err); - } - res.redirect('/'); -}); +wss.on('connection', (ws) => { + webSocket = ws; + console.log('Received WEB SOCKET request.'); + + ws.on('message', async (message) => { + const jsResponse = message.toString(); + console.log(`Received from JS: ${jsResponse}`); + + // Move participant to target call if response is "yes" + if (jsResponse.trim().toLowerCase() === 'yes') { + console.log('TODO: Move Participant'); + try { + console.log(` + ~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~ + Move Participant operation started.. + Source Caller Id: ${lobbyCallerId} + Source Connection Id: ${lobbyCallConnectionId} + Target Connection Id: ${targetCallConnectionId} + `); + + // Get the target connection + const targetConnection = acsClient.getCallConnection(targetCallConnectionId); + + // Get participants from source connection for reference + // const sourceConnection = client.getCallConnection(lobbyConnectionId); + + // Create participant identifier based on the input + let participantToMove; + if (lobbyCallerId.startsWith('+')) { + // Phone number + participantToMove = new PhoneNumberIdentifier(lobbyCallerId); + } else { + // ACS Communication User + participantToMove = new CommunicationUserIdentifier(lobbyCallerId); + } + + const response = await targetConnection.moveParticipants({ + participantsToMove: [participantToMove], + sourceCallConnectionId: lobbyCallConnectionId + }); + const rawResponse = response._response; + if (rawResponse.status >= 200 && rawResponse.status <= 299) { + console.log(); + console.log('Move Participants operation completed successfully.'); + } else { + throw new Error(`Move Participants operation failed with status code: ${rawResponse.status}`); + } + } catch (ex) { + console.log(`Error in manual move participants operation: ${ex.message}`); + } + } + }); -app.get('/createCall3', async (req, res) => { - console.log('--------- createCall3 - Call 3 API Endpoint " -------------------'); - try { - const callbackUri = new URL('/api/callbacks', callbackUriHost).toString(); - const callee : PhoneNumberIdentifier = { - phoneNumber: acsOutboundPhoneNumber - }; - const callInvite : CallInvite = { - targetParticipant: callee, - sourceCallIdNumber: { - phoneNumber: acsInboundPhoneNumber, - }, - }; - const options = { - callIntelligenceOptions: { - cognitiveServicesEndpoint: process.env.COGNITIVE_SERVICES_ENDPOINT - }, - operationContext: 'CallThree' - }; - var createCallResult = await acsClient.createCall(callInvite, callbackUri, options); - callConnectionId3 = createCallResult.callConnectionProperties.callConnectionId; - // Track this as Call 2 - lastWorkflowCallType = "CallThree"; - callerId3 = acsInboundPhoneNumber; - calleeId3 = acsOutboundPhoneNumber; - - console.log('=== CALL THREE WORKFLOW INITIATED ==='); - console.log(`Created call from ${acsInboundPhoneNumber} to ${acsOutboundPhoneNumber}`); - console.log(`Connection ID: ${callConnectionId3}`); - console.log(`This call should trigger MoveParticipantEvent (Scenario 3) which will redirect to ACS user ${acsTestIdentity3}`); - console.log('Operation Context: CallThree'); - console.log('=== END WORKFLOW INITIATION ==='); - } catch (err) { - console.error('Error creating call:', err); - } - res.redirect('/'); + ws.on('close', () => { + webSocket = null; + }); }); -app.get('/moveParticipant2', async (req, res) => { - console.log('--------- MoveParticipant API End Point -------------------'); +app.get('/TargetCallToAcsUser(Create)', async (req, res) => { + const acsTarget = req.body.acsTarget; // expects { "acsTarget": "" } + console.log('\n~~~~~~~~~~~~ /TargetCall(Create) ~~~~~~~~~~~~\n'); try { - const request = req.body; - console.log('=== MANUAL MOVE PARTICIPANT REQUESTED ==='); - console.log(`Source Connection ID: ${callConnectionId2}`); - console.log(`Target Connection ID: ${callConnectionId1}`); - console.log(`Participant to Move: ${acsOutboundPhoneNumber}`); - - // Get the target connection (where we want to move participants to) - const targetConnection = acsClient.getCallConnection(callConnectionId1); - - // Get participants from source connection for reference (optional) - const sourceConnection = acsClient.getCallConnection(callConnectionId2); - - // Create participant identifier based on the input - let participantToMove; - if (acsOutboundPhoneNumber.startsWith('+')) { - // Phone number - participantToMove = { phoneNumber: acsOutboundPhoneNumber }; - console.log(`Moving phone number participant: ${acsOutboundPhoneNumber}`); - } else if (acsOutboundPhoneNumber.startsWith('8:acs:')) { - // ACS Communication User - participantToMove = { communicationUserId: acsOutboundPhoneNumber }; - console.log(`Moving ACS user participant: ${acsOutboundPhoneNumber}`); - } else { - console.log("Invalid participant format. Use phone number (+1234567890) or ACS user ID (8:acs:...)"); - } - - // Prepare move participants options - const options : MoveParticipantsOptions = { - operationContext: "MoveParticipant2" + const callbackUri = `${callbackUriHost}/api/callbacks`; + const callInvite = new CommunicationUserIdentifier(acsTarget); + const createCallOptions = { + callInvite, + callbackUri, + callIntelligenceOptions: { + cognitiveServicesEndpoint: 'https://cognitive-service-waferwire.cognitiveservices.azure.com/' + } }; - // Call the ACS SDK to move participants - await targetConnection.moveParticipants([participantToMove], callConnectionId2, options); - callConnectionId2 = ""; - callerId2 = ""; - calleeId2 = ""; - calleeId1 = acsTestIdentity2; - - // For demonstration, assume success - console.log('Move Participants operation completed successfully'); - console.log(`Moved ${acsTestIdentity2} from ${callConnectionId2} to ${callConnectionId1}`); - console.log('=== MOVE PARTICIPANTS OPERATION COMPLETE ==='); + const createCallResult = await acsClient.createCall(createCallOptions); + targetCallConnectionId = createCallResult.callConnectionProperties.callConnectionId; + + const logMsg = ` + TargetCall: + ----------- + From: Call Automation + To: ${acsTarget} + Target Call Connection Id: ${targetCallConnectionId} + Correlation Id: ${createCallResult.callConnectionProperties.correlationId} + `; + console.log(logMsg); + res.type('text/plain').send(logMsg); } catch (err) { - console.error(`Error in manual move participant operation: ${err.message}`); + console.error('Error creating call:', err); + res.status(500).send('Error creating call: ' + err.message); } - res.redirect('/'); }); -app.get('/moveParticipant3', async (req, res) => { - console.log('--------- MoveParticipant API End Point -------------------'); - +app.get('/GetParticipants/:callConnectionId', async (req, res) => { + const callConnectionId = req.params.callConnectionId; + console.log(`\n~~~~~~~~~~~~ /GetParticipants/${callConnectionId} ~~~~~~~~~~~~\n`); try { - const request = req.body; - console.log('=== MANUAL MOVE PARTICIPANT REQUESTED ==='); - console.log(`Source Connection ID: ${callConnectionId3}`); - console.log(`Target Connection ID: ${callConnectionId1}`); - console.log(`Participant to Move: ${acsOutboundPhoneNumber}`); - - // Get the target connection (where we want to move participants to) - const targetConnection = acsClient.getCallConnection(callConnectionId1); - - // Get participants from source connection for reference (optional) - const sourceConnection = acsClient.getCallConnection(callConnectionId3); - - // Create participant identifier based on the input - let participantToMove; - if (acsOutboundPhoneNumber.startsWith('+')) { - // Phone number - participantToMove = { phoneNumber: acsOutboundPhoneNumber }; - console.log(`Moving phone number participant: ${acsOutboundPhoneNumber}`); - } else if (acsOutboundPhoneNumber.startsWith('8:acs:')) { - // ACS Communication User - participantToMove = { communicationUserId: acsOutboundPhoneNumber }; - console.log(`Moving ACS user participant: ${acsOutboundPhoneNumber}`); + const callConnection = acsClient.getCallConnection(callConnectionId); + const participantsResponse = await callConnection.getParticipants(); + const participants = participantsResponse.value; + + // Format participant info + const participantInfo = participants.map(p => { + let type = p.identifier.kind || p.identifier.constructor.name; + let rawId = p.identifier.rawId; + let phoneNumber = p.identifier.phoneNumber || null; + let acsUserId = p.identifier.communicationUserId || null; + + return { + rawId, + type, + phoneNumber, + acsUserId + }; + }); + + // Sort: phone numbers first, then ACS users + participantInfo.sort((a, b) => { + if (!a.acsUserId && b.acsUserId) return -1; + if (a.acsUserId && !b.acsUserId) return 1; + return 0; + }); + + // Format output + if (participantInfo.length === 0) { + return res.status(404).json({ + message: "No participants found for the specified call connection.", + callConnectionId + }); } else { - console.log("Invalid participant format. Use phone number (+1234567890) or ACS user ID (8:acs:...)"); + let msg = `\nNo of Participants: ${participantInfo.length}\nParticipants: \n-------------\n`; + msg += participantInfo.map((p, i) => { + if (p.acsUserId) { + return `${i + 1}. ${p.type} - RawId: ${p.acsUserId}`; + } else { + return `${i + 1}. ${p.type} - RawId: ${p.rawId}, Phone: ${p.phoneNumber}`; + } + }).join('\n'); + console.log(msg); + return res.type('text/plain').send(msg); } - - // Prepare move participants options - const options : MoveParticipantsOptions = { - operationContext: "MoveParticipant3" - }; - - // Call the ACS SDK to move participants - await targetConnection.moveParticipants([participantToMove], callConnectionId3, options); - callConnectionId3 = ""; - callerId3 = ""; - calleeId3 = ""; - calleeId1 = acsTestIdentity3; - - // For demonstration, assume success - console.log('Move Participants operation completed successfully'); - console.log(`Moved ${acsTestIdentity3} from ${callConnectionId3} to ${callConnectionId1}`); - console.log('=== MOVE PARTICIPANTS OPERATION COMPLETE ==='); - } catch (err) { - console.error(`Error in manual move participant operation: ${err.message}`); + } catch (ex) { + console.error(`Error getting participants for call ${callConnectionId}: ${ex.message}`); + return res.status(400).json({ + error: ex.message, + callConnectionId + }); } - res.redirect('/'); }); app.get('/terminateCalls', async (req, res) => { - console.log(`calls 1: ${callConnectionId1}, 2: ${callConnectionId2}, 3: ${callConnectionId3}`); - if (callConnectionId1) { + console.log(`calls 1: ${lobbyCallConnectionId}, 2: ${targetCallConnectionId}`); + if (lobbyCallConnectionId) { try { - console.log(`Terminating Call 1 with ID: ${callConnectionId1}`); - const callConnection1 = acsClient.getCallConnection(callConnectionId1); - await callConnection1.hangUp(true); + console.log(`Terminating Lobby Call with ID: ${lobbyCallConnectionId}`); + const lobbyConnection = acsClient.getCallConnection(lobbyCallConnectionId); + await lobbyConnection.hangUp(true); } catch (error) { - console.error(`Error terminating Call 1: ${error.message}`); + console.error(`Error terminating Lobby Call: ${error.message}`); } } - if (callConnectionId2) { + if (targetCallConnectionId) { try { - console.log(`Terminating Call 2 with ID: ${callConnectionId2}`); - const callConnection2 = acsClient.getCallConnection(callConnectionId2); - await callConnection2.hangUp(true); + console.log(`Terminating Target Call with ID: ${targetCallConnectionId}`); + const targetConnection = acsClient.getCallConnection(targetCallConnectionId); + await targetConnection.hangUp(true); } catch (error) { - console.error(`Error terminating Call 2: ${error.message}`); - } - } - if (callConnectionId3) { - try { - console.log(`Terminating Call 3 with ID: ${callConnectionId3}`); - const callConnection3 = acsClient.getCallConnection(callConnectionId3); - await callConnection3.hangUp(true); - } catch (error) { - console.error(`Error terminating Call 3: ${error.message}`); + console.error(`Error terminating Target Call: ${error.message}`); } } console.log("Calls hung up successfully."); - callConnectionId1 = ""; - callConnectionId2 = ""; - callConnectionId3 = ""; - callerId1 = ""; - callerId2 = ""; - callerId3 = ""; - calleeId1 = ""; - calleeId2 = ""; - calleeId3 = ""; + lobbyCallConnectionId = ""; + targetCallConnectionId = ""; + lobbyCallerId = ""; res.redirect('/'); }); -app.post('/api/moveParticipantEvent', async (req, res) => { +app.post('/api/LobbyCallSupportEventHandler', async (req, res) => { console.log('--------- /api/moveParticipantEvent -------------------'); const event = req.body[0]; const eventData = event.data; @@ -333,59 +251,32 @@ app.post('/api/moveParticipantEvent', async (req, res) => { console.log(`From Caller Id: ${fromCallerId}`); console.log(`To Caller Id : ${toCallerId}`); - // Scenario 1: User calls from their phone number to ACS inbound number - if (fromCallerId.includes(userPhoneNumber)) { - console.log('=== SCENARIO 1: USER INCOMING CALL ==='); - - const callbackUri = new URL('/api/callbacks', callbackUriHost).toString(); - const options : AnswerCallOptions = { - operationContext: "CallOne" + // Lobby Call: Answer + if (toCallerId.includes(acsGeneratedId)) { + const callbackUri = `${callbackUriHost}/api/callbacks`; + const options = { + incomingCallContext: eventData.incomingCallContext, + callbackUri: callbackUri, + operationContext: 'LobbyCall', + callIntelligenceOptions: { + cognitiveServicesEndpoint: process.env.COGNITIVE_SERVICES_ENDPOINT + } }; - //console.log(`Incoming call context: ${eventData.incomingCallContext}`); - var answerCallResult = await acsClient.answerCall(eventData.incomingCallContext, callbackUri, options); - callConnectionId1 = answerCallResult.callConnectionProperties.callConnectionId; - - console.log(`User Call Answered - CallConnectionId: ${callConnectionId1}`); - console.log(`Correlation Id: ${eventData.correlationId}`); - console.log('Operation Context: CallOne'); - console.log('=== END SCENARIO 1 ==='); - } - // Scenario 2: ACS inbound number calls ACS outbound number (workflow triggered) - else if (fromCallerId.includes(acsInboundPhoneNumber)) { - console.log('=== SCENARIO 2: WORKFLOW CALL TO BE REDIRECTED ==='); - console.log(`Last Workflow Call Type: ${lastWorkflowCallType}`); - - // Check which type of workflow call this is and redirect accordingly - let redirectTarget; - if (lastWorkflowCallType === 'CallTwo') { - // Redirect the call to ACS User Identity 2 - redirectTarget = acsTestIdentity2; - const callee : CommunicationUserIdentifier = { - communicationUserId: redirectTarget - }; - const callInvite : CallInvite = { - targetParticipant: callee - }; - //console.log(`Incoming call context: ${eventData.incomingCallContext}`); - var redirectCallResult = await acsClient.redirectCall(eventData.incomingCallContext, callInvite); - console.log('PROCESSING CALL TWO - Redirecting to ACS User Identity 2'); - } else if (lastWorkflowCallType === 'CallThree') { - // Redirect the call to ACS User Identity 3 - redirectTarget = acsTestIdentity3; - const callee : CommunicationUserIdentifier = { - communicationUserId: redirectTarget - }; - const callInvite : CallInvite = { - targetParticipant: callee - }; - //console.log(`Incoming call context: ${eventData.incomingCallContext}`); - var redirectCallResult = await acsClient.redirectCall(eventData.incomingCallContext, callInvite); - console.log('PROCESSING CALL THREE - Redirecting to ACS User Identity 3'); - } - console.log('=== END SCENARIO 2 ==='); + const answerCallResult = await acsClient.answerCall(options); + lobbyCallConnectionId = answerCallResult.callConnectionProperties.callConnectionId; + + console.log( + `User Call(Inbound) Answered by Call Automation.`, + `From Caller Raw Id: ${fromCallerId}`, + `To Caller Raw Id: ${toCallerId}`, + `Lobby Call Connection Id: ${lobbyCallConnectionId}`, + `Correlation Id: ${eventData.correlationId}`, + `Lobby Call answered successfully.` + ); } } + res.status(200).send(); }); @@ -396,43 +287,60 @@ app.post('/api/callbacks', async (req, res) => { // For demonstration, log the event type and IDs console.log(`Received call event: ${event.type}`); console.log(`Correlation id:-> ${eventData.correlationId}`) + if (event.type === "Microsoft.Communication.CallConnected") { console.log('\n--------- CallConnected Event Block -------------------'); - switch (eventData.operationContext) { - case 'CallOne': - //callConnectionId1 = callConnectionId; - console.log('=== CALL ONE CONNECTED ==='); - console.log('User call connected'); - console.log('=== END CALL ONE CONNECTED ==='); - break; - case 'CallTwo': - //callConnectionId2 = callConnectionId; - calleeId2 = acsTestIdentity2; - console.log('=== CALL TWO CONNECTED ==='); - console.log('User call connected'); - console.log('=== END CALL TWO CONNECTED ==='); - break; - case 'CallThree': - //callConnectionId3 = callConnectionId; - calleeId3 = acsTestIdentity3; - console.log('=== CALL THREE CONNECTED ==='); - console.log('User call connected'); - console.log('=== END CALL THREE CONNECTED ==='); - break; + + if ((eventData.operationContext || '') === 'LobbyCall') { + console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); + console.log(`Received call event : ${event.type}`); + console.log(`Lobby Call Connection Id: ${eventData.callConnectionId}`); + console.log(`Correlation Id: ${eventData.correlationId}`); + + // Record lobby caller id and connection id + const lobbyCallConnection = acsClient.getCallConnection(eventData.callConnectionId); + const callConnectionProperties = await lobbyCallConnection.getCallConnectionProperties(); + lobbyCallerId = callConnectionProperties.source.rawId; + lobbyCallConnectionId = callConnectionProperties.callConnectionId; + console.log(`Lobby Caller Id: ${lobbyCallerId}`); + console.log(`Lobby Connection Id: ${lobbyCallConnectionId}`); + + // Play lobby waiting message + const callMedia = acsClient.getCallConnection(eventData.callConnectionId).getCallMedia(); + const textSource = new TextSource("You are currently in a lobby call, we will notify the admin that you are waiting."); + textSource.voiceName = "en-US-NancyNeural"; + const playTo = [new CommunicationUserIdentifier(acsIdentity)]; + const playToOptions = new PlayOptions({ playSource: textSource, playTo }); + playToOptions.operationContext = "playToContext"; + await callMedia.play(playToOptions); } - } else if (event.type === 'Microsoft.Communication.CallDisconnected') { - console.log(`Call disconnected: ${eventData.callConnectionId}`); - } else { - // Log other events but don't process them for Move Participants scenario - console.log(`Received event: ${event.type} - No action needed for Move Participants scenario`); + } else if (event.type === "Microsoft.Communication.PlayCompleted") { + console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); + console.log(`Received event: ${event.type}`); + + // Notify Target Call user via websocket + if (!webSocket || webSocket.readyState !== 1) { // 1 = OPEN + console.log("ERROR: Web socket is not available."); + return res.status(404).send("Message sent"); + } + + const confirmMessageToTargetCall = "A user is waiting in lobby, do you want to add the user to your call?"; + // Notify Client + webSocket.send(confirmMessageToTargetCall); + console.log(`Target Call notified with message: ${confirmMessageToTargetCall}`); + return res.status(200).send(`Target Call notified with message: ${confirmMessageToTargetCall}`); + } else if (event.type === "Microsoft.Communication.MoveParticipantsSucceeded") { + console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); + console.log(`Received event: ${event.type}`); + console.log(`Call Connection Id: ${eventData.callConnectionId}`); + console.log(`Correlation Id: ${eventData.correlationId}`); + } else if (event.type === "Microsoft.Communication.CallDisconnected") { + console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); + console.log(`Received event: ${event.type}`); + console.log(`Call Connection Id: ${eventData.callConnectionId}`); } - res.status(200).send(); -}); -app.get('/call-data', (req, res) => { - console.log("Call Data Endpoint Hit"); - console.log(`call 1: ${callConnectionId1}, call 2: ${callConnectionId2}, call 3: ${callConnectionId3}`); - res.json({ callConnectionId1, callConnectionId2, callConnectionId3, callerId1, callerId2, callerId3, calleeId1, calleeId2, calleeId3 }); + res.status(200).send(); }); // GET endpoint to serve the webpage From 4f0d59dd739990933fc430ca8355dbfb3497d0ca Mon Sep 17 00:00:00 2001 From: nageshy Date: Sun, 27 Jul 2025 10:16:35 +0530 Subject: [PATCH 03/12] Update code --- callautomation-lobbycall-sample/package.json | 2 +- callautomation-lobbycall-sample/src/app.ts | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/callautomation-lobbycall-sample/package.json b/callautomation-lobbycall-sample/package.json index 57a994cf..6582ac9b 100644 --- a/callautomation-lobbycall-sample/package.json +++ b/callautomation-lobbycall-sample/package.json @@ -11,7 +11,7 @@ "author": "", "license": "ISC", "dependencies": { - "@azure/communication-call-automation": "^1.5.0", + "@azure/communication-call-automation": "file:C:/Projects/Repos/azure-sdk-for-js/sdk/communication/communication-call-automation", "@azure/communication-common": "^2.2.0", "@azure/communication-identity": "^1.3.1", "@azure/communication-rooms": "^1.1.1", diff --git a/callautomation-lobbycall-sample/src/app.ts b/callautomation-lobbycall-sample/src/app.ts index 1200eba5..af056a8b 100644 --- a/callautomation-lobbycall-sample/src/app.ts +++ b/callautomation-lobbycall-sample/src/app.ts @@ -1,12 +1,9 @@ import { config } from 'dotenv'; import express, { Application } from 'express'; -import { CommunicationUserIdentifier, PhoneNumberIdentifier } from "@azure/communication-common"; import { - CallAutomationClient, - CallInvite, - AnswerCallOptions, - MoveParticipantsOptions + CallAutomationClient } from "@azure/communication-call-automation"; +import { PhoneNumberIdentifier, CommunicationUserIdentifier } from "@azure/communication-common"; config(); From 9b03e3a7bb2e43725fc8b9caacd45592cf31235c Mon Sep 17 00:00:00 2001 From: nageshy Date: Sun, 27 Jul 2025 10:58:05 +0530 Subject: [PATCH 04/12] Update code --- callautomation-lobbycall-sample/package.json | 2 +- callautomation-lobbycall-sample/src/app.ts | 514 +- .../src/app.ts.xxx | 277 + .../package-lock.json | 7174 +++++++++++++++++ 4 files changed, 7794 insertions(+), 173 deletions(-) create mode 100644 callautomation-lobbycall-sample/src/app.ts.xxx create mode 100644 callautomation-multiple-dial-out/package-lock.json diff --git a/callautomation-lobbycall-sample/package.json b/callautomation-lobbycall-sample/package.json index 6582ac9b..d49147a0 100644 --- a/callautomation-lobbycall-sample/package.json +++ b/callautomation-lobbycall-sample/package.json @@ -11,7 +11,7 @@ "author": "", "license": "ISC", "dependencies": { - "@azure/communication-call-automation": "file:C:/Projects/Repos/azure-sdk-for-js/sdk/communication/communication-call-automation", + "@azure/communication-call-automation": "file:../../azure-sdk-for-js/sdk/communication/communication-call-automation", "@azure/communication-common": "^2.2.0", "@azure/communication-identity": "^1.3.1", "@azure/communication-rooms": "^1.1.1", diff --git a/callautomation-lobbycall-sample/src/app.ts b/callautomation-lobbycall-sample/src/app.ts index af056a8b..bd19a61e 100644 --- a/callautomation-lobbycall-sample/src/app.ts +++ b/callautomation-lobbycall-sample/src/app.ts @@ -1,9 +1,12 @@ import { config } from 'dotenv'; import express, { Application } from 'express'; +import { CommunicationUserIdentifier, PhoneNumberIdentifier } from "@azure/communication-common"; import { - CallAutomationClient + CallAutomationClient, + CallInvite, + AnswerCallOptions, + MoveParticipantsOptions } from "@azure/communication-call-automation"; -import { PhoneNumberIdentifier, CommunicationUserIdentifier } from "@azure/communication-common"; config(); @@ -21,7 +24,6 @@ let lobbyCallerId: string; const callbackUriHost = process.env.CALLBACK_URI || ""; const connectionString = process.env.CONNECTION_STRING || "" const endpoint = process.env.PMA_ENDPOINT || "" -let webSocket = null; async function createAcsClient() { lobbyCallConnectionId = ""; @@ -33,99 +35,28 @@ async function createAcsClient() { console.log("Initialized ACS Client."); } -const http = require('http'); -const WebSocket = require('ws'); -const server = http.createServer(app); - -// WebSocket server setup -const wss = new WebSocket.Server({ noServer: true }); - -server.on('upgrade', (request, socket, head) => { - // Only accept connections to the correct path - const url = request.url || ''; - if (url === `/ws/${process.env.SOCKET_TOKEN}`) { - wss.handleUpgrade(request, socket, head, function done(ws) { - wss.emit('connection', ws, request); - }); - } else { - socket.destroy(); - } -}); - -wss.on('connection', (ws) => { - webSocket = ws; - console.log('Received WEB SOCKET request.'); - - ws.on('message', async (message) => { - const jsResponse = message.toString(); - console.log(`Received from JS: ${jsResponse}`); - - // Move participant to target call if response is "yes" - if (jsResponse.trim().toLowerCase() === 'yes') { - console.log('TODO: Move Participant'); - try { - console.log(` - ~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~ - Move Participant operation started.. - Source Caller Id: ${lobbyCallerId} - Source Connection Id: ${lobbyCallConnectionId} - Target Connection Id: ${targetCallConnectionId} - `); - - // Get the target connection - const targetConnection = acsClient.getCallConnection(targetCallConnectionId); - - // Get participants from source connection for reference - // const sourceConnection = client.getCallConnection(lobbyConnectionId); - - // Create participant identifier based on the input - let participantToMove; - if (lobbyCallerId.startsWith('+')) { - // Phone number - participantToMove = new PhoneNumberIdentifier(lobbyCallerId); - } else { - // ACS Communication User - participantToMove = new CommunicationUserIdentifier(lobbyCallerId); - } - - const response = await targetConnection.moveParticipants({ - participantsToMove: [participantToMove], - sourceCallConnectionId: lobbyCallConnectionId - }); - const rawResponse = response._response; - if (rawResponse.status >= 200 && rawResponse.status <= 299) { - console.log(); - console.log('Move Participants operation completed successfully.'); - } else { - throw new Error(`Move Participants operation failed with status code: ${rawResponse.status}`); - } - } catch (ex) { - console.log(`Error in manual move participants operation: ${ex.message}`); - } - } - }); - - ws.on('close', () => { - webSocket = null; - }); -}); - app.get('/TargetCallToAcsUser(Create)', async (req, res) => { const acsTarget = req.body.acsTarget; // expects { "acsTarget": "" } console.log('\n~~~~~~~~~~~~ /TargetCall(Create) ~~~~~~~~~~~~\n'); try { const callbackUri = `${callbackUriHost}/api/callbacks`; - const callInvite = new CommunicationUserIdentifier(acsTarget); + const callee : CommunicationUserIdentifier = { + communicationUserId: acsTarget + }; + const callInvite : CallInvite = { + targetParticipant: callee + }; const createCallOptions = { - callInvite, - callbackUri, callIntelligenceOptions: { cognitiveServicesEndpoint: 'https://cognitive-service-waferwire.cognitiveservices.azure.com/' } }; - - const createCallResult = await acsClient.createCall(createCallOptions); + const createCallResult = await acsClient.createCall( + callInvite, + callbackUri, + createCallOptions + ); targetCallConnectionId = createCallResult.callConnectionProperties.callConnectionId; const logMsg = ` @@ -149,7 +80,7 @@ app.get('/GetParticipants/:callConnectionId', async (req, res) => { console.log(`\n~~~~~~~~~~~~ /GetParticipants/${callConnectionId} ~~~~~~~~~~~~\n`); try { const callConnection = acsClient.getCallConnection(callConnectionId); - const participantsResponse = await callConnection.getParticipants(); + const participantsResponse = await callConnection.getAllParticipant(); const participants = participantsResponse.value; // Format participant info @@ -201,34 +132,263 @@ app.get('/GetParticipants/:callConnectionId', async (req, res) => { } }); +app.get('/userCallToCallAutomation', async (req, res) => { + console.log("--------- UserCallToCallAutomation - Call 1 API Endpoint -------------------"); + try { + const callbackUri = new URL('/api/callbacks', callbackUriHost).toString(); + const callee : PhoneNumberIdentifier = { + phoneNumber: acsInboundPhoneNumber + }; + const callInvite : CallInvite = { + targetParticipant: callee, + sourceCallIdNumber: { + phoneNumber: userPhoneNumber, + }, + }; + const options = { + callIntelligenceOptions: { + cognitiveServicesEndpoint: process.env.COGNITIVE_SERVICES_ENDPOINT + }, + operationContext: 'CallOne' + }; + var createCallResult = await acsClient.createCall(callInvite, callbackUri, options); + callConnectionId1 = createCallResult.callConnectionProperties.callConnectionId; + callerId1 = userPhoneNumber; + calleeId1 = acsInboundPhoneNumber; + + console.log("=== Call From User to Call Automation ==="); + console.log(`Created call from ${userPhoneNumber} to ${acsOutboundPhoneNumber}`); + console.log(`Connection ID: ${callConnectionId1}`); + console.log("=== END WORKFLOW INITIATION ==="); + } catch (err) { + console.error('Error creating call:', err); + } + res.redirect('/'); +}); + +app.get('/createCall2', async (req, res) => { + console.log('--------- createCall2 - Call 2 API Endpoint " -------------------'); + try { + const callbackUri = new URL('/api/callbacks', callbackUriHost).toString(); + const callee : PhoneNumberIdentifier = { + phoneNumber: acsOutboundPhoneNumber + }; + const callInvite : CallInvite = { + targetParticipant: callee, + sourceCallIdNumber: { + phoneNumber: acsInboundPhoneNumber, + }, + }; + const options = { + callIntelligenceOptions: { + cognitiveServicesEndpoint: process.env.COGNITIVE_SERVICES_ENDPOINT + }, + operationContext: 'CallTwo' + }; + var createCallResult = await acsClient.createCall(callInvite, callbackUri, options); + callConnectionId2 = createCallResult.callConnectionProperties.callConnectionId; + // Track this as Call 2 + lastWorkflowCallType = "CallTwo"; + callerId2 = acsInboundPhoneNumber; + calleeId2 = acsOutboundPhoneNumber; + + console.log('=== CALL TWO WORKFLOW INITIATED ==='); + console.log(`Created call from ${acsInboundPhoneNumber} to ${acsOutboundPhoneNumber}`); + console.log(`Connection ID: ${callConnectionId2}`); + console.log(`This call should trigger MoveParticipantEvent (Scenario 2) which will redirect to ACS user ${acsTestIdentity2}`); + console.log('Operation Context: CallTwo'); + console.log('=== END WORKFLOW INITIATION ==='); + } catch (err) { + console.error('Error creating call:', err); + } + res.redirect('/'); +}); + +app.get('/createCall3', async (req, res) => { + console.log('--------- createCall3 - Call 3 API Endpoint " -------------------'); + try { + const callbackUri = new URL('/api/callbacks', callbackUriHost).toString(); + const callee : PhoneNumberIdentifier = { + phoneNumber: acsOutboundPhoneNumber + }; + const callInvite : CallInvite = { + targetParticipant: callee, + sourceCallIdNumber: { + phoneNumber: acsInboundPhoneNumber, + }, + }; + const options = { + callIntelligenceOptions: { + cognitiveServicesEndpoint: process.env.COGNITIVE_SERVICES_ENDPOINT + }, + operationContext: 'CallThree' + }; + var createCallResult = await acsClient.createCall(callInvite, callbackUri, options); + callConnectionId3 = createCallResult.callConnectionProperties.callConnectionId; + // Track this as Call 2 + lastWorkflowCallType = "CallThree"; + callerId3 = acsInboundPhoneNumber; + calleeId3 = acsOutboundPhoneNumber; + + console.log('=== CALL THREE WORKFLOW INITIATED ==='); + console.log(`Created call from ${acsInboundPhoneNumber} to ${acsOutboundPhoneNumber}`); + console.log(`Connection ID: ${callConnectionId3}`); + console.log(`This call should trigger MoveParticipantEvent (Scenario 3) which will redirect to ACS user ${acsTestIdentity3}`); + console.log('Operation Context: CallThree'); + console.log('=== END WORKFLOW INITIATION ==='); + } catch (err) { + console.error('Error creating call:', err); + } + res.redirect('/'); +}); + +app.get('/moveParticipant2', async (req, res) => { + console.log('--------- MoveParticipant API End Point -------------------'); + + try { + const request = req.body; + console.log('=== MANUAL MOVE PARTICIPANT REQUESTED ==='); + console.log(`Source Connection ID: ${callConnectionId2}`); + console.log(`Target Connection ID: ${callConnectionId1}`); + console.log(`Participant to Move: ${acsOutboundPhoneNumber}`); + + // Get the target connection (where we want to move participants to) + const targetConnection = acsClient.getCallConnection(callConnectionId1); + + // Get participants from source connection for reference (optional) + const sourceConnection = acsClient.getCallConnection(callConnectionId2); + + // Create participant identifier based on the input + let participantToMove; + if (acsOutboundPhoneNumber.startsWith('+')) { + // Phone number + participantToMove = { phoneNumber: acsOutboundPhoneNumber }; + console.log(`Moving phone number participant: ${acsOutboundPhoneNumber}`); + } else if (acsOutboundPhoneNumber.startsWith('8:acs:')) { + // ACS Communication User + participantToMove = { communicationUserId: acsOutboundPhoneNumber }; + console.log(`Moving ACS user participant: ${acsOutboundPhoneNumber}`); + } else { + console.log("Invalid participant format. Use phone number (+1234567890) or ACS user ID (8:acs:...)"); + } + + // Prepare move participants options + const options : MoveParticipantsOptions = { + operationContext: "MoveParticipant2" + }; + + // Call the ACS SDK to move participants + await targetConnection.moveParticipants([participantToMove], callConnectionId2, options); + callConnectionId2 = ""; + callerId2 = ""; + calleeId2 = ""; + calleeId1 = acsTestIdentity2; + + // For demonstration, assume success + console.log('Move Participants operation completed successfully'); + console.log(`Moved ${acsTestIdentity2} from ${callConnectionId2} to ${callConnectionId1}`); + console.log('=== MOVE PARTICIPANTS OPERATION COMPLETE ==='); + } catch (err) { + console.error(`Error in manual move participant operation: ${err.message}`); + } + res.redirect('/'); +}); + +app.get('/moveParticipant3', async (req, res) => { + console.log('--------- MoveParticipant API End Point -------------------'); + + try { + const request = req.body; + console.log('=== MANUAL MOVE PARTICIPANT REQUESTED ==='); + console.log(`Source Connection ID: ${callConnectionId3}`); + console.log(`Target Connection ID: ${callConnectionId1}`); + console.log(`Participant to Move: ${acsOutboundPhoneNumber}`); + + // Get the target connection (where we want to move participants to) + const targetConnection = acsClient.getCallConnection(callConnectionId1); + + // Get participants from source connection for reference (optional) + const sourceConnection = acsClient.getCallConnection(callConnectionId3); + + // Create participant identifier based on the input + let participantToMove; + if (acsOutboundPhoneNumber.startsWith('+')) { + // Phone number + participantToMove = { phoneNumber: acsOutboundPhoneNumber }; + console.log(`Moving phone number participant: ${acsOutboundPhoneNumber}`); + } else if (acsOutboundPhoneNumber.startsWith('8:acs:')) { + // ACS Communication User + participantToMove = { communicationUserId: acsOutboundPhoneNumber }; + console.log(`Moving ACS user participant: ${acsOutboundPhoneNumber}`); + } else { + console.log("Invalid participant format. Use phone number (+1234567890) or ACS user ID (8:acs:...)"); + } + + // Prepare move participants options + const options : MoveParticipantsOptions = { + operationContext: "MoveParticipant3" + }; + + // Call the ACS SDK to move participants + await targetConnection.moveParticipants([participantToMove], callConnectionId3, options); + callConnectionId3 = ""; + callerId3 = ""; + calleeId3 = ""; + calleeId1 = acsTestIdentity3; + + // For demonstration, assume success + console.log('Move Participants operation completed successfully'); + console.log(`Moved ${acsTestIdentity3} from ${callConnectionId3} to ${callConnectionId1}`); + console.log('=== MOVE PARTICIPANTS OPERATION COMPLETE ==='); + } catch (err) { + console.error(`Error in manual move participant operation: ${err.message}`); + } + res.redirect('/'); +}); + app.get('/terminateCalls', async (req, res) => { - console.log(`calls 1: ${lobbyCallConnectionId}, 2: ${targetCallConnectionId}`); - if (lobbyCallConnectionId) { + console.log(`calls 1: ${callConnectionId1}, 2: ${callConnectionId2}, 3: ${callConnectionId3}`); + if (callConnectionId1) { + try { + console.log(`Terminating Call 1 with ID: ${callConnectionId1}`); + const callConnection1 = acsClient.getCallConnection(callConnectionId1); + await callConnection1.hangUp(true); + } catch (error) { + console.error(`Error terminating Call 1: ${error.message}`); + } + } + if (callConnectionId2) { try { - console.log(`Terminating Lobby Call with ID: ${lobbyCallConnectionId}`); - const lobbyConnection = acsClient.getCallConnection(lobbyCallConnectionId); - await lobbyConnection.hangUp(true); + console.log(`Terminating Call 2 with ID: ${callConnectionId2}`); + const callConnection2 = acsClient.getCallConnection(callConnectionId2); + await callConnection2.hangUp(true); } catch (error) { - console.error(`Error terminating Lobby Call: ${error.message}`); + console.error(`Error terminating Call 2: ${error.message}`); } } - if (targetCallConnectionId) { + if (callConnectionId3) { try { - console.log(`Terminating Target Call with ID: ${targetCallConnectionId}`); - const targetConnection = acsClient.getCallConnection(targetCallConnectionId); - await targetConnection.hangUp(true); + console.log(`Terminating Call 3 with ID: ${callConnectionId3}`); + const callConnection3 = acsClient.getCallConnection(callConnectionId3); + await callConnection3.hangUp(true); } catch (error) { - console.error(`Error terminating Target Call: ${error.message}`); + console.error(`Error terminating Call 3: ${error.message}`); } } console.log("Calls hung up successfully."); - lobbyCallConnectionId = ""; - targetCallConnectionId = ""; - lobbyCallerId = ""; + callConnectionId1 = ""; + callConnectionId2 = ""; + callConnectionId3 = ""; + callerId1 = ""; + callerId2 = ""; + callerId3 = ""; + calleeId1 = ""; + calleeId2 = ""; + calleeId3 = ""; res.redirect('/'); }); -app.post('/api/LobbyCallSupportEventHandler', async (req, res) => { +app.post('/api/moveParticipantEvent', async (req, res) => { console.log('--------- /api/moveParticipantEvent -------------------'); const event = req.body[0]; const eventData = event.data; @@ -248,32 +408,59 @@ app.post('/api/LobbyCallSupportEventHandler', async (req, res) => { console.log(`From Caller Id: ${fromCallerId}`); console.log(`To Caller Id : ${toCallerId}`); - // Lobby Call: Answer - if (toCallerId.includes(acsGeneratedId)) { - const callbackUri = `${callbackUriHost}/api/callbacks`; - const options = { - incomingCallContext: eventData.incomingCallContext, - callbackUri: callbackUri, - operationContext: 'LobbyCall', - callIntelligenceOptions: { - cognitiveServicesEndpoint: process.env.COGNITIVE_SERVICES_ENDPOINT - } + // Scenario 1: User calls from their phone number to ACS inbound number + if (fromCallerId.includes(userPhoneNumber)) { + console.log('=== SCENARIO 1: USER INCOMING CALL ==='); + + const callbackUri = new URL('/api/callbacks', callbackUriHost).toString(); + const options : AnswerCallOptions = { + operationContext: "CallOne" }; - const answerCallResult = await acsClient.answerCall(options); - lobbyCallConnectionId = answerCallResult.callConnectionProperties.callConnectionId; - - console.log( - `User Call(Inbound) Answered by Call Automation.`, - `From Caller Raw Id: ${fromCallerId}`, - `To Caller Raw Id: ${toCallerId}`, - `Lobby Call Connection Id: ${lobbyCallConnectionId}`, - `Correlation Id: ${eventData.correlationId}`, - `Lobby Call answered successfully.` - ); + //console.log(`Incoming call context: ${eventData.incomingCallContext}`); + var answerCallResult = await acsClient.answerCall(eventData.incomingCallContext, callbackUri, options); + callConnectionId1 = answerCallResult.callConnectionProperties.callConnectionId; + + console.log(`User Call Answered - CallConnectionId: ${callConnectionId1}`); + console.log(`Correlation Id: ${eventData.correlationId}`); + console.log('Operation Context: CallOne'); + console.log('=== END SCENARIO 1 ==='); + } + // Scenario 2: ACS inbound number calls ACS outbound number (workflow triggered) + else if (fromCallerId.includes(acsInboundPhoneNumber)) { + console.log('=== SCENARIO 2: WORKFLOW CALL TO BE REDIRECTED ==='); + console.log(`Last Workflow Call Type: ${lastWorkflowCallType}`); + + // Check which type of workflow call this is and redirect accordingly + let redirectTarget; + if (lastWorkflowCallType === 'CallTwo') { + // Redirect the call to ACS User Identity 2 + redirectTarget = acsTestIdentity2; + const callee : CommunicationUserIdentifier = { + communicationUserId: redirectTarget + }; + const callInvite : CallInvite = { + targetParticipant: callee + }; + //console.log(`Incoming call context: ${eventData.incomingCallContext}`); + var redirectCallResult = await acsClient.redirectCall(eventData.incomingCallContext, callInvite); + console.log('PROCESSING CALL TWO - Redirecting to ACS User Identity 2'); + } else if (lastWorkflowCallType === 'CallThree') { + // Redirect the call to ACS User Identity 3 + redirectTarget = acsTestIdentity3; + const callee : CommunicationUserIdentifier = { + communicationUserId: redirectTarget + }; + const callInvite : CallInvite = { + targetParticipant: callee + }; + //console.log(`Incoming call context: ${eventData.incomingCallContext}`); + var redirectCallResult = await acsClient.redirectCall(eventData.incomingCallContext, callInvite); + console.log('PROCESSING CALL THREE - Redirecting to ACS User Identity 3'); + } + console.log('=== END SCENARIO 2 ==='); } } - res.status(200).send(); }); @@ -284,62 +471,45 @@ app.post('/api/callbacks', async (req, res) => { // For demonstration, log the event type and IDs console.log(`Received call event: ${event.type}`); console.log(`Correlation id:-> ${eventData.correlationId}`) - if (event.type === "Microsoft.Communication.CallConnected") { console.log('\n--------- CallConnected Event Block -------------------'); - - if ((eventData.operationContext || '') === 'LobbyCall') { - console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); - console.log(`Received call event : ${event.type}`); - console.log(`Lobby Call Connection Id: ${eventData.callConnectionId}`); - console.log(`Correlation Id: ${eventData.correlationId}`); - - // Record lobby caller id and connection id - const lobbyCallConnection = acsClient.getCallConnection(eventData.callConnectionId); - const callConnectionProperties = await lobbyCallConnection.getCallConnectionProperties(); - lobbyCallerId = callConnectionProperties.source.rawId; - lobbyCallConnectionId = callConnectionProperties.callConnectionId; - console.log(`Lobby Caller Id: ${lobbyCallerId}`); - console.log(`Lobby Connection Id: ${lobbyCallConnectionId}`); - - // Play lobby waiting message - const callMedia = acsClient.getCallConnection(eventData.callConnectionId).getCallMedia(); - const textSource = new TextSource("You are currently in a lobby call, we will notify the admin that you are waiting."); - textSource.voiceName = "en-US-NancyNeural"; - const playTo = [new CommunicationUserIdentifier(acsIdentity)]; - const playToOptions = new PlayOptions({ playSource: textSource, playTo }); - playToOptions.operationContext = "playToContext"; - await callMedia.play(playToOptions); + switch (eventData.operationContext) { + case 'CallOne': + //callConnectionId1 = callConnectionId; + console.log('=== CALL ONE CONNECTED ==='); + console.log('User call connected'); + console.log('=== END CALL ONE CONNECTED ==='); + break; + case 'CallTwo': + //callConnectionId2 = callConnectionId; + calleeId2 = acsTestIdentity2; + console.log('=== CALL TWO CONNECTED ==='); + console.log('User call connected'); + console.log('=== END CALL TWO CONNECTED ==='); + break; + case 'CallThree': + //callConnectionId3 = callConnectionId; + calleeId3 = acsTestIdentity3; + console.log('=== CALL THREE CONNECTED ==='); + console.log('User call connected'); + console.log('=== END CALL THREE CONNECTED ==='); + break; } - } else if (event.type === "Microsoft.Communication.PlayCompleted") { - console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); - console.log(`Received event: ${event.type}`); - - // Notify Target Call user via websocket - if (!webSocket || webSocket.readyState !== 1) { // 1 = OPEN - console.log("ERROR: Web socket is not available."); - return res.status(404).send("Message sent"); - } - - const confirmMessageToTargetCall = "A user is waiting in lobby, do you want to add the user to your call?"; - // Notify Client - webSocket.send(confirmMessageToTargetCall); - console.log(`Target Call notified with message: ${confirmMessageToTargetCall}`); - return res.status(200).send(`Target Call notified with message: ${confirmMessageToTargetCall}`); - } else if (event.type === "Microsoft.Communication.MoveParticipantsSucceeded") { - console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); - console.log(`Received event: ${event.type}`); - console.log(`Call Connection Id: ${eventData.callConnectionId}`); - console.log(`Correlation Id: ${eventData.correlationId}`); - } else if (event.type === "Microsoft.Communication.CallDisconnected") { - console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); - console.log(`Received event: ${event.type}`); - console.log(`Call Connection Id: ${eventData.callConnectionId}`); + } else if (event.type === 'Microsoft.Communication.CallDisconnected') { + console.log(`Call disconnected: ${eventData.callConnectionId}`); + } else { + // Log other events but don't process them for Move Participants scenario + console.log(`Received event: ${event.type} - No action needed for Move Participants scenario`); } - res.status(200).send(); }); +app.get('/call-data', (req, res) => { + console.log("Call Data Endpoint Hit"); + console.log(`call 1: ${callConnectionId1}, call 2: ${callConnectionId2}, call 3: ${callConnectionId3}`); + res.json({ callConnectionId1, callConnectionId2, callConnectionId3, callerId1, callerId2, callerId3, calleeId1, calleeId2, calleeId3 }); +}); + // GET endpoint to serve the webpage app.get('/', (req, res) => { res.sendFile('index.html', { root: 'src/webpage' }); diff --git a/callautomation-lobbycall-sample/src/app.ts.xxx b/callautomation-lobbycall-sample/src/app.ts.xxx new file mode 100644 index 00000000..1cc06e64 --- /dev/null +++ b/callautomation-lobbycall-sample/src/app.ts.xxx @@ -0,0 +1,277 @@ +import { config } from 'dotenv'; +import express, { Application } from 'express'; +import { CommunicationUserIdentifier, PhoneNumberIdentifier } from "@azure/communication-common"; +import { + CallAutomationClient, + CallInvite, + AnswerCallOptions, + MoveParticipantsOptions +} from "@azure/communication-call-automation"; + +config(); + +const PORT = process.env.PORT; +const app: Application = express(); +app.use(express.static('webpage')); +app.use(express.urlencoded({ extended: true })); +app.use(express.json()); + +let lobbyCallConnectionId: string; +let targetCallConnectionId: string; +let acsGeneratedId: string; +let acsClient: CallAutomationClient; +let lobbyCallerId: string; +const callbackUriHost = process.env.CALLBACK_URI || ""; +const connectionString = process.env.CONNECTION_STRING || "" +const endpoint = process.env.PMA_ENDPOINT || "" + +async function createAcsClient() { + lobbyCallConnectionId = ""; + targetCallConnectionId = ""; + acsGeneratedId = process.env.ACS_GENERATED_ID || ""; + lobbyCallerId = ""; + // acsClient = new CallAutomationClient(endpoint, connectionString); + acsClient = new CallAutomationClient(connectionString); + console.log("Initialized ACS Client."); +} + +app.get('/TargetCallToAcsUser(Create)', async (req, res) => { + const acsTarget = req.body.acsTarget; // expects { "acsTarget": "" } + console.log('\n~~~~~~~~~~~~ /TargetCall(Create) ~~~~~~~~~~~~\n'); + + try { + const callbackUri = `${callbackUriHost}/api/callbacks`; + const callInvite = new CommunicationUserIdentifier(acsTarget); + const createCallOptions = { + callInvite, + callbackUri, + callIntelligenceOptions: { + cognitiveServicesEndpoint: 'https://cognitive-service-waferwire.cognitiveservices.azure.com/' + } + }; + + const createCallResult = await acsClient.createCall(createCallOptions); + targetCallConnectionId = createCallResult.callConnectionProperties.callConnectionId; + + const logMsg = ` + TargetCall: + ----------- + From: Call Automation + To: ${acsTarget} + Target Call Connection Id: ${targetCallConnectionId} + Correlation Id: ${createCallResult.callConnectionProperties.correlationId} + `; + console.log(logMsg); + res.type('text/plain').send(logMsg); + } catch (err) { + console.error('Error creating call:', err); + res.status(500).send('Error creating call: ' + err.message); + } +}); + +app.get('/GetParticipants/:callConnectionId', async (req, res) => { + const callConnectionId = req.params.callConnectionId; + console.log(`\n~~~~~~~~~~~~ /GetParticipants/${callConnectionId} ~~~~~~~~~~~~\n`); + try { + const callConnection = acsClient.getCallConnection(callConnectionId); + const participantsResponse = await callConnection.getParticipants(); + const participants = participantsResponse.value; + + // Format participant info + const participantInfo = participants.map(p => { + let type = p.identifier.kind || p.identifier.constructor.name; + let rawId = p.identifier.rawId; + let phoneNumber = p.identifier.phoneNumber || null; + let acsUserId = p.identifier.communicationUserId || null; + + return { + rawId, + type, + phoneNumber, + acsUserId + }; + }); + + // Sort: phone numbers first, then ACS users + participantInfo.sort((a, b) => { + if (!a.acsUserId && b.acsUserId) return -1; + if (a.acsUserId && !b.acsUserId) return 1; + return 0; + }); + + // Format output + if (participantInfo.length === 0) { + return res.status(404).json({ + message: "No participants found for the specified call connection.", + callConnectionId + }); + } else { + let msg = `\nNo of Participants: ${participantInfo.length}\nParticipants: \n-------------\n`; + msg += participantInfo.map((p, i) => { + if (p.acsUserId) { + return `${i + 1}. ${p.type} - RawId: ${p.acsUserId}`; + } else { + return `${i + 1}. ${p.type} - RawId: ${p.rawId}, Phone: ${p.phoneNumber}`; + } + }).join('\n'); + console.log(msg); + return res.type('text/plain').send(msg); + } + } catch (ex) { + console.error(`Error getting participants for call ${callConnectionId}: ${ex.message}`); + return res.status(400).json({ + error: ex.message, + callConnectionId + }); + } +}); + +app.get('/terminateCalls', async (req, res) => { + console.log(`calls 1: ${lobbyCallConnectionId}, 2: ${targetCallConnectionId}`); + if (lobbyCallConnectionId) { + try { + console.log(`Terminating Lobby Call with ID: ${lobbyCallConnectionId}`); + const lobbyConnection = acsClient.getCallConnection(lobbyCallConnectionId); + await lobbyConnection.hangUp(true); + } catch (error) { + console.error(`Error terminating Lobby Call: ${error.message}`); + } + } + if (targetCallConnectionId) { + try { + console.log(`Terminating Target Call with ID: ${targetCallConnectionId}`); + const targetConnection = acsClient.getCallConnection(targetCallConnectionId); + await targetConnection.hangUp(true); + } catch (error) { + console.error(`Error terminating Target Call: ${error.message}`); + } + } + console.log("Calls hung up successfully."); + lobbyCallConnectionId = ""; + targetCallConnectionId = ""; + lobbyCallerId = ""; + res.redirect('/'); +}); + +app.post('/api/LobbyCallSupportEventHandler', async (req, res) => { + console.log('--------- /api/moveParticipantEvent -------------------'); + const event = req.body[0]; + const eventData = event.data; + if (event.eventType === "Microsoft.EventGrid.SubscriptionValidationEvent") { + console.log("SubscriptionValidation event"); + res.status(200).json({ + validationResponse: eventData.validationCode, + }); + return; + } + + // ACS Incoming Call event + if (event.eventType === 'Microsoft.Communication.IncomingCall') { + const fromCallerId = eventData.from.rawId; + const toCallerId = eventData.to.rawId; + + console.log(`From Caller Id: ${fromCallerId}`); + console.log(`To Caller Id : ${toCallerId}`); + + // Lobby Call: Answer + if (toCallerId.includes(acsGeneratedId)) { + const callbackUri = `${callbackUriHost}/api/callbacks`; + const options = { + incomingCallContext: eventData.incomingCallContext, + callbackUri: callbackUri, + operationContext: 'LobbyCall', + callIntelligenceOptions: { + cognitiveServicesEndpoint: process.env.COGNITIVE_SERVICES_ENDPOINT + } + }; + + const answerCallResult = await acsClient.answerCall(options); + lobbyCallConnectionId = answerCallResult.callConnectionProperties.callConnectionId; + + console.log( + `User Call(Inbound) Answered by Call Automation.`, + `From Caller Raw Id: ${fromCallerId}`, + `To Caller Raw Id: ${toCallerId}`, + `Lobby Call Connection Id: ${lobbyCallConnectionId}`, + `Correlation Id: ${eventData.correlationId}`, + `Lobby Call answered successfully.` + ); + } + } + + res.status(200).send(); +}); + +app.post('/api/callbacks', async (req, res) => { + console.log('--------- /api/callbacks -------------------'); + const event = req.body[0]; + const eventData = event.data; + // For demonstration, log the event type and IDs + console.log(`Received call event: ${event.type}`); + console.log(`Correlation id:-> ${eventData.correlationId}`) + + if (event.type === "Microsoft.Communication.CallConnected") { + console.log('\n--------- CallConnected Event Block -------------------'); + + if ((eventData.operationContext || '') === 'LobbyCall') { + console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); + console.log(`Received call event : ${event.type}`); + console.log(`Lobby Call Connection Id: ${eventData.callConnectionId}`); + console.log(`Correlation Id: ${eventData.correlationId}`); + + // Record lobby caller id and connection id + const lobbyCallConnection = acsClient.getCallConnection(eventData.callConnectionId); + const callConnectionProperties = await lobbyCallConnection.getCallConnectionProperties(); + lobbyCallerId = callConnectionProperties.source.rawId; + lobbyCallConnectionId = callConnectionProperties.callConnectionId; + console.log(`Lobby Caller Id: ${lobbyCallerId}`); + console.log(`Lobby Connection Id: ${lobbyCallConnectionId}`); + + // Play lobby waiting message + const callMedia = acsClient.getCallConnection(eventData.callConnectionId).getCallMedia(); + const textSource = new TextSource("You are currently in a lobby call, we will notify the admin that you are waiting."); + textSource.voiceName = "en-US-NancyNeural"; + const playTo = [new CommunicationUserIdentifier(acsIdentity)]; + const playToOptions = new PlayOptions({ playSource: textSource, playTo }); + playToOptions.operationContext = "playToContext"; + await callMedia.play(playToOptions); + } + } else if (event.type === "Microsoft.Communication.PlayCompleted") { + console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); + console.log(`Received event: ${event.type}`); + + // Notify Target Call user via websocket + if (!webSocket || webSocket.readyState !== 1) { // 1 = OPEN + console.log("ERROR: Web socket is not available."); + return res.status(404).send("Message sent"); + } + + const confirmMessageToTargetCall = "A user is waiting in lobby, do you want to add the user to your call?"; + // Notify Client + webSocket.send(confirmMessageToTargetCall); + console.log(`Target Call notified with message: ${confirmMessageToTargetCall}`); + return res.status(200).send(`Target Call notified with message: ${confirmMessageToTargetCall}`); + } else if (event.type === "Microsoft.Communication.MoveParticipantsSucceeded") { + console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); + console.log(`Received event: ${event.type}`); + console.log(`Call Connection Id: ${eventData.callConnectionId}`); + console.log(`Correlation Id: ${eventData.correlationId}`); + } else if (event.type === "Microsoft.Communication.CallDisconnected") { + console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); + console.log(`Received event: ${event.type}`); + console.log(`Call Connection Id: ${eventData.callConnectionId}`); + } + + res.status(200).send(); +}); + +// GET endpoint to serve the webpage +app.get('/', (req, res) => { + res.sendFile('index.html', { root: 'src/webpage' }); +}); + +// Start the server +app.listen(PORT, async () => { + console.log(`Server is listening on port ${PORT}`); + await createAcsClient(); +}); diff --git a/callautomation-multiple-dial-out/package-lock.json b/callautomation-multiple-dial-out/package-lock.json new file mode 100644 index 00000000..5fb643d2 --- /dev/null +++ b/callautomation-multiple-dial-out/package-lock.json @@ -0,0 +1,7174 @@ +{ + "name": "callautomation_connect_rooms", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "callautomation_connect_rooms", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@azure/communication-call-automation": "file:../../azure-sdk-for-js/sdk/communication/communication-call-automation", + "@azure/communication-common": "^2.2.0", + "@azure/communication-identity": "^1.3.1", + "@azure/communication-rooms": "^1.1.1", + "@azure/eventgrid": "^4.12.0", + "@types/express": "^4.17.17", + "@types/node": "^20.2.1", + "dotenv": "^16.0.3", + "express": "^4.18.2" + }, + "devDependencies": { + "nodemon": "^2.0.22", + "ts-node": "^10.9.1", + "typescript": "^5.0.4" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@arethetypeswrong+cli@0.17.4/node_modules/@arethetypeswrong/cli": { + "version": "0.17.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@arethetypeswrong/core": "0.17.4", + "chalk": "^4.1.2", + "cli-table3": "^0.6.3", + "commander": "^10.0.1", + "marked": "^9.1.2", + "marked-terminal": "^7.1.0", + "semver": "^7.5.4" + }, + "bin": { + "attw": "dist/index.js" + }, + "devDependencies": { + "@types/marked": "^5.0.0", + "@types/marked-terminal": "^3.1.3", + "@types/node": "^22.5.0", + "@types/semver": "^7.5.3", + "ts-expose-internals": "5.6.1-rc" + }, + "engines": { + "node": ">=18" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@azure+arm-servicebus@6.1.0/node_modules/@azure/arm-servicebus": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.3.0", + "@azure/core-client": "^1.6.1", + "@azure/core-lro": "^2.2.0", + "@azure/core-paging": "^1.2.0", + "@azure/core-rest-pipeline": "^1.8.0", + "tslib": "^2.2.0" + }, + "devDependencies": { + "@azure-tools/test-credential": "^1.0.0", + "@azure-tools/test-recorder": "^2.0.0", + "@azure/dev-tool": "^1.0.0", + "@azure/identity": "^2.0.1", + "@microsoft/api-extractor": "^7.31.1", + "@rollup/plugin-commonjs": "^21.0.1", + "@rollup/plugin-json": "^4.1.0", + "@rollup/plugin-multi-entry": "^4.1.0", + "@rollup/plugin-node-resolve": "^13.1.3", + "@types/chai": "^4.2.8", + "@types/node": "^14.0.0", + "chai": "^4.2.0", + "cross-env": "^7.0.2", + "mkdirp": "^1.0.4", + "mocha": "^7.1.1", + "rimraf": "^3.0.0", + "rollup": "^2.66.1", + "rollup-plugin-sourcemaps": "^0.6.3", + "typescript": "~4.8.0", + "uglify-js": "^3.4.9" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@azure+core-lro@2.7.2/node_modules/@azure/core-lro": { + "version": "2.7.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-util": "^1.2.0", + "@azure/logger": "^1.0.0", + "tslib": "^2.6.2" + }, + "devDependencies": { + "@azure/core-rest-pipeline": "^1.1.0", + "@azure/dev-tool": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@microsoft/api-extractor": "^7.40.3", + "@types/node": "^18.0.0", + "@vitest/browser": "^1.3.1", + "@vitest/coverage-istanbul": "^1.3.1", + "eslint": "^8.56.0", + "playwright": "^1.41.2", + "prettier": "^3.2.5", + "rimraf": "^5.0.5", + "tshy": "^1.13.0", + "typescript": "~5.3.3", + "vitest": "^1.3.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@azure+identity@4.10.0/node_modules/@azure/identity": { + "version": "4.10.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.9.0", + "@azure/core-client": "^1.9.2", + "@azure/core-rest-pipeline": "^1.17.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.11.0", + "@azure/logger": "^1.0.0", + "@azure/msal-browser": "^4.2.0", + "@azure/msal-node": "^3.5.0", + "open": "^10.1.0", + "tslib": "^2.2.0" + }, + "devDependencies": { + "@azure-tools/test-recorder": "^4.1.0", + "@azure-tools/test-utils-vitest": "^1.0.0", + "@azure/dev-tool": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@azure/keyvault-keys": "^4.2.0", + "@types/jsonwebtoken": "^9.0.0", + "@types/ms": "^2.1.0", + "@types/node": "^18.0.0", + "@vitest/browser": "^3.0.9", + "@vitest/coverage-istanbul": "^3.0.9", + "assertion-error": "^2.0.1", + "dotenv": "^16.0.0", + "eslint": "^9.9.0", + "jsonwebtoken": "^9.0.0", + "ms": "^2.1.3", + "playwright": "^1.48.2", + "typescript": "~5.8.2", + "vitest": "^3.0.9" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@azure+identity@4.3.0/node_modules/@azure/identity": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.5.0", + "@azure/core-client": "^1.9.2", + "@azure/core-rest-pipeline": "^1.1.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.3.0", + "@azure/logger": "^1.0.0", + "@azure/msal-browser": "^3.11.1", + "@azure/msal-node": "^2.9.2", + "events": "^3.0.0", + "jws": "^4.0.0", + "open": "^8.0.0", + "stoppable": "^1.1.0", + "tslib": "^2.2.0" + }, + "devDependencies": { + "@azure-tools/test-recorder": "^3.0.0", + "@azure-tools/test-utils": "^1.0.1", + "@azure/dev-tool": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@azure/keyvault-keys": "^4.2.0", + "@microsoft/api-extractor": "^7.31.1", + "@types/chai": "^4.1.6", + "@types/jsonwebtoken": "^9.0.0", + "@types/jws": "^3.2.2", + "@types/mocha": "^10.0.0", + "@types/ms": "^0.7.31", + "@types/node": "^18.0.0", + "@types/sinon": "^17.0.0", + "@types/stoppable": "^1.1.0", + "@types/uuid": "^8.0.0", + "chai": "^4.2.0", + "cross-env": "^7.0.3", + "dotenv": "^16.0.0", + "eslint": "^8.0.0", + "inherits": "^2.0.3", + "jsonwebtoken": "^9.0.0", + "karma": "^6.2.0", + "karma-chrome-launcher": "^3.0.0", + "karma-coverage": "^2.0.0", + "karma-env-preprocessor": "^0.1.1", + "karma-junit-reporter": "^2.0.1", + "karma-mocha": "^2.0.1", + "karma-mocha-reporter": "^2.2.5", + "karma-sourcemap-loader": "^0.3.8", + "mocha": "^10.0.0", + "ms": "^2.1.3", + "nyc": "^15.1.0", + "puppeteer": "^22.2.0", + "rimraf": "^5.0.5", + "sinon": "^17.0.0", + "ts-node": "^10.0.0", + "typescript": "~5.4.5", + "util": "^0.12.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@azure+keyvault-keys@4.9.0/node_modules/@azure/keyvault-keys": { + "version": "4.9.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.3.0", + "@azure/core-client": "^1.5.0", + "@azure/core-http-compat": "^2.0.1", + "@azure/core-lro": "^2.2.0", + "@azure/core-paging": "^1.1.1", + "@azure/core-rest-pipeline": "^1.8.1", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.0.0", + "@azure/keyvault-common": "^2.0.0", + "@azure/logger": "^1.0.0", + "tslib": "^2.2.0" + }, + "devDependencies": { + "@azure-tools/test-credential": "^2.0.0", + "@azure-tools/test-recorder": "^4.1.0", + "@azure-tools/test-utils-vitest": "^1.0.0", + "@azure/dev-tool": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@azure/identity": "^4.4.1", + "@microsoft/api-extractor": "^7.31.1", + "@types/node": "^18.0.0", + "@vitest/browser": "^2.1.2", + "@vitest/coverage-istanbul": "^2.1.2", + "cross-env": "^7.0.2", + "dayjs": "^1.10.7", + "dotenv": "^16.0.0", + "eslint": "^9.9.0", + "playwright": "^1.47.2", + "rimraf": "^5.0.5", + "typescript": "~5.6.2", + "vitest": "^2.1.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@azure+msal-browser@4.13.0/node_modules/@azure/msal-browser": { + "version": "4.13.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/msal-common": "15.7.0" + }, + "devDependencies": { + "@azure/storage-blob": "^12.2.1", + "@babel/core": "^7.7.2", + "@babel/plugin-proposal-class-properties": "^7.7.0", + "@babel/plugin-proposal-object-rest-spread": "^7.6.2", + "@babel/preset-env": "^7.7.1", + "@babel/preset-typescript": "^7.7.2", + "@microsoft/api-extractor": "^7.43.4", + "@rollup/plugin-node-resolve": "^15.0.1", + "@rollup/plugin-terser": "^0.4.0", + "@rollup/plugin-typescript": "^11.0.0", + "@types/jest": "^29.5.0", + "@types/node": "^20.3.1", + "dotenv": "^8.2.0", + "eslint-config-msal": "file:../../shared-configs/eslint-config-msal", + "fake-indexeddb": "^3.1.3", + "jest": "^29.5.0", + "jest-environment-jsdom": "^29.5.0", + "jest-junit": "^16.0.0", + "msal-test-utils": "file:../../shared-test-utils", + "prettier": "^2.8.7", + "rimraf": "^3.0.0", + "rollup": "^4.22.4", + "rollup-msal": "file:../../shared-configs/rollup-msal", + "shx": "^0.3.2", + "ssri": "^8.0.1", + "ts-jest": "^29.2.5", + "ts-jest-resolver": "^2.0.1", + "tslib": "^1.10.0", + "typescript": "^4.9.5" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@azure+msal-node@2.16.2/node_modules/@azure/msal-node": { + "version": "2.16.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/msal-common": "14.16.0", + "jsonwebtoken": "^9.0.0", + "uuid": "^8.3.0" + }, + "devDependencies": { + "@microsoft/api-extractor": "^7.43.4", + "@rollup/plugin-node-resolve": "^15.0.1", + "@rollup/plugin-typescript": "^11.0.0", + "@types/jest": "^29.5.0", + "@types/jsonwebtoken": "^9.0.1", + "@types/node": "^20.3.1", + "@types/uuid": "^7.0.0", + "eslint-config-msal": "file:../../shared-configs/eslint-config-msal", + "jest": "^29.5.0", + "prettier": "2.8.7", + "rollup": "^4.22.4", + "rollup-msal": "file:../../shared-configs/rollup-msal", + "ts-jest": "^29.1.0", + "tslib": "^1.10.0", + "typescript": "^4.9.5", + "yargs": "^17.3.1" + }, + "engines": { + "node": ">=16" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@azure+msal-node@3.6.0/node_modules/@azure/msal-node": { + "version": "3.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/msal-common": "15.7.0", + "jsonwebtoken": "^9.0.0", + "uuid": "^8.3.0" + }, + "devDependencies": { + "@microsoft/api-extractor": "^7.43.4", + "@rollup/plugin-node-resolve": "^15.0.1", + "@rollup/plugin-typescript": "^11.0.0", + "@types/jest": "^29.5.0", + "@types/jsonwebtoken": "^9.0.1", + "@types/node": "^20.3.1", + "@types/uuid": "^7.0.0", + "eslint-config-msal": "file:../../shared-configs/eslint-config-msal", + "jest": "^29.5.0", + "jest-junit": "^16.0.0", + "prettier": "2.8.7", + "rollup": "^4.22.4", + "rollup-msal": "file:../../shared-configs/rollup-msal", + "ts-jest": "^29.1.0", + "tslib": "^1.10.0", + "typescript": "^4.9.5", + "yargs": "^17.3.1" + }, + "engines": { + "node": ">=16" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@eslint+compat@1.2.9_eslint@9.28.0/node_modules/@eslint/compat": { + "version": "1.2.9", + "dev": true, + "license": "Apache-2.0", + "devDependencies": { + "@eslint/core": "^0.14.0", + "c8": "^9.1.0", + "eslint": "^9.11.0", + "mocha": "^10.4.0", + "rollup": "^4.16.2", + "typescript": "^5.4.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": "^9.10.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@eslint+eslintrc@3.3.1/node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "devDependencies": { + "c8": "^7.7.3", + "chai": "^4.3.4", + "eslint": "^9.20.1", + "eslint-config-eslint": "^11.0.0", + "eslint-release": "^3.2.0", + "fs-teardown": "^0.1.3", + "mocha": "^9.0.3", + "rollup": "^2.70.1", + "shelljs": "^0.8.5", + "sinon": "^11.1.2", + "temp-dir": "^2.0.0", + "typescript": "^5.7.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@eslint+js@9.28.0/node_modules/@eslint/js": { + "version": "9.28.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@microsoft+api-extractor-model@7.30.6_@types+node@18.19.110/node_modules/@microsoft/api-extractor-model": { + "version": "7.30.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/tsdoc": "~0.15.1", + "@microsoft/tsdoc-config": "~0.17.1", + "@rushstack/node-core-library": "5.13.1" + }, + "devDependencies": { + "@rushstack/heft": "0.73.2", + "decoupled-local-node-rig": "1.0.0", + "local-eslint-config": "1.0.0" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@microsoft+api-extractor@7.52.8_@types+node@18.19.110/node_modules/@microsoft/api-extractor": { + "version": "7.52.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/api-extractor-model": "7.30.6", + "@microsoft/tsdoc": "~0.15.1", + "@microsoft/tsdoc-config": "~0.17.1", + "@rushstack/node-core-library": "5.13.1", + "@rushstack/rig-package": "0.5.3", + "@rushstack/terminal": "0.15.3", + "@rushstack/ts-command-line": "5.0.1", + "lodash": "~4.17.15", + "minimatch": "~3.0.3", + "resolve": "~1.22.1", + "semver": "~7.5.4", + "source-map": "~0.6.1", + "typescript": "5.8.2" + }, + "bin": { + "api-extractor": "bin/api-extractor" + }, + "devDependencies": { + "@rushstack/heft": "0.73.2", + "@types/lodash": "4.14.116", + "@types/minimatch": "3.0.5", + "@types/resolve": "1.20.2", + "@types/semver": "7.5.0", + "decoupled-local-node-rig": "1.0.0", + "local-eslint-config": "1.0.0" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@opentelemetry+api@1.9.0/node_modules/@opentelemetry/api": { + "version": "1.9.0", + "dev": true, + "license": "Apache-2.0", + "devDependencies": { + "@types/mocha": "10.0.6", + "@types/node": "18.6.5", + "@types/sinon": "17.0.3", + "@types/webpack": "5.28.5", + "@types/webpack-env": "1.16.3", + "babel-plugin-istanbul": "6.1.1", + "codecov": "3.8.3", + "cross-var": "1.1.0", + "dpdm": "3.13.1", + "karma": "6.4.3", + "karma-chrome-launcher": "3.1.0", + "karma-coverage": "2.2.1", + "karma-mocha": "2.0.1", + "karma-mocha-webworker": "1.3.0", + "karma-spec-reporter": "0.0.36", + "karma-webpack": "5.0.1", + "lerna": "6.6.2", + "memfs": "3.5.3", + "mocha": "10.2.0", + "nyc": "15.1.0", + "sinon": "15.1.2", + "ts-loader": "9.5.1", + "ts-mocha": "10.0.0", + "typescript": "4.4.4", + "unionfs": "4.5.4", + "webpack": "5.89.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@rollup+plugin-inject@5.0.5_rollup@4.41.1/node_modules/@rollup/plugin-inject": { + "version": "5.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.3" + }, + "devDependencies": { + "@rollup/plugin-buble": "^1.0.0", + "del-cli": "^5.0.0", + "locate-character": "^2.0.5", + "rollup": "^4.0.0-24", + "source-map": "^0.7.4", + "typescript": "^4.8.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+chai-as-promised@8.0.2/node_modules/@types/chai-as-promised": { + "version": "8.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "*" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+debug@4.1.12/node_modules/@types/debug": { + "version": "4.1.12", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+eslint-config-prettier@6.11.3/node_modules/@types/eslint-config-prettier": { + "version": "6.11.3", + "dev": true, + "license": "MIT" + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+eslint@9.6.1/node_modules/@types/eslint": { + "version": "9.6.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+estree@1.0.7/node_modules/@types/estree": { + "version": "1.0.7", + "dev": true, + "license": "MIT" + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+express-serve-static-core@5.0.6/node_modules/@types/express-serve-static-core": { + "version": "5.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+express@5.0.2/node_modules/@types/express": { + "version": "5.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "*" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+fs-extra@11.0.4/node_modules/@types/fs-extra": { + "version": "11.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/jsonfile": "*", + "@types/node": "*" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+is-buffer@2.0.2/node_modules/@types/is-buffer": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+jsonwebtoken@9.0.9/node_modules/@types/jsonwebtoken": { + "version": "9.0.9", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*", + "@types/node": "*" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+minimist@1.2.5/node_modules/@types/minimist": { + "version": "1.2.5", + "dev": true, + "license": "MIT" + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+ms@2.1.0/node_modules/@types/ms": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+node@18.19.110/node_modules/@types/node": { + "version": "18.19.110", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+semver@7.7.0/node_modules/@types/semver": { + "version": "7.7.0", + "dev": true, + "license": "MIT" + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+trusted-types@2.0.7/node_modules/@types/trusted-types": { + "version": "2.0.7", + "dev": true, + "license": "MIT" + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+unzipper@0.10.11/node_modules/@types/unzipper": { + "version": "0.10.11", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+ws@7.4.7/node_modules/@types/ws": { + "version": "7.4.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+ws@8.18.1/node_modules/@types/ws": { + "version": "8.18.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@typescript-eslint+eslint-plugin@8.26.1_@typescript-eslint+parser@8.26.1_eslint@9.28.0_typesc_cpt2wfi56j2kmlqfdpy32xzd7a/node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.26.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.26.1", + "@typescript-eslint/type-utils": "8.26.1", + "@typescript-eslint/utils": "8.26.1", + "@typescript-eslint/visitor-keys": "8.26.1", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.0.1" + }, + "devDependencies": { + "@jest/types": "29.6.3", + "@types/marked": "^5.0.2", + "@types/mdast": "^4.0.3", + "@types/natural-compare": "*", + "@typescript-eslint/rule-schema-to-typescript-types": "8.26.1", + "@typescript-eslint/rule-tester": "8.26.1", + "ajv": "^6.12.6", + "cross-env": "^7.0.3", + "cross-fetch": "*", + "eslint": "*", + "jest": "29.7.0", + "jest-specific-snapshot": "^8.0.0", + "json-schema": "*", + "markdown-table": "^3.0.3", + "marked": "^5.1.2", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-mdx": "^3.0.0", + "micromark-extension-mdxjs": "^3.0.0", + "prettier": "^3.2.5", + "rimraf": "*", + "title-case": "^3.0.3", + "tsx": "*", + "typescript": "*", + "unist-util-visit": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@typescript-eslint+parser@8.26.1_eslint@9.28.0_typescript@5.8.3/node_modules/@typescript-eslint/parser": { + "version": "8.26.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.26.1", + "@typescript-eslint/types": "8.26.1", + "@typescript-eslint/typescript-estree": "8.26.1", + "@typescript-eslint/visitor-keys": "8.26.1", + "debug": "^4.3.4" + }, + "devDependencies": { + "@jest/types": "29.6.3", + "downlevel-dts": "*", + "glob": "*", + "jest": "29.7.0", + "prettier": "^3.2.5", + "rimraf": "*", + "typescript": "*" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@typescript-eslint+rule-tester@8.26.1_eslint@9.28.0_typescript@5.8.3/node_modules/@typescript-eslint/rule-tester": { + "version": "8.26.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/parser": "8.26.1", + "@typescript-eslint/typescript-estree": "8.26.1", + "@typescript-eslint/utils": "8.26.1", + "ajv": "^6.12.6", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "4.6.2", + "semver": "^7.6.0" + }, + "devDependencies": { + "@jest/types": "29.6.3", + "@types/json-stable-stringify-without-jsonify": "^1.0.2", + "@types/lodash.merge": "4.6.9", + "chai": "^4.4.1", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esprima": "^4.0.1", + "mocha": "^10.4.0", + "sinon": "^16.1.3", + "source-map-support": "^0.5.21", + "typescript": "*" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@typescript-eslint+typescript-estree@8.26.1_typescript@5.8.3/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.26.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.26.1", + "@typescript-eslint/visitor-keys": "8.26.1", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.0.1" + }, + "devDependencies": { + "@jest/types": "29.6.3", + "glob": "*", + "jest": "29.7.0", + "prettier": "^3.2.5", + "rimraf": "*", + "tmp": "*", + "typescript": "*" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@typescript-eslint+utils@8.26.1_eslint@9.28.0_typescript@5.8.3/node_modules/@typescript-eslint/utils": { + "version": "8.26.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.26.1", + "@typescript-eslint/types": "8.26.1", + "@typescript-eslint/typescript-estree": "8.26.1" + }, + "devDependencies": { + "downlevel-dts": "*", + "jest": "29.7.0", + "prettier": "^3.2.5", + "rimraf": "*", + "typescript": "*" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+browser@3.2.0_playwright@1.52.0_vite@6.3.5_@types+node@22.7.9_tsx@4.19.4_yaml@2.8.0__vitest@3.2.0/node_modules/@vitest/browser": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@testing-library/dom": "^10.4.0", + "@testing-library/user-event": "^14.6.1", + "@vitest/mocker": "3.2.0", + "@vitest/utils": "3.2.0", + "magic-string": "^0.30.17", + "sirv": "^3.0.1", + "tinyrainbow": "^2.0.0", + "ws": "^8.18.2" + }, + "devDependencies": { + "@types/ws": "^8.18.1", + "@vitest/runner": "3.2.0", + "@vitest/ui": "3.2.0", + "@vitest/ws-client": "3.2.0", + "@wdio/protocols": "^9.15.0", + "@wdio/types": "^9.15.0", + "birpc": "2.3.0", + "flatted": "^3.3.3", + "ivya": "^1.6.0", + "mime": "^4.0.7", + "pathe": "^2.0.3", + "periscopic": "^4.0.2", + "playwright": "^1.52.0", + "playwright-core": "^1.52.0", + "safaridriver": "^1.0.0", + "vitest": "3.2.0", + "webdriverio": "^9.15.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "playwright": "*", + "vitest": "3.2.0", + "webdriverio": "^7.0.0 || ^8.0.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "playwright": { + "optional": true + }, + "safaridriver": { + "optional": true + }, + "webdriverio": { + "optional": true + } + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+coverage-istanbul@3.2.0_vitest@3.2.0/node_modules/@vitest/coverage-istanbul": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@istanbuljs/schema": "^0.1.3", + "debug": "^4.4.1", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-instrument": "^6.0.3", + "istanbul-lib-report": "^3.0.1", + "istanbul-lib-source-maps": "^5.0.6", + "istanbul-reports": "^3.1.7", + "magicast": "^0.3.5", + "test-exclude": "^7.0.1", + "tinyrainbow": "^2.0.0" + }, + "devDependencies": { + "@types/debug": "^4.1.12", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-lib-instrument": "^1.7.7", + "@types/istanbul-lib-report": "^3.0.3", + "@types/istanbul-lib-source-maps": "^4.0.4", + "@types/istanbul-reports": "^3.0.4", + "@types/test-exclude": "^6.0.2", + "pathe": "^2.0.3", + "vitest": "3.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "vitest": "3.2.0" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+expect@3.2.0/node_modules/@vitest/expect": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.0", + "@vitest/utils": "3.2.0", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "devDependencies": { + "@vitest/runner": "3.2.0", + "rollup-plugin-copy": "^3.5.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/assertion-error@2.0.1/node_modules/assertion-error": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/autorest@3.7.2/node_modules/autorest": { + "version": "3.7.2", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "autorest": "entrypoints/app.js" + }, + "devDependencies": { + "@autorest/common": "~1.6.1", + "@autorest/configuration": "~1.12.2", + "@autorest/core": "~3.10.6", + "@azure-tools/async-io": "~3.0.0", + "@azure-tools/extension": "~3.7.2", + "@azure-tools/tasks": "~3.0.0", + "@azure-tools/uri": "~3.1.1", + "@types/commonmark": "^0.27.0", + "@types/jest": "^29.5.14", + "@types/node": "~22.15.19", + "@types/semver": "7.7.0", + "@types/source-map-support": "^0.5.3", + "@types/webpack": "~5.28.5", + "@typescript-eslint/eslint-plugin": "^8.32.1", + "@typescript-eslint/parser": "^8.32.1", + "chalk": "^4.1.0", + "copy-webpack-plugin": "^13.0.0", + "cpy-cli": "~5.0.0", + "eslint": "^8.28.0", + "eslint-plugin-import": "~2.31.0", + "eslint-plugin-jest": "~28.11.0", + "eslint-plugin-node": "~11.1.0", + "eslint-plugin-prettier": "~5.4.0", + "eslint-plugin-unicorn": "~49.0.0", + "jest": "^29.3.1", + "mkdirp": "~3.0.1", + "prettier": "~3.5.3", + "rimraf": "^6.0.1", + "safe-buffer": "5.2.1", + "semver": "^7.7.2", + "source-map": "^0.8.0-beta.0", + "source-map-support": "^0.5.19", + "ts-jest": "^29.3.4", + "ts-loader": "~9.5.2", + "typescript": "~5.8.3", + "untildify": "^4.0.0", + "webpack": "~5.99.8", + "webpack-cli": "~6.0.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/buffer@6.0.3/node_modules/buffer": { + "version": "6.0.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + }, + "devDependencies": { + "airtap": "^3.0.0", + "benchmark": "^2.1.4", + "browserify": "^17.0.0", + "concat-stream": "^2.0.0", + "hyperquest": "^2.1.3", + "is-buffer": "^2.0.5", + "is-nan": "^1.3.0", + "split": "^1.0.1", + "standard": "*", + "tape": "^5.0.1", + "through2": "^4.0.2", + "uglify-js": "^3.11.5" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/builtin-modules@3.3.0/node_modules/builtin-modules": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "devDependencies": { + "ava": "^1.4.1", + "tsd": "^0.7.2", + "xo": "^0.24.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/chai-as-promised@8.0.1_chai@5.2.0/node_modules/chai-as-promised": { + "version": "8.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "check-error": "^2.0.0" + }, + "devDependencies": { + "c8": "^9.1.0", + "chai": "^5.1.0", + "eslint": "^8.57.0", + "mocha": "^10.4.0", + "prettier": "^3.2.5" + }, + "peerDependencies": { + "chai": ">= 2.1.2 < 6" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/chai-exclude@3.0.1_chai@5.2.0/node_modules/chai-exclude": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "fclone": "^1.0.11" + }, + "devDependencies": { + "@types/chai": "^4.3.16", + "chai": "^5.1.1", + "mocha": "^10.6.0", + "standard": "^17.0.0" + }, + "peerDependencies": { + "chai": ">= 5" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/chai@5.2.0/node_modules/chai": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "devDependencies": { + "@eslint/js": "^9.17.0", + "@rollup/plugin-commonjs": "^25.0.7", + "@web/dev-server-rollup": "^0.6.1", + "@web/test-runner": "^0.18.0", + "@web/test-runner-playwright": "^0.11.0", + "c8": "^10.1.3", + "esbuild": "^0.19.10", + "eslint": "^8.56.0", + "eslint-plugin-jsdoc": "^48.0.4", + "mocha": "^10.2.0", + "prettier": "^3.4.2" + }, + "engines": { + "node": ">=12" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/chalk@4.1.2/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "devDependencies": { + "ava": "^2.4.0", + "coveralls": "^3.0.7", + "execa": "^4.0.0", + "import-fresh": "^3.1.0", + "matcha": "^0.7.0", + "nyc": "^15.0.0", + "resolve-from": "^5.0.0", + "tsd": "^0.7.4", + "xo": "^0.28.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/concurrently@8.2.2/node_modules/concurrently": { + "version": "8.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "date-fns": "^2.30.0", + "lodash": "^4.17.21", + "rxjs": "^7.8.1", + "shell-quote": "^1.8.1", + "spawn-command": "0.0.2", + "supports-color": "^8.1.1", + "tree-kill": "^1.2.2", + "yargs": "^17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "devDependencies": { + "@hirez_io/observer-spy": "^2.2.0", + "@swc/core": "^1.3.93", + "@swc/jest": "^0.2.29", + "@types/jest": "^29.5.6", + "@types/lodash": "^4.14.200", + "@types/node": "^14.18.62", + "@types/shell-quote": "^1.7.3", + "@types/supports-color": "^8.1.2", + "@types/yargs": "^17.0.29", + "@typescript-eslint/eslint-plugin": "^6.8.0", + "@typescript-eslint/parser": "^6.8.0", + "coveralls-next": "^4.2.0", + "ctrlc-wrapper": "^0.0.4", + "esbuild": "~0.19.5", + "eslint": "^8.51.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-import": "^2.28.1", + "eslint-plugin-jest": "^27.4.2", + "eslint-plugin-prettier": "^5.0.1", + "eslint-plugin-simple-import-sort": "^10.0.0", + "husky": "^8.0.3", + "jest": "^29.7.0", + "jest-create-mock-instance": "^2.0.0", + "lint-staged": "^13.3.0", + "prettier": "^3.0.3", + "safe-publish-latest": "^2.0.0", + "string-argv": "^0.3.2", + "typescript": "~5.2.2" + }, + "engines": { + "node": "^14.13.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/cross-env@7.0.3/node_modules/cross-env": { + "version": "7.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "devDependencies": { + "kcd-scripts": "^5.5.0" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/debug@4.4.1/node_modules/debug": { + "version": "4.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "devDependencies": { + "brfs": "^2.0.1", + "browserify": "^16.2.3", + "coveralls": "^3.0.2", + "karma": "^3.1.4", + "karma-browserify": "^6.0.0", + "karma-chrome-launcher": "^2.2.0", + "karma-mocha": "^1.3.0", + "mocha": "^5.2.0", + "mocha-lcov-reporter": "^1.2.0", + "sinon": "^14.0.0", + "xo": "^0.23.0" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/dotenv@16.5.0/node_modules/dotenv": { + "version": "16.5.0", + "dev": true, + "license": "BSD-2-Clause", + "devDependencies": { + "@types/node": "^18.11.3", + "decache": "^4.6.2", + "sinon": "^14.0.1", + "standard": "^17.0.0", + "standard-version": "^9.5.0", + "tap": "^19.2.0", + "typescript": "^4.8.4" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint-config-prettier@10.1.5_eslint@9.28.0/node_modules/eslint-config-prettier": { + "version": "10.1.5", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint-plugin-n@17.19.0_eslint@9.28.0_typescript@5.8.3/node_modules/eslint-plugin-n": { + "version": "17.19.0", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.5.0", + "@typescript-eslint/utils": "^8.26.1", + "enhanced-resolve": "^5.17.1", + "eslint-plugin-es-x": "^7.8.0", + "get-tsconfig": "^4.8.1", + "globals": "^15.11.0", + "ignore": "^5.3.2", + "minimatch": "^9.0.5", + "semver": "^7.6.3", + "ts-declaration-location": "^1.0.6" + }, + "devDependencies": { + "@eslint/js": "^9.14.0", + "@types/eslint": "^9.6.1", + "@types/estree": "^1.0.6", + "@types/node": "^20.17.5", + "@typescript-eslint/parser": "^8.26.1", + "@typescript-eslint/typescript-estree": "^8.26.1", + "eslint": "^9.14.0", + "eslint-config-prettier": "^9.1.0", + "eslint-doc-generator": "^1.7.1", + "eslint-plugin-eslint-plugin": "^6.3.1", + "eslint-plugin-n": "file:.", + "fast-glob": "^3.3.2", + "husky": "^9.1.6", + "lint-staged": "^15.2.10", + "markdownlint-cli": "^0.42.0", + "mocha": "^10.8.2", + "npm-run-all2": "^6.2.6", + "nyc": "^17.1.0", + "opener": "^1.5.2", + "prettier": "^3.3.3", + "punycode": "^2.3.1", + "release-it": "^17.10.0", + "rimraf": "^5.0.10", + "ts-ignore-import": "^4.0.1", + "type-fest": "^4.26.1", + "typescript": "~5.6" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": ">=8.23.0" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint-plugin-no-only-tests@3.3.0/node_modules/eslint-plugin-no-only-tests": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "peer": true, + "devDependencies": { + "@biomejs/biome": "^1.8.3", + "@types/eslint": "^9.6.0", + "@types/eslint__js": "^8.42.3", + "@types/node": "^22.3.0", + "eslint": ">=9.0.0", + "typescript": "^5.5.4" + }, + "engines": { + "node": ">=5.0.0" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint-plugin-promise@7.2.1_eslint@9.28.0/node_modules/eslint-plugin-promise": { + "version": "7.2.1", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0" + }, + "devDependencies": { + "@typescript-eslint/parser": "^7.17.0", + "doctoc": "^2.2.1", + "eslint": "^8.56.0", + "eslint-config-prettier": "^9.1.0", + "eslint-doc-generator": "^1.7.1", + "eslint-plugin-eslint-plugin": "^6.2.0", + "eslint-plugin-jest": "^28.6.0", + "eslint-plugin-n": "^17.9.0", + "eslint-plugin-prettier": "^5.2.1", + "globals": "^15.8.0", + "husky": "^9.1.1", + "jest": "^29.7.0", + "lint-staged": "^15.2.7", + "npm-run-all2": "^6.2.2", + "prettier": "^3.3.3", + "typescript": "~5.6.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint-plugin-tsdoc@0.4.0/node_modules/eslint-plugin-tsdoc": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@microsoft/tsdoc": "0.15.1", + "@microsoft/tsdoc-config": "0.17.1" + }, + "devDependencies": { + "@rushstack/heft": "^0.66.13", + "@rushstack/heft-node-rig": "~2.6.11", + "@types/eslint": "8.40.1", + "@types/estree": "1.0.1", + "@types/heft-jest": "1.0.3", + "@types/node": "14.18.36", + "eslint": "~8.57.0", + "eslint-plugin-header": "~3.1.1" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint@9.28.0/node_modules/eslint": { + "version": "9.28.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.20.0", + "@eslint/config-helpers": "^0.2.1", + "@eslint/core": "^0.14.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.28.0", + "@eslint/plugin-kit": "^0.3.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.3.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "devDependencies": { + "@arethetypeswrong/cli": "^0.18.0", + "@babel/core": "^7.4.3", + "@babel/preset-env": "^7.4.3", + "@cypress/webpack-preprocessor": "^6.0.2", + "@eslint/json": "^0.12.0", + "@trunkio/launcher": "^1.3.4", + "@types/esquery": "^1.5.4", + "@types/node": "^22.13.14", + "@typescript-eslint/parser": "^8.4.0", + "babel-loader": "^8.0.5", + "c8": "^7.12.0", + "chai": "^4.0.1", + "cheerio": "^0.22.0", + "common-tags": "^1.8.0", + "core-js": "^3.1.3", + "cypress": "^14.1.0", + "ejs": "^3.0.2", + "eslint": "file:.", + "eslint-config-eslint": "file:packages/eslint-config-eslint", + "eslint-plugin-eslint-plugin": "^6.0.0", + "eslint-plugin-expect-type": "^0.6.0", + "eslint-plugin-yml": "^1.14.0", + "eslint-release": "^3.3.0", + "eslint-rule-composer": "^0.3.0", + "eslump": "^3.0.0", + "esprima": "^4.0.1", + "fast-glob": "^3.2.11", + "fs-teardown": "^0.1.3", + "glob": "^10.0.0", + "globals": "^16.2.0", + "got": "^11.8.3", + "gray-matter": "^4.0.3", + "jiti": "^2.2.0", + "jiti-v2.0": "npm:jiti@2.0.x", + "jiti-v2.1": "npm:jiti@2.1.x", + "knip": "^5.32.0", + "lint-staged": "^11.0.0", + "load-perf": "^0.2.0", + "markdown-it": "^12.2.0", + "markdown-it-container": "^3.0.0", + "marked": "^4.0.8", + "metascraper": "^5.25.7", + "metascraper-description": "^5.25.7", + "metascraper-image": "^5.29.3", + "metascraper-logo": "^5.25.7", + "metascraper-logo-favicon": "^5.25.7", + "metascraper-title": "^5.25.7", + "mocha": "^10.7.3", + "node-polyfill-webpack-plugin": "^1.0.3", + "npm-license": "^0.3.3", + "pirates": "^4.0.5", + "progress": "^2.0.3", + "proxyquire": "^2.0.1", + "recast": "^0.23.0", + "regenerator-runtime": "^0.14.0", + "semver": "^7.5.3", + "shelljs": "^0.10.0", + "sinon": "^11.0.0", + "typescript": "^5.3.3", + "webpack": "^5.23.0", + "webpack-cli": "^4.5.0", + "yorkie": "^2.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/events@3.3.0/node_modules/events": { + "version": "3.3.0", + "license": "MIT", + "devDependencies": { + "airtap": "^1.0.0", + "functions-have-names": "^1.2.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "isarray": "^2.0.5", + "tape": "^5.0.0" + }, + "engines": { + "node": ">=0.8.x" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/express@4.21.2/node_modules/express": { + "version": "4.21.2", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "devDependencies": { + "after": "0.8.2", + "connect-redis": "3.4.2", + "cookie-parser": "1.4.6", + "cookie-session": "2.0.0", + "ejs": "3.1.9", + "eslint": "8.47.0", + "express-session": "1.17.2", + "hbs": "4.2.0", + "marked": "0.7.0", + "method-override": "3.0.0", + "mocha": "10.2.0", + "morgan": "1.10.0", + "nyc": "15.1.0", + "pbkdf2-password": "1.2.1", + "supertest": "6.3.0", + "vhost": "~3.0.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/express@5.1.0/node_modules/express": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.0", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "devDependencies": { + "after": "0.8.2", + "connect-redis": "^8.0.1", + "cookie-parser": "1.4.7", + "cookie-session": "2.1.0", + "ejs": "^3.1.10", + "eslint": "8.47.0", + "express-session": "^1.18.1", + "hbs": "4.2.0", + "marked": "^15.0.3", + "method-override": "3.0.0", + "mocha": "^10.7.3", + "morgan": "1.10.0", + "nyc": "^17.1.0", + "pbkdf2-password": "1.2.1", + "supertest": "^6.3.0", + "vhost": "~3.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/fast-xml-parser@5.2.3/node_modules/fast-xml-parser": { + "version": "5.2.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "strnum": "^2.1.0" + }, + "bin": { + "fxparser": "src/cli/cli.js" + }, + "devDependencies": { + "@babel/core": "^7.13.10", + "@babel/plugin-transform-runtime": "^7.13.10", + "@babel/preset-env": "^7.13.10", + "@babel/register": "^7.13.8", + "@types/node": "20", + "babel-loader": "^8.2.2", + "c8": "^10.1.3", + "eslint": "^8.3.0", + "he": "^1.2.0", + "jasmine": "^5.6.0", + "prettier": "^3.5.1", + "publish-please": "^5.5.2", + "typescript": "5", + "webpack": "^5.64.4", + "webpack-cli": "^4.9.1" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/fs-extra@11.3.0/node_modules/fs-extra": { + "version": "11.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "devDependencies": { + "klaw": "^2.1.1", + "klaw-sync": "^3.0.2", + "minimist": "^1.1.1", + "mocha": "^10.1.0", + "nyc": "^15.0.0", + "proxyquire": "^2.0.1", + "read-dir-files": "^0.1.1", + "standard": "^17.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/glob@10.4.5/node_modules/glob": { + "version": "10.4.5", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "devDependencies": { + "@types/node": "^20.11.30", + "memfs": "^3.4.13", + "mkdirp": "^3.0.1", + "prettier": "^3.2.5", + "rimraf": "^5.0.7", + "sync-content": "^1.0.2", + "tap": "^19.0.0", + "tshy": "^1.14.0", + "typedoc": "^0.25.12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/http-proxy-agent@7.0.2/node_modules/http-proxy-agent": { + "version": "7.0.2", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "devDependencies": { + "@types/debug": "^4.1.7", + "@types/jest": "^29.5.1", + "@types/node": "^14.18.45", + "async-listen": "^3.0.0", + "jest": "^29.5.0", + "proxy": "2.1.1", + "ts-jest": "^29.1.0", + "tsconfig": "0.0.0", + "typescript": "^5.0.4" + }, + "engines": { + "node": ">= 14" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/https-proxy-agent@7.0.6/node_modules/https-proxy-agent": { + "version": "7.0.6", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "devDependencies": { + "@types/async-retry": "^1.4.5", + "@types/debug": "4", + "@types/jest": "^29.5.1", + "@types/node": "^14.18.45", + "async-listen": "^3.0.0", + "async-retry": "^1.3.3", + "jest": "^29.5.0", + "proxy": "2.2.0", + "ts-jest": "^29.1.0", + "tsconfig": "0.0.0", + "typescript": "^5.0.4" + }, + "engines": { + "node": ">= 14" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/inherits@2.0.4/node_modules/inherits": { + "version": "2.0.4", + "dev": true, + "license": "ISC", + "devDependencies": { + "tap": "^14.2.4" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/is-buffer@2.0.5/node_modules/is-buffer": { + "version": "2.0.5", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "devDependencies": { + "airtap": "^3.0.0", + "standard": "*", + "tape": "^5.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/jsonwebtoken@9.0.2/node_modules/jsonwebtoken": { + "version": "9.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "devDependencies": { + "atob": "^2.1.2", + "chai": "^4.1.2", + "conventional-changelog": "~1.1.0", + "cost-of-modules": "^1.0.1", + "eslint": "^4.19.1", + "mocha": "^5.2.0", + "nsp": "^2.6.2", + "nyc": "^11.9.0", + "sinon": "^6.0.0" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/jssha@3.3.1/node_modules/jssha": { + "version": "3.3.1", + "dev": true, + "license": "BSD-3-Clause", + "devDependencies": { + "@rollup/plugin-terser": "^0.4.3", + "@rollup/plugin-typescript": "^11.1.2", + "@types/chai": "^4.3.5", + "@types/mocha": "^10.0.1", + "@types/rewire": "^2.5.28", + "@types/sinon": "^10.0.16", + "@typescript-eslint/eslint-plugin": "^6.2.1", + "@typescript-eslint/parser": "^6.2.1", + "chai": "^4.3.7", + "coveralls": "^3.1.1", + "eslint": "^8.46.0", + "husky": "^8.0.3", + "karma": "^6.4.2", + "karma-chai": "^0.1.0", + "karma-chrome-launcher": "^3.2.0", + "karma-firefox-launcher": "^2.1.2", + "karma-mocha": "^2.0.1", + "lint-staged": "^13.2.3", + "mocha": "^10.2.0", + "nyc": "^15.1.0", + "prettier": "^3.0.1", + "rewire": "^6.0.0", + "rollup": "^3.27.2", + "rollup-plugin-dts": "^5.3.1", + "sinon": "^15.2.0", + "ts-node": "^10.9.1", + "tslib": "^2.6.1", + "typescript": "^5.1.6" + }, + "engines": { + "node": "*" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/jwt-decode@4.0.0/node_modules/jwt-decode": { + "version": "4.0.0", + "license": "MIT", + "devDependencies": { + "@babel/core": "7.23.2", + "@typescript-eslint/eslint-plugin": "^6.4.1", + "@typescript-eslint/parser": "^6.4.1", + "browser-sync": "^2.29.3", + "concurrently": "^8.2.0", + "eslint": "^8.48.0", + "eslint-config-prettier": "^9.0.0", + "eslint-import-resolver-typescript": "^3.6.0", + "eslint-plugin-import": "^2.28.1", + "eslint-plugin-prettier": "^5.0.0", + "husky": "^8.0.3", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.6.2", + "lint-staged": "^15.0.2", + "prettier": "^3.0.2", + "publint": "^0.2.2", + "shx": "^0.3.4", + "ts-jest": "^29.1.1", + "ts-node": "^10.9.1", + "typescript": "^5.1.6" + }, + "engines": { + "node": ">=18" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/long@5.3.2/node_modules/long": { + "version": "5.3.2", + "dev": true, + "license": "Apache-2.0", + "devDependencies": { + "esm2umd": "^0.3.1", + "prettier": "^3.5.0", + "typescript": "^5.7.3" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/memfs@4.17.2/node_modules/memfs": { + "version": "4.17.2", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/json-pack": "^1.0.3", + "@jsonjoy.com/util": "^1.3.0", + "tree-dump": "^1.0.1", + "tslib": "^2.0.0" + }, + "devDependencies": { + "@semantic-release/changelog": "^6.0.1", + "@semantic-release/git": "^10.0.1", + "@semantic-release/npm": "^9.0.1", + "@types/jest": "^29.0.0", + "@types/mime": "^3.0.0", + "@types/node": "^10.17.60", + "app-root-path": "^3.1.0", + "assert": "^2.0.0", + "buffer": "^6.0.3", + "html-webpack-plugin": "^5.5.3", + "husky": "^8.0.1", + "isomorphic-git": "^1.24.2", + "jest": "^29.0.0", + "path-browserify": "^1.0.1", + "prettier": "^3.0.0", + "process": "^0.11.10", + "readable-stream": "^4.4.0", + "rimraf": "^5.0.0", + "semantic-release": "^19.0.3", + "tar-stream": "^3.1.2", + "ts-jest": "^29.1.0", + "ts-loader": "^9.4.3", + "ts-node": "^10.9.1", + "tslint": "^6.1.3", + "tslint-config-common": "^1.6.2", + "typescript": "^5.1.3", + "url": "^0.11.1", + "util": "^0.12.5", + "webpack": "^5.87.0", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^4.15.1" + }, + "engines": { + "node": ">= 4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/minimist@1.2.8/node_modules/minimist": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "devDependencies": { + "@ljharb/eslint-config": "^21.0.1", + "aud": "^2.0.2", + "auto-changelog": "^2.4.0", + "eslint": "=8.8.0", + "in-publish": "^2.0.1", + "npmignore": "^0.3.0", + "nyc": "^10.3.2", + "safe-publish-latest": "^2.0.0", + "tape": "^5.6.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/mkdirp@3.0.1/node_modules/mkdirp": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "devDependencies": { + "@types/brace-expansion": "^1.1.0", + "@types/node": "^18.11.9", + "@types/tap": "^15.0.7", + "c8": "^7.12.0", + "eslint-config-prettier": "^8.6.0", + "prettier": "^2.8.2", + "tap": "^16.3.3", + "ts-node": "^10.9.1", + "typedoc": "^0.23.21", + "typescript": "^4.9.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/mockdate@3.0.5/node_modules/mockdate": { + "version": "3.0.5", + "dev": true, + "license": "MIT", + "devDependencies": { + "mocha": "7.1.2", + "rollup": "2.42.4", + "rollup-plugin-typescript2": "0.30.0", + "should": "13.2.3", + "typescript": "3.9.3" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/ms@2.1.3/node_modules/ms": { + "version": "2.1.3", + "dev": true, + "license": "MIT", + "devDependencies": { + "eslint": "4.18.2", + "expect.js": "0.3.1", + "husky": "0.14.3", + "lint-staged": "5.0.0", + "mocha": "4.0.1", + "prettier": "2.0.5" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/nock@14.0.1/node_modules/nock": { + "version": "14.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@mswjs/interceptors": "^0.37.3", + "json-stringify-safe": "^5.0.1", + "propagate": "^2.0.0" + }, + "devDependencies": { + "@definitelytyped/dtslint": "^0.0.163", + "@sinonjs/fake-timers": "^11.2.2", + "assert-rejects": "^1.0.0", + "chai": "^4.1.2", + "dirty-chai": "^2.0.1", + "eslint": "^8.8.0", + "eslint-config-prettier": "^9.0.0", + "eslint-config-standard": "^17.0.0-0", + "eslint-plugin-import": "^2.16.0", + "eslint-plugin-mocha": "^10.0.3", + "eslint-plugin-node": "^11.0.0", + "eslint-plugin-promise": "^6.0.0", + "form-data": "^4.0.0", + "got": "^11.3.0", + "jest": "^29.7.0", + "mocha": "^9.1.3", + "npm-run-all": "^4.1.5", + "nyc": "^15.0.0", + "prettier": "3.2.5", + "proxyquire": "^2.1.0", + "rimraf": "^3.0.0", + "semantic-release": "^24.1.0", + "sinon": "^17.0.1", + "sinon-chai": "^3.7.0", + "typescript": "^5.0.4" + }, + "engines": { + "node": ">=18.20.0 <20 || >=20.12.1" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/open@10.1.2/node_modules/open": { + "version": "10.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" + }, + "devDependencies": { + "@types/node": "^20.10.5", + "ava": "^6.0.1", + "tsd": "^0.30.1", + "xo": "^0.56.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/playwright@1.52.0/node_modules/playwright": { + "version": "1.52.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.52.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/prettier@3.5.3/node_modules/prettier": { + "version": "3.5.3", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/process@0.11.10/node_modules/process": { + "version": "0.11.10", + "dev": true, + "license": "MIT", + "devDependencies": { + "mocha": "2.2.1", + "zuul": "^3.10.3" + }, + "engines": { + "node": ">= 0.6.0" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/rhea-promise@3.0.3/node_modules/rhea-promise": { + "version": "3.0.3", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.0.0", + "rhea": "^3.0.0", + "tslib": "^2.6.0" + }, + "devDependencies": { + "@azure/abort-controller": "^1.0.1", + "@types/chai": "^4.3.7", + "@types/debug": "^4.0.0", + "@types/mocha": "^10.0.0", + "@types/node": "^16.0.0", + "@typescript-eslint/eslint-plugin": "~7.8.0", + "@typescript-eslint/parser": "~7.8.0", + "chai": "^4.3.10", + "dotenv": "^16.0.0", + "eslint": "^8.42.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-jsdoc": "^46.2.6", + "mocha": "^10.0.0", + "rimraf": "^5.0.5", + "ts-node": "^10.0.0", + "typescript": "~5.0.4" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/rhea@3.0.4/node_modules/rhea": { + "version": "3.0.4", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.3.3" + }, + "devDependencies": { + "@types/debug": "^4.1.7", + "@types/mocha": "^9.0.0", + "@types/node": "10 -", + "browserify": "", + "eslint": "^7.32.0", + "minimist": ">=0.2.4", + "mocha": "^9.1.4", + "nyc": "^15.1.0", + "require-self": "^0.2.1", + "ts-node": "^10.4.0", + "typescript": "^4.5.5", + "uglify-js": ">=2.4.24", + "ws": "^6.0.0" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/rimraf@5.0.10/node_modules/rimraf": { + "version": "5.0.10", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "devDependencies": { + "@types/node": "^20.12.11", + "mkdirp": "^3.0.1", + "prettier": "^3.2.5", + "tap": "^19.0.1", + "tshy": "^1.14.0", + "typedoc": "^0.25.13", + "typescript": "^5.4.5" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/semver@7.7.2/node_modules/semver": { + "version": "7.7.2", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "devDependencies": { + "@npmcli/eslint-config": "^5.0.0", + "@npmcli/template-oss": "4.24.3", + "benchmark": "^2.1.4", + "tap": "^16.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/strip-json-comments@5.0.2/node_modules/strip-json-comments": { + "version": "5.0.2", + "dev": true, + "license": "MIT", + "devDependencies": { + "ava": "^4.3.1", + "matcha": "^0.7.0", + "tsd": "^0.22.0", + "xo": "^0.54.2" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tar@7.4.3/node_modules/tar": { + "version": "7.4.3", + "dev": true, + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" + }, + "devDependencies": { + "chmodr": "^1.2.0", + "end-of-stream": "^1.4.3", + "events-to-array": "^2.0.3", + "mutate-fs": "^2.1.1", + "nock": "^13.5.4", + "prettier": "^3.2.5", + "rimraf": "^5.0.5", + "tap": "^18.7.2", + "tshy": "^1.13.1", + "typedoc": "^0.25.13" + }, + "engines": { + "node": ">=18" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/ts-morph@26.0.0/node_modules/ts-morph": { + "version": "26.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@ts-morph/common": "~0.27.0", + "code-block-writer": "^13.0.3" + }, + "devDependencies": { + "@rollup/plugin-typescript": "^12.1.2", + "@types/chai": "^5.2.1", + "@types/diff": "^7.0.2", + "@types/mocha": "^10.0.10", + "@types/node": "^22.14.1", + "chai": "^5.2.0", + "conditional-type-checks": "^1.0.6", + "cross-env": "^7.0.3", + "diff": "^7.0.0", + "mocha": "11.1.0", + "rimraf": "^6.0.1", + "rollup": "=4.40.0", + "standard-version": "^9.5.0", + "ts-node": "10.9.2", + "typescript": "~5.8.3" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tshy@2.0.1/node_modules/tshy": { + "version": "2.0.1", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "chalk": "^5.3.0", + "chokidar": "^3.6.0", + "foreground-child": "^3.1.1", + "minimatch": "^9.0.4", + "mkdirp": "^3.0.1", + "polite-json": "^5.0.0", + "resolve-import": "^1.4.5", + "rimraf": "^5.0.1", + "sync-content": "^1.0.2", + "typescript": "5", + "walk-up-path": "^3.0.1" + }, + "bin": { + "tshy": "dist/esm/index.js" + }, + "devDependencies": { + "@types/node": "^20.12.7", + "prettier": "^3.3.2", + "tap": "^19.2.1", + "typedoc": "^0.26.2" + }, + "engines": { + "node": "16 >=16.17 || 18 >=18.15.0 || >=20.6.1" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib": { + "version": "2.8.1", + "license": "0BSD" + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tsx@4.19.3/node_modules/tsx": { + "version": "4.19.3", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.25.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tsx@4.19.4/node_modules/tsx": { + "version": "4.19.4", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.25.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript-eslint@8.26.1_eslint@9.28.0_typescript@5.8.3/node_modules/typescript-eslint": { + "version": "8.26.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.26.1", + "@typescript-eslint/parser": "8.26.1", + "@typescript-eslint/utils": "8.26.1" + }, + "devDependencies": { + "@jest/types": "29.6.3", + "downlevel-dts": "*", + "jest": "29.7.0", + "prettier": "^3.2.5", + "rimraf": "*", + "typescript": "*" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@4.2.4/node_modules/typescript": { + "version": "4.2.4", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "devDependencies": { + "@octokit/rest": "latest", + "@types/browserify": "latest", + "@types/chai": "latest", + "@types/convert-source-map": "latest", + "@types/glob": "latest", + "@types/gulp": "^4.0.5", + "@types/gulp-concat": "latest", + "@types/gulp-newer": "latest", + "@types/gulp-rename": "0.0.33", + "@types/gulp-sourcemaps": "0.0.32", + "@types/jake": "latest", + "@types/merge2": "latest", + "@types/microsoft__typescript-etw": "latest", + "@types/minimatch": "latest", + "@types/minimist": "latest", + "@types/mkdirp": "latest", + "@types/mocha": "latest", + "@types/ms": "latest", + "@types/node": "latest", + "@types/node-fetch": "^2.3.4", + "@types/q": "latest", + "@types/source-map-support": "latest", + "@types/through2": "latest", + "@types/xml2js": "^0.4.0", + "@typescript-eslint/eslint-plugin": "4.5.0", + "@typescript-eslint/experimental-utils": "4.5.0", + "@typescript-eslint/parser": "4.5.0", + "async": "latest", + "azure-devops-node-api": "^10.1.0", + "browser-resolve": "^1.11.2", + "browserify": "latest", + "chai": "latest", + "chalk": "latest", + "convert-source-map": "latest", + "del": "5.1.0", + "diff": "^4.0.2", + "eslint": "7.12.1", + "eslint-formatter-autolinkable-stylish": "1.1.4", + "eslint-plugin-import": "2.22.1", + "eslint-plugin-jsdoc": "30.7.6", + "eslint-plugin-no-null": "1.0.2", + "fancy-log": "latest", + "fs-extra": "^9.0.0", + "glob": "latest", + "gulp": "^4.0.0", + "gulp-concat": "latest", + "gulp-insert": "latest", + "gulp-newer": "latest", + "gulp-rename": "latest", + "gulp-sourcemaps": "latest", + "istanbul": "latest", + "merge2": "latest", + "minimist": "latest", + "mkdirp": "latest", + "mocha": "latest", + "mocha-fivemat-progress-reporter": "latest", + "ms": "latest", + "node-fetch": "^2.6.0", + "plugin-error": "latest", + "pretty-hrtime": "^1.0.3", + "prex": "^0.4.3", + "q": "latest", + "remove-internal": "^2.9.2", + "source-map-support": "latest", + "through2": "latest", + "typescript": "^4.0.0-dev.20200624", + "vinyl": "latest", + "vinyl-sourcemaps-apply": "latest", + "xml2js": "^0.4.19" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript": { + "version": "5.8.3", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "devDependencies": { + "@dprint/formatter": "^0.4.1", + "@dprint/typescript": "0.93.3", + "@esfx/canceltoken": "^1.0.0", + "@eslint/js": "^9.17.0", + "@octokit/rest": "^21.0.2", + "@types/chai": "^4.3.20", + "@types/diff": "^5.2.3", + "@types/minimist": "^1.2.5", + "@types/mocha": "^10.0.10", + "@types/ms": "^0.7.34", + "@types/node": "latest", + "@types/source-map-support": "^0.5.10", + "@types/which": "^3.0.4", + "@typescript-eslint/rule-tester": "^8.18.1", + "@typescript-eslint/type-utils": "^8.18.1", + "@typescript-eslint/utils": "^8.18.1", + "azure-devops-node-api": "^14.1.0", + "c8": "^10.1.3", + "chai": "^4.5.0", + "chalk": "^4.1.2", + "chokidar": "^3.6.0", + "diff": "^5.2.0", + "dprint": "^0.47.6", + "esbuild": "^0.24.0", + "eslint": "^9.17.0", + "eslint-formatter-autolinkable-stylish": "^1.4.0", + "eslint-plugin-regexp": "^2.7.0", + "fast-xml-parser": "^4.5.1", + "glob": "^10.4.5", + "globals": "^15.13.0", + "hereby": "^1.10.0", + "jsonc-parser": "^3.3.1", + "knip": "^5.41.0", + "minimist": "^1.2.8", + "mocha": "^10.8.2", + "mocha-fivemat-progress-reporter": "^0.1.0", + "monocart-coverage-reports": "^2.11.4", + "ms": "^2.1.3", + "playwright": "^1.49.1", + "source-map-support": "^0.5.21", + "tslib": "^2.8.1", + "typescript": "^5.7.2", + "typescript-eslint": "^8.18.1", + "which": "^3.0.1" + }, + "engines": { + "node": ">=14.17" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/unzipper@0.12.3/node_modules/unzipper": { + "version": "0.12.3", + "dev": true, + "license": "MIT", + "dependencies": { + "bluebird": "~3.7.2", + "duplexer2": "~0.1.4", + "fs-extra": "^11.2.0", + "graceful-fs": "^4.2.2", + "node-int64": "^0.4.0" + }, + "devDependencies": { + "@aws-sdk/client-s3": "^3.0.0", + "@eslint/js": "^9.2.0", + "aws-sdk": "^2.1636.0", + "dirdiff": ">= 0.0.1 < 1", + "eslint": "^9.2.0", + "globals": "^15.2.0", + "iconv-lite": "^0.4.24", + "request": "^2.88.0", + "stream-buffers": ">= 0.2.5 < 1", + "tap": "^16.3.10", + "temp": ">= 0.4.0 < 1" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/util@0.12.5/node_modules/util": { + "version": "0.12.5", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + }, + "devDependencies": { + "airtap": "~1.0.0", + "core-js": "^3.6.5", + "is-async-supported": "~1.2.0", + "object.assign": "~4.1.0", + "object.entries": "^1.1.0", + "run-series": "~1.1.4", + "safe-buffer": "^5.1.2", + "tape": "~4.9.0" + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/vitest@3.2.0_@types+debug@4.1.12_@types+node@18.19.110_@vitest+browser@3.2.0_tsx@4.19.3_yaml@2.8.0/node_modules/vitest": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.0", + "@vitest/mocker": "3.2.0", + "@vitest/pretty-format": "^3.2.0", + "@vitest/runner": "3.2.0", + "@vitest/snapshot": "3.2.0", + "@vitest/spy": "3.2.0", + "@vitest/utils": "3.2.0", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.0", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "devDependencies": { + "@ampproject/remapping": "^2.3.0", + "@antfu/install-pkg": "^1.1.0", + "@edge-runtime/vm": "^5.0.0", + "@sinonjs/fake-timers": "14.0.0", + "@types/debug": "^4.1.12", + "@types/estree": "^1.0.7", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/jsdom": "^21.1.7", + "@types/mime": "^4.0.0", + "@types/node": "^22.15.29", + "@types/picomatch": "^4.0.0", + "@types/prompts": "^2.4.9", + "@types/sinonjs__fake-timers": "^8.1.5", + "acorn-walk": "^8.3.4", + "birpc": "2.3.0", + "cac": "^6.7.14", + "chai-subset": "^1.6.0", + "find-up": "^6.3.0", + "flatted": "^3.3.3", + "happy-dom": "^17.5.6", + "jsdom": "^26.1.0", + "local-pkg": "^1.1.1", + "mime": "^4.0.7", + "pretty-format": "^29.7.0", + "prompts": "^2.4.2", + "strip-literal": "^3.0.0", + "ws": "^8.18.2" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.0", + "@vitest/ui": "3.2.0", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/vitest@3.2.0_@types+debug@4.1.12_@types+node@18.19.110_@vitest+browser@3.2.0_tsx@4.19.4_yaml@2.8.0/node_modules/vitest": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.0", + "@vitest/mocker": "3.2.0", + "@vitest/pretty-format": "^3.2.0", + "@vitest/runner": "3.2.0", + "@vitest/snapshot": "3.2.0", + "@vitest/spy": "3.2.0", + "@vitest/utils": "3.2.0", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.0", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "devDependencies": { + "@ampproject/remapping": "^2.3.0", + "@antfu/install-pkg": "^1.1.0", + "@edge-runtime/vm": "^5.0.0", + "@sinonjs/fake-timers": "14.0.0", + "@types/debug": "^4.1.12", + "@types/estree": "^1.0.7", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/jsdom": "^21.1.7", + "@types/mime": "^4.0.0", + "@types/node": "^22.15.29", + "@types/picomatch": "^4.0.0", + "@types/prompts": "^2.4.9", + "@types/sinonjs__fake-timers": "^8.1.5", + "acorn-walk": "^8.3.4", + "birpc": "2.3.0", + "cac": "^6.7.14", + "chai-subset": "^1.6.0", + "find-up": "^6.3.0", + "flatted": "^3.3.3", + "happy-dom": "^17.5.6", + "jsdom": "^26.1.0", + "local-pkg": "^1.1.1", + "mime": "^4.0.7", + "pretty-format": "^29.7.0", + "prompts": "^2.4.2", + "strip-literal": "^3.0.0", + "ws": "^8.18.2" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.0", + "@vitest/ui": "3.2.0", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/ws@8.18.2/node_modules/ws": { + "version": "8.18.2", + "dev": true, + "license": "MIT", + "devDependencies": { + "benchmark": "^2.1.4", + "bufferutil": "^4.0.1", + "eslint": "^9.0.0", + "eslint-config-prettier": "^10.0.1", + "eslint-plugin-prettier": "^5.0.0", + "globals": "^16.0.0", + "mocha": "^8.4.0", + "nyc": "^15.0.0", + "prettier": "^3.0.0", + "utf-8-validate": "^6.0.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/yaml@2.8.0/node_modules/yaml": { + "version": "2.8.0", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "devDependencies": { + "@babel/core": "^7.12.10", + "@babel/plugin-transform-typescript": "^7.12.17", + "@babel/preset-env": "^7.12.11", + "@eslint/js": "^9.9.1", + "@rollup/plugin-babel": "^6.0.3", + "@rollup/plugin-replace": "^5.0.2", + "@rollup/plugin-typescript": "^12.1.1", + "@types/jest": "^29.2.4", + "@types/node": "^20.11.20", + "babel-jest": "^29.0.1", + "cross-env": "^7.0.3", + "eslint": "^9.9.1", + "eslint-config-prettier": "^9.0.0", + "fast-check": "^2.12.0", + "jest": "^29.0.1", + "jest-ts-webcompat-resolver": "^1.0.0", + "prettier": "^3.0.2", + "rollup": "^4.12.0", + "tslib": "^2.8.1", + "typescript": "^5.7.2", + "typescript-eslint": "^8.4.0" + }, + "engines": { + "node": ">= 14.6" + } + }, + "../../azure-sdk-for-js/common/tools/dev-tool": { + "name": "@azure/dev-tool", + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@_ts/max": "npm:typescript@latest", + "@_ts/min": "npm:typescript@~4.2.4", + "@arethetypeswrong/cli": "^0.17.4", + "@azure/identity": "^4.9.0", + "@microsoft/api-extractor": "^7.52.4", + "@microsoft/api-extractor-model": "^7.30.5", + "chalk": "^4.1.1", + "concurrently": "^8.2.2", + "dotenv": "^16.0.0", + "express": "^5.1.0", + "fs-extra": "^11.2.0", + "memfs": "^4.14.1", + "minimist": "^1.2.8", + "prettier": "^3.3.3", + "semver": "^7.6.0", + "strip-json-comments": "^5.0.1", + "tar": "^7.4.3", + "ts-morph": "^26.0.0", + "tshy": "^2.0.0", + "tslib": "^2.8.1", + "tsx": "4.19.3", + "typescript": "~5.8.2", + "unzipper": "~0.12.3", + "yaml": "^2.3.4" + }, + "bin": { + "dev-tool": "launch.js", + "dtx": "dtx.js" + }, + "devDependencies": { + "@eslint/js": "^9.9.0", + "@types/express": "^5.0.1", + "@types/express-serve-static-core": "^5.0.6", + "@types/fs-extra": "^11.0.4", + "@types/minimist": "^1.2.5", + "@types/node": "^18.0.0", + "@types/semver": "^7.7.0", + "@types/unzipper": "~0.10.11", + "@vitest/coverage-istanbul": "^3.0.9", + "autorest": "^3.7.1", + "builtin-modules": "^3.1.0", + "cross-env": "^7.0.3", + "eslint": "^9.9.0", + "mkdirp": "^3.0.1", + "rimraf": "^5.0.5", + "typescript-eslint": "~8.26.0", + "vitest": "^3.0.9" + } + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/@_ts/max": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/@_ts/min": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@4.2.4/node_modules/typescript", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/@arethetypeswrong/cli": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@arethetypeswrong+cli@0.17.4/node_modules/@arethetypeswrong/cli", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/@azure/identity": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@azure+identity@4.10.0/node_modules/@azure/identity", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/@eslint/js": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@eslint+js@9.28.0/node_modules/@eslint/js", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/@microsoft/api-extractor": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@microsoft+api-extractor@7.52.8_@types+node@18.19.110/node_modules/@microsoft/api-extractor", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/@microsoft/api-extractor-model": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@microsoft+api-extractor-model@7.30.6_@types+node@18.19.110/node_modules/@microsoft/api-extractor-model", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/@types/express": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+express@5.0.2/node_modules/@types/express", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/@types/express-serve-static-core": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+express-serve-static-core@5.0.6/node_modules/@types/express-serve-static-core", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/@types/fs-extra": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+fs-extra@11.0.4/node_modules/@types/fs-extra", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/@types/minimist": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+minimist@1.2.5/node_modules/@types/minimist", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/@types/node": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+node@18.19.110/node_modules/@types/node", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/@types/semver": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+semver@7.7.0/node_modules/@types/semver", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/@types/unzipper": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+unzipper@0.10.11/node_modules/@types/unzipper", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/@vitest/coverage-istanbul": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+coverage-istanbul@3.2.0_vitest@3.2.0/node_modules/@vitest/coverage-istanbul", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/autorest": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/autorest@3.7.2/node_modules/autorest", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/builtin-modules": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/builtin-modules@3.3.0/node_modules/builtin-modules", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/chalk": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/chalk@4.1.2/node_modules/chalk", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/concurrently": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/concurrently@8.2.2/node_modules/concurrently", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/cross-env": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/cross-env@7.0.3/node_modules/cross-env", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/dotenv": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/dotenv@16.5.0/node_modules/dotenv", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint@9.28.0/node_modules/eslint", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/express": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/express@5.1.0/node_modules/express", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/fs-extra": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/fs-extra@11.3.0/node_modules/fs-extra", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/memfs": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/memfs@4.17.2/node_modules/memfs", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/minimist": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/minimist@1.2.8/node_modules/minimist", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/mkdirp": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/mkdirp@3.0.1/node_modules/mkdirp", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/prettier": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/prettier@3.5.3/node_modules/prettier", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/rimraf": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/rimraf@5.0.10/node_modules/rimraf", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/semver": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/semver@7.7.2/node_modules/semver", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/strip-json-comments": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/strip-json-comments@5.0.2/node_modules/strip-json-comments", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/tar": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tar@7.4.3/node_modules/tar", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/ts-morph": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/ts-morph@26.0.0/node_modules/ts-morph", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/tshy": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tshy@2.0.1/node_modules/tshy", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/tslib": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/tsx": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tsx@4.19.3/node_modules/tsx", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/typescript": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/typescript-eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript-eslint@8.26.1_eslint@9.28.0_typescript@5.8.3/node_modules/typescript-eslint", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/unzipper": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/unzipper@0.12.3/node_modules/unzipper", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/vitest": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/vitest@3.2.0_@types+debug@4.1.12_@types+node@18.19.110_@vitest+browser@3.2.0_tsx@4.19.3_yaml@2.8.0/node_modules/vitest", + "link": true + }, + "../../azure-sdk-for-js/common/tools/dev-tool/node_modules/yaml": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/yaml@2.8.0/node_modules/yaml", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk": { + "name": "@azure/eslint-plugin-azure-sdk", + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint/compat": "^1.2.4", + "@eslint/js": "^9.9.0", + "@types/eslint": "^9.6.0", + "@types/estree": "~1.0.0", + "@typescript-eslint/typescript-estree": "~8.26.0", + "eslint-config-prettier": "^10.0.1", + "glob": "^10.3.10", + "tslib": "^2.6.2", + "typescript": "~5.8.2", + "typescript-eslint": "~8.26.0" + }, + "devDependencies": { + "@types/eslint": "^9.6.0", + "@types/eslint-config-prettier": "6.11.3", + "@types/node": "^18.0.0", + "@typescript-eslint/eslint-plugin": "~8.26.0", + "@typescript-eslint/parser": "~8.26.0", + "@typescript-eslint/rule-tester": "~8.26.0", + "@typescript-eslint/utils": "~8.26.0", + "@vitest/browser": "^3.0.9", + "@vitest/coverage-istanbul": "^3.0.9", + "eslint": "^9.9.0", + "playwright": "^1.49.1", + "prettier": "^3.3.3", + "rimraf": "^5.0.5", + "tshy": "^2.0.0", + "vitest": "^3.0.9" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@eslint/eslintrc": "^3.2.0", + "@typescript-eslint/eslint-plugin": "~8.26.0", + "@typescript-eslint/parser": "~8.26.0", + "eslint": "^9.9.0", + "eslint-plugin-n": "^17.15.0", + "eslint-plugin-no-only-tests": "^3.3.0", + "eslint-plugin-promise": "^7.2.1", + "eslint-plugin-tsdoc": "^0.4.0" + } + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/@eslint/compat": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@eslint+compat@1.2.9_eslint@9.28.0/node_modules/@eslint/compat", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/@eslint/eslintrc": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@eslint+eslintrc@3.3.1/node_modules/@eslint/eslintrc", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/@eslint/js": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@eslint+js@9.28.0/node_modules/@eslint/js", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/@types/eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+eslint@9.6.1/node_modules/@types/eslint", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/@types/eslint-config-prettier": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+eslint-config-prettier@6.11.3/node_modules/@types/eslint-config-prettier", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/@types/estree": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+estree@1.0.7/node_modules/@types/estree", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/@types/node": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+node@18.19.110/node_modules/@types/node", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/@typescript-eslint/eslint-plugin": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@typescript-eslint+eslint-plugin@8.26.1_@typescript-eslint+parser@8.26.1_eslint@9.28.0_typesc_cpt2wfi56j2kmlqfdpy32xzd7a/node_modules/@typescript-eslint/eslint-plugin", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/@typescript-eslint/parser": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@typescript-eslint+parser@8.26.1_eslint@9.28.0_typescript@5.8.3/node_modules/@typescript-eslint/parser", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/@typescript-eslint/rule-tester": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@typescript-eslint+rule-tester@8.26.1_eslint@9.28.0_typescript@5.8.3/node_modules/@typescript-eslint/rule-tester", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/@typescript-eslint/typescript-estree": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@typescript-eslint+typescript-estree@8.26.1_typescript@5.8.3/node_modules/@typescript-eslint/typescript-estree", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/@typescript-eslint/utils": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@typescript-eslint+utils@8.26.1_eslint@9.28.0_typescript@5.8.3/node_modules/@typescript-eslint/utils", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/@vitest/browser": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+browser@3.2.0_playwright@1.52.0_vite@6.3.5_@types+node@22.7.9_tsx@4.19.4_yaml@2.8.0__vitest@3.2.0/node_modules/@vitest/browser", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/@vitest/coverage-istanbul": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+coverage-istanbul@3.2.0_vitest@3.2.0/node_modules/@vitest/coverage-istanbul", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint@9.28.0/node_modules/eslint", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/eslint-config-prettier": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint-config-prettier@10.1.5_eslint@9.28.0/node_modules/eslint-config-prettier", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/eslint-plugin-n": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint-plugin-n@17.19.0_eslint@9.28.0_typescript@5.8.3/node_modules/eslint-plugin-n", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/eslint-plugin-no-only-tests": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint-plugin-no-only-tests@3.3.0/node_modules/eslint-plugin-no-only-tests", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/eslint-plugin-promise": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint-plugin-promise@7.2.1_eslint@9.28.0/node_modules/eslint-plugin-promise", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/eslint-plugin-tsdoc": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint-plugin-tsdoc@0.4.0/node_modules/eslint-plugin-tsdoc", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/glob": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/glob@10.4.5/node_modules/glob", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/playwright": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/playwright@1.52.0/node_modules/playwright", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/prettier": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/prettier@3.5.3/node_modules/prettier", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/rimraf": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/rimraf@5.0.10/node_modules/rimraf", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/tshy": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tshy@2.0.1/node_modules/tshy", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/tslib": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/typescript": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/typescript-eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript-eslint@8.26.1_eslint@9.28.0_typescript@5.8.3/node_modules/typescript-eslint", + "link": true + }, + "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk/node_modules/vitest": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/vitest@3.2.0_@types+debug@4.1.12_@types+node@18.19.110_@vitest+browser@3.2.0_tsx@4.19.4_yaml@2.8.0/node_modules/vitest", + "link": true + }, + "../../azure-sdk-for-js/common/tools/vite-plugin-browser-test-map": { + "name": "@azure-tools/vite-plugin-browser-test-map", + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.2.0" + }, + "devDependencies": { + "@eslint/js": "^9.9.0", + "@types/node": "^18.0.0", + "eslint": "^9.9.0", + "prettier": "^3.3.3", + "rimraf": "^5.0.0", + "typescript": "~5.8.2", + "typescript-eslint": "~8.26.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../azure-sdk-for-js/common/tools/vite-plugin-browser-test-map/node_modules/@eslint/js": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@eslint+js@9.28.0/node_modules/@eslint/js", + "link": true + }, + "../../azure-sdk-for-js/common/tools/vite-plugin-browser-test-map/node_modules/@types/node": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+node@18.19.110/node_modules/@types/node", + "link": true + }, + "../../azure-sdk-for-js/common/tools/vite-plugin-browser-test-map/node_modules/eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint@9.28.0/node_modules/eslint", + "link": true + }, + "../../azure-sdk-for-js/common/tools/vite-plugin-browser-test-map/node_modules/prettier": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/prettier@3.5.3/node_modules/prettier", + "link": true + }, + "../../azure-sdk-for-js/common/tools/vite-plugin-browser-test-map/node_modules/rimraf": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/rimraf@5.0.10/node_modules/rimraf", + "link": true + }, + "../../azure-sdk-for-js/common/tools/vite-plugin-browser-test-map/node_modules/tslib": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib", + "link": true + }, + "../../azure-sdk-for-js/common/tools/vite-plugin-browser-test-map/node_modules/typescript": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript", + "link": true + }, + "../../azure-sdk-for-js/common/tools/vite-plugin-browser-test-map/node_modules/typescript-eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript-eslint@8.26.1_eslint@9.28.0_typescript@5.8.3/node_modules/typescript-eslint", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation": { + "name": "@azure/communication-call-automation", + "version": "1.5.0-beta.1", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/communication-common": "^2.3.1", + "@azure/core-auth": "^1.9.0", + "@azure/core-client": "^1.9.2", + "@azure/core-paging": "^1.6.2", + "@azure/core-rest-pipeline": "^1.17.0", + "@azure/core-tracing": "^1.2.0", + "@azure/core-util": "^1.11.0", + "@azure/logger": "^1.1.4", + "events": "^3.0.0", + "tslib": "^2.8.1" + }, + "devDependencies": { + "@azure-tools/test-credential": "^2.0.0", + "@azure-tools/test-recorder": "^4.1.0", + "@azure-tools/test-utils-vitest": "^1.0.0", + "@azure-tools/vite-plugin-browser-test-map": "^1.0.0", + "@azure/communication-identity": "^1.2.0", + "@azure/communication-phone-numbers": "^1.2.0", + "@azure/dev-tool": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@azure/identity": "^4.5.0", + "@azure/service-bus": "^7.9.5", + "@types/node": "^18.0.0", + "@vitest/browser": "^3.0.9", + "@vitest/coverage-istanbul": "^3.0.9", + "dotenv": "^16.0.0", + "eslint": "^9.9.0", + "inherits": "^2.0.3", + "playwright": "^1.48.2", + "typescript": "~5.8.2", + "vitest": "^3.0.9" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/@azure-tools/test-credential": { + "resolved": "../../azure-sdk-for-js/sdk/test-utils/test-credential", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/@azure-tools/test-recorder": { + "resolved": "../../azure-sdk-for-js/sdk/test-utils/recorder", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/@azure-tools/test-utils-vitest": { + "resolved": "../../azure-sdk-for-js/sdk/test-utils/test-utils-vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/@azure-tools/vite-plugin-browser-test-map": { + "resolved": "../../azure-sdk-for-js/common/tools/vite-plugin-browser-test-map", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/@azure/abort-controller": { + "resolved": "../../azure-sdk-for-js/sdk/core/abort-controller", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/@azure/communication-common": { + "resolved": "../../azure-sdk-for-js/sdk/communication/communication-common", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/@azure/communication-identity": { + "resolved": "../../azure-sdk-for-js/sdk/communication/communication-identity", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/@azure/communication-phone-numbers": { + "resolved": "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/@azure/core-auth": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-auth", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/@azure/core-client": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-client", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/@azure/core-paging": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-paging", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/@azure/core-rest-pipeline": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-rest-pipeline", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/@azure/core-tracing": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-tracing", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/@azure/core-util": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-util", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/@azure/dev-tool": { + "resolved": "../../azure-sdk-for-js/common/tools/dev-tool", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/@azure/eslint-plugin-azure-sdk": { + "resolved": "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/@azure/identity": { + "resolved": "../../azure-sdk-for-js/sdk/identity/identity", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/@azure/logger": { + "resolved": "../../azure-sdk-for-js/sdk/core/logger", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/@azure/service-bus": { + "resolved": "../../azure-sdk-for-js/sdk/servicebus/service-bus", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/@types/node": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+node@18.19.110/node_modules/@types/node", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/@vitest/browser": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+browser@3.2.0_playwright@1.52.0_vite@6.3.5_@types+node@22.7.9_tsx@4.19.4_yaml@2.8.0__vitest@3.2.0/node_modules/@vitest/browser", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/@vitest/coverage-istanbul": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+coverage-istanbul@3.2.0_vitest@3.2.0/node_modules/@vitest/coverage-istanbul", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/dotenv": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/dotenv@16.5.0/node_modules/dotenv", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint@9.28.0/node_modules/eslint", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/events": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/events@3.3.0/node_modules/events", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/inherits": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/inherits@2.0.4/node_modules/inherits", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/playwright": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/playwright@1.52.0/node_modules/playwright", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/tslib": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/typescript": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-call-automation/node_modules/vitest": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/vitest@3.2.0_@types+debug@4.1.12_@types+node@18.19.110_@vitest+browser@3.2.0_tsx@4.19.4_yaml@2.8.0/node_modules/vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-common": { + "name": "@azure/communication-common", + "version": "2.4.1", + "license": "MIT", + "dependencies": { + "@azure-rest/core-client": "^2.3.3", + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.9.0", + "@azure/core-rest-pipeline": "^1.17.0", + "@azure/core-tracing": "^1.2.0", + "@azure/core-util": "^1.11.0", + "events": "^3.3.0", + "jwt-decode": "^4.0.0", + "tslib": "^2.8.1" + }, + "devDependencies": { + "@azure-tools/test-utils-vitest": "^1.0.0", + "@azure/dev-tool": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@azure/identity": "~4.3.0", + "@azure/logger": "^1.1.4", + "@types/node": "^18.0.0", + "@vitest/browser": "^3.0.9", + "@vitest/coverage-istanbul": "^3.0.9", + "eslint": "^9.9.0", + "mockdate": "^3.0.5", + "nock": "14.0.1", + "playwright": "^1.48.0", + "typescript": "~5.8.2", + "vitest": "^3.0.9" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../azure-sdk-for-js/sdk/communication/communication-common/node_modules/@azure-rest/core-client": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-client-rest", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-common/node_modules/@azure-tools/test-utils-vitest": { + "resolved": "../../azure-sdk-for-js/sdk/test-utils/test-utils-vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-common/node_modules/@azure/abort-controller": { + "resolved": "../../azure-sdk-for-js/sdk/core/abort-controller", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-common/node_modules/@azure/core-auth": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-auth", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-common/node_modules/@azure/core-rest-pipeline": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-rest-pipeline", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-common/node_modules/@azure/core-tracing": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-tracing", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-common/node_modules/@azure/core-util": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-util", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-common/node_modules/@azure/dev-tool": { + "resolved": "../../azure-sdk-for-js/common/tools/dev-tool", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-common/node_modules/@azure/eslint-plugin-azure-sdk": { + "resolved": "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-common/node_modules/@azure/identity": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@azure+identity@4.3.0/node_modules/@azure/identity", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-common/node_modules/@azure/logger": { + "resolved": "../../azure-sdk-for-js/sdk/core/logger", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-common/node_modules/@types/node": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+node@18.19.110/node_modules/@types/node", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-common/node_modules/@vitest/browser": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+browser@3.2.0_playwright@1.52.0_vite@6.3.5_@types+node@22.7.9_tsx@4.19.4_yaml@2.8.0__vitest@3.2.0/node_modules/@vitest/browser", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-common/node_modules/@vitest/coverage-istanbul": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+coverage-istanbul@3.2.0_vitest@3.2.0/node_modules/@vitest/coverage-istanbul", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-common/node_modules/eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint@9.28.0/node_modules/eslint", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-common/node_modules/events": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/events@3.3.0/node_modules/events", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-common/node_modules/jwt-decode": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/jwt-decode@4.0.0/node_modules/jwt-decode", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-common/node_modules/mockdate": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/mockdate@3.0.5/node_modules/mockdate", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-common/node_modules/nock": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/nock@14.0.1/node_modules/nock", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-common/node_modules/playwright": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/playwright@1.52.0/node_modules/playwright", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-common/node_modules/tslib": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-common/node_modules/typescript": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-common/node_modules/vitest": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/vitest@3.2.0_@types+debug@4.1.12_@types+node@18.19.110_@vitest+browser@3.2.0_tsx@4.19.4_yaml@2.8.0/node_modules/vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity": { + "name": "@azure/communication-identity", + "version": "1.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/communication-common": "^2.3.1", + "@azure/core-auth": "^1.9.0", + "@azure/core-client": "^1.9.2", + "@azure/core-lro": "^2.7.2", + "@azure/core-paging": "^1.6.2", + "@azure/core-rest-pipeline": "^1.18.2", + "@azure/core-tracing": "^1.2.0", + "@azure/logger": "^1.1.4", + "events": "^3.3.0", + "tslib": "^2.8.1" + }, + "devDependencies": { + "@azure-tools/test-credential": "^2.0.0", + "@azure-tools/test-recorder": "^4.1.0", + "@azure-tools/test-utils-vitest": "^1.0.0", + "@azure/core-util": "^1.6.1", + "@azure/dev-tool": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@azure/identity": "^4.5.0", + "@azure/msal-node": "^2.16.1", + "@types/node": "^18.0.0", + "@vitest/browser": "^3.0.9", + "@vitest/coverage-istanbul": "^3.0.9", + "dotenv": "^16.0.0", + "eslint": "^9.9.0", + "playwright": "^1.48.2", + "typescript": "~5.8.2", + "vitest": "^3.0.9" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/@azure-tools/test-credential": { + "resolved": "../../azure-sdk-for-js/sdk/test-utils/test-credential", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/@azure-tools/test-recorder": { + "resolved": "../../azure-sdk-for-js/sdk/test-utils/recorder", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/@azure-tools/test-utils-vitest": { + "resolved": "../../azure-sdk-for-js/sdk/test-utils/test-utils-vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/@azure/abort-controller": { + "resolved": "../../azure-sdk-for-js/sdk/core/abort-controller", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/@azure/communication-common": { + "resolved": "../../azure-sdk-for-js/sdk/communication/communication-common", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/@azure/core-auth": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-auth", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/@azure/core-client": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-client", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/@azure/core-lro": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@azure+core-lro@2.7.2/node_modules/@azure/core-lro", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/@azure/core-paging": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-paging", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/@azure/core-rest-pipeline": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-rest-pipeline", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/@azure/core-tracing": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-tracing", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/@azure/core-util": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-util", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/@azure/dev-tool": { + "resolved": "../../azure-sdk-for-js/common/tools/dev-tool", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/@azure/eslint-plugin-azure-sdk": { + "resolved": "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/@azure/identity": { + "resolved": "../../azure-sdk-for-js/sdk/identity/identity", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/@azure/logger": { + "resolved": "../../azure-sdk-for-js/sdk/core/logger", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/@azure/msal-node": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@azure+msal-node@2.16.2/node_modules/@azure/msal-node", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/@types/node": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+node@18.19.110/node_modules/@types/node", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/@vitest/browser": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+browser@3.2.0_playwright@1.52.0_vite@6.3.5_@types+node@22.7.9_tsx@4.19.4_yaml@2.8.0__vitest@3.2.0/node_modules/@vitest/browser", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/@vitest/coverage-istanbul": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+coverage-istanbul@3.2.0_vitest@3.2.0/node_modules/@vitest/coverage-istanbul", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/dotenv": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/dotenv@16.5.0/node_modules/dotenv", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint@9.28.0/node_modules/eslint", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/events": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/events@3.3.0/node_modules/events", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/playwright": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/playwright@1.52.0/node_modules/playwright", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/tslib": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/typescript": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-identity/node_modules/vitest": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/vitest@3.2.0_@types+debug@4.1.12_@types+node@18.19.110_@vitest+browser@3.2.0_tsx@4.19.4_yaml@2.8.0/node_modules/vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers": { + "name": "@azure/communication-phone-numbers", + "version": "1.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/communication-common": "^2.3.1", + "@azure/core-auth": "^1.9.0", + "@azure/core-client": "^1.9.2", + "@azure/core-lro": "^2.7.2", + "@azure/core-paging": "^1.6.2", + "@azure/core-rest-pipeline": "^1.18.2", + "@azure/core-tracing": "^1.2.0", + "@azure/core-util": "^1.11.0", + "@azure/logger": "^1.1.4", + "events": "^3.3.0", + "tslib": "^2.8.1" + }, + "devDependencies": { + "@azure-tools/test-credential": "^2.0.0", + "@azure-tools/test-recorder": "^4.1.0", + "@azure-tools/test-utils-vitest": "^1.0.0", + "@azure/dev-tool": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@azure/identity": "^4.5.0", + "@types/node": "^18.0.0", + "@vitest/browser": "^3.0.9", + "@vitest/coverage-istanbul": "^3.0.9", + "dotenv": "^16.0.0", + "eslint": "^9.9.0", + "playwright": "^1.48.2", + "typescript": "~5.8.2", + "vitest": "^3.0.9" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers/node_modules/@azure-tools/test-credential": { + "resolved": "../../azure-sdk-for-js/sdk/test-utils/test-credential", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers/node_modules/@azure-tools/test-recorder": { + "resolved": "../../azure-sdk-for-js/sdk/test-utils/recorder", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers/node_modules/@azure-tools/test-utils-vitest": { + "resolved": "../../azure-sdk-for-js/sdk/test-utils/test-utils-vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers/node_modules/@azure/abort-controller": { + "resolved": "../../azure-sdk-for-js/sdk/core/abort-controller", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers/node_modules/@azure/communication-common": { + "resolved": "../../azure-sdk-for-js/sdk/communication/communication-common", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers/node_modules/@azure/core-auth": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-auth", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers/node_modules/@azure/core-client": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-client", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers/node_modules/@azure/core-lro": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@azure+core-lro@2.7.2/node_modules/@azure/core-lro", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers/node_modules/@azure/core-paging": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-paging", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers/node_modules/@azure/core-rest-pipeline": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-rest-pipeline", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers/node_modules/@azure/core-tracing": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-tracing", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers/node_modules/@azure/core-util": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-util", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers/node_modules/@azure/dev-tool": { + "resolved": "../../azure-sdk-for-js/common/tools/dev-tool", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers/node_modules/@azure/eslint-plugin-azure-sdk": { + "resolved": "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers/node_modules/@azure/identity": { + "resolved": "../../azure-sdk-for-js/sdk/identity/identity", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers/node_modules/@azure/logger": { + "resolved": "../../azure-sdk-for-js/sdk/core/logger", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers/node_modules/@types/node": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+node@18.19.110/node_modules/@types/node", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers/node_modules/@vitest/browser": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+browser@3.2.0_playwright@1.52.0_vite@6.3.5_@types+node@22.7.9_tsx@4.19.4_yaml@2.8.0__vitest@3.2.0/node_modules/@vitest/browser", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers/node_modules/@vitest/coverage-istanbul": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+coverage-istanbul@3.2.0_vitest@3.2.0/node_modules/@vitest/coverage-istanbul", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers/node_modules/dotenv": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/dotenv@16.5.0/node_modules/dotenv", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers/node_modules/eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint@9.28.0/node_modules/eslint", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers/node_modules/events": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/events@3.3.0/node_modules/events", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers/node_modules/playwright": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/playwright@1.52.0/node_modules/playwright", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers/node_modules/tslib": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers/node_modules/typescript": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript", + "link": true + }, + "../../azure-sdk-for-js/sdk/communication/communication-phone-numbers/node_modules/vitest": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/vitest@3.2.0_@types+debug@4.1.12_@types+node@18.19.110_@vitest+browser@3.2.0_tsx@4.19.4_yaml@2.8.0/node_modules/vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/abort-controller": { + "name": "@azure/abort-controller", + "version": "2.1.3", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "devDependencies": { + "@azure/dev-tool": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@types/node": "^18.0.0", + "@vitest/browser": "^3.0.9", + "@vitest/coverage-istanbul": "^3.0.9", + "eslint": "^9.9.0", + "playwright": "^1.41.2", + "typescript": "~5.8.2", + "vitest": "^3.0.9" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../azure-sdk-for-js/sdk/core/abort-controller/node_modules/@azure/dev-tool": { + "resolved": "../../azure-sdk-for-js/common/tools/dev-tool", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/abort-controller/node_modules/@azure/eslint-plugin-azure-sdk": { + "resolved": "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/abort-controller/node_modules/@types/node": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+node@18.19.110/node_modules/@types/node", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/abort-controller/node_modules/@vitest/browser": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+browser@3.2.0_playwright@1.52.0_vite@6.3.5_@types+node@22.7.9_tsx@4.19.4_yaml@2.8.0__vitest@3.2.0/node_modules/@vitest/browser", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/abort-controller/node_modules/@vitest/coverage-istanbul": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+coverage-istanbul@3.2.0_vitest@3.2.0/node_modules/@vitest/coverage-istanbul", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/abort-controller/node_modules/eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint@9.28.0/node_modules/eslint", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/abort-controller/node_modules/playwright": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/playwright@1.52.0/node_modules/playwright", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/abort-controller/node_modules/tslib": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/abort-controller/node_modules/typescript": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/abort-controller/node_modules/vitest": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/vitest@3.2.0_@types+debug@4.1.12_@types+node@18.19.110_@vitest+browser@3.2.0_tsx@4.19.4_yaml@2.8.0/node_modules/vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-amqp": { + "name": "@azure/core-amqp", + "version": "4.3.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.7.2", + "@azure/core-util": "^1.9.0", + "@azure/logger": "^1.1.2", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "rhea": "^3.0.0", + "rhea-promise": "^3.0.0", + "tslib": "^2.6.2", + "util": "^0.12.5" + }, + "devDependencies": { + "@azure-tools/vite-plugin-browser-test-map": "^1.0.0", + "@azure/dev-tool": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@rollup/plugin-inject": "^5.0.5", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0", + "@types/ws": "^8.5.10", + "@vitest/browser": "^3.0.9", + "@vitest/coverage-istanbul": "^3.0.9", + "debug": "^4.3.4", + "eslint": "^9.9.0", + "playwright": "^1.43.1", + "typescript": "~5.8.2", + "vitest": "^3.0.9", + "ws": "^8.17.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../azure-sdk-for-js/sdk/core/core-amqp/node_modules/@azure-tools/vite-plugin-browser-test-map": { + "resolved": "../../azure-sdk-for-js/common/tools/vite-plugin-browser-test-map", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-amqp/node_modules/@azure/abort-controller": { + "resolved": "../../azure-sdk-for-js/sdk/core/abort-controller", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-amqp/node_modules/@azure/core-auth": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-auth", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-amqp/node_modules/@azure/core-util": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-util", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-amqp/node_modules/@azure/dev-tool": { + "resolved": "../../azure-sdk-for-js/common/tools/dev-tool", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-amqp/node_modules/@azure/eslint-plugin-azure-sdk": { + "resolved": "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-amqp/node_modules/@azure/logger": { + "resolved": "../../azure-sdk-for-js/sdk/core/logger", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-amqp/node_modules/@rollup/plugin-inject": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@rollup+plugin-inject@5.0.5_rollup@4.41.1/node_modules/@rollup/plugin-inject", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-amqp/node_modules/@types/debug": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+debug@4.1.12/node_modules/@types/debug", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-amqp/node_modules/@types/node": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+node@18.19.110/node_modules/@types/node", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-amqp/node_modules/@types/ws": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+ws@8.18.1/node_modules/@types/ws", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-amqp/node_modules/@vitest/browser": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+browser@3.2.0_playwright@1.52.0_vite@6.3.5_@types+node@22.7.9_tsx@4.19.4_yaml@2.8.0__vitest@3.2.0/node_modules/@vitest/browser", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-amqp/node_modules/@vitest/coverage-istanbul": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+coverage-istanbul@3.2.0_vitest@3.2.0/node_modules/@vitest/coverage-istanbul", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-amqp/node_modules/buffer": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/buffer@6.0.3/node_modules/buffer", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-amqp/node_modules/debug": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/debug@4.4.1/node_modules/debug", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-amqp/node_modules/eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint@9.28.0/node_modules/eslint", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-amqp/node_modules/events": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/events@3.3.0/node_modules/events", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-amqp/node_modules/playwright": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/playwright@1.52.0/node_modules/playwright", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-amqp/node_modules/process": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/process@0.11.10/node_modules/process", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-amqp/node_modules/rhea": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/rhea@3.0.4/node_modules/rhea", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-amqp/node_modules/rhea-promise": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/rhea-promise@3.0.3/node_modules/rhea-promise", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-amqp/node_modules/tslib": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-amqp/node_modules/typescript": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-amqp/node_modules/util": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/util@0.12.5/node_modules/util", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-amqp/node_modules/vitest": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/vitest@3.2.0_@types+debug@4.1.12_@types+node@18.19.110_@vitest+browser@3.2.0_tsx@4.19.4_yaml@2.8.0/node_modules/vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-amqp/node_modules/ws": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/ws@8.18.2/node_modules/ws", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-auth": { + "name": "@azure/core-auth", + "version": "1.9.1", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-util": "^1.11.0", + "tslib": "^2.6.2" + }, + "devDependencies": { + "@azure/dev-tool": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@types/node": "^18.0.0", + "@vitest/browser": "^3.0.9", + "@vitest/coverage-istanbul": "^3.0.9", + "eslint": "^9.9.0", + "playwright": "^1.41.2", + "typescript": "~5.8.2", + "vitest": "^3.0.9" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../azure-sdk-for-js/sdk/core/core-auth/node_modules/@azure/abort-controller": { + "resolved": "../../azure-sdk-for-js/sdk/core/abort-controller", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-auth/node_modules/@azure/core-util": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-util", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-auth/node_modules/@azure/dev-tool": { + "resolved": "../../azure-sdk-for-js/common/tools/dev-tool", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-auth/node_modules/@azure/eslint-plugin-azure-sdk": { + "resolved": "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-auth/node_modules/@types/node": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+node@18.19.110/node_modules/@types/node", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-auth/node_modules/@vitest/browser": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+browser@3.2.0_playwright@1.52.0_vite@6.3.5_@types+node@22.7.9_tsx@4.19.4_yaml@2.8.0__vitest@3.2.0/node_modules/@vitest/browser", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-auth/node_modules/@vitest/coverage-istanbul": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+coverage-istanbul@3.2.0_vitest@3.2.0/node_modules/@vitest/coverage-istanbul", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-auth/node_modules/eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint@9.28.0/node_modules/eslint", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-auth/node_modules/playwright": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/playwright@1.52.0/node_modules/playwright", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-auth/node_modules/tslib": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-auth/node_modules/typescript": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-auth/node_modules/vitest": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/vitest@3.2.0_@types+debug@4.1.12_@types+node@18.19.110_@vitest+browser@3.2.0_tsx@4.19.4_yaml@2.8.0/node_modules/vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client": { + "name": "@azure/core-client", + "version": "1.9.5", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.4.0", + "@azure/core-rest-pipeline": "^1.20.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.6.1", + "@azure/logger": "^1.0.0", + "tslib": "^2.6.2" + }, + "devDependencies": { + "@azure/core-xml": "^1.3.4", + "@azure/dev-tool": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@types/node": "^18.0.0", + "@vitest/browser": "^3.0.9", + "@vitest/coverage-istanbul": "^3.0.9", + "eslint": "^9.9.0", + "playwright": "^1.41.2", + "typescript": "~5.8.2", + "vitest": "^3.0.9" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../azure-sdk-for-js/sdk/core/core-client-rest": { + "name": "@azure-rest/core-client", + "version": "2.4.1", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.3.0", + "@azure/core-rest-pipeline": "^1.5.0", + "@azure/core-tracing": "^1.0.1", + "@typespec/ts-http-runtime": "^0.2.2", + "tslib": "^2.6.2" + }, + "devDependencies": { + "@azure/dev-tool": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@types/node": "^18.0.0", + "@vitest/browser": "^3.0.9", + "@vitest/coverage-istanbul": "^3.0.9", + "eslint": "^9.9.0", + "playwright": "^1.41.2", + "typescript": "~5.8.2", + "vitest": "^3.0.9" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../azure-sdk-for-js/sdk/core/core-client-rest/node_modules/@azure/abort-controller": { + "resolved": "../../azure-sdk-for-js/sdk/core/abort-controller", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client-rest/node_modules/@azure/core-auth": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-auth", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client-rest/node_modules/@azure/core-rest-pipeline": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-rest-pipeline", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client-rest/node_modules/@azure/core-tracing": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-tracing", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client-rest/node_modules/@azure/dev-tool": { + "resolved": "../../azure-sdk-for-js/common/tools/dev-tool", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client-rest/node_modules/@azure/eslint-plugin-azure-sdk": { + "resolved": "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client-rest/node_modules/@types/node": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+node@18.19.110/node_modules/@types/node", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client-rest/node_modules/@typespec/ts-http-runtime": { + "resolved": "../../azure-sdk-for-js/sdk/core/ts-http-runtime", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client-rest/node_modules/@vitest/browser": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+browser@3.2.0_playwright@1.52.0_vite@6.3.5_@types+node@22.7.9_tsx@4.19.4_yaml@2.8.0__vitest@3.2.0/node_modules/@vitest/browser", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client-rest/node_modules/@vitest/coverage-istanbul": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+coverage-istanbul@3.2.0_vitest@3.2.0/node_modules/@vitest/coverage-istanbul", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client-rest/node_modules/eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint@9.28.0/node_modules/eslint", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client-rest/node_modules/playwright": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/playwright@1.52.0/node_modules/playwright", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client-rest/node_modules/tslib": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client-rest/node_modules/typescript": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client-rest/node_modules/vitest": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/vitest@3.2.0_@types+debug@4.1.12_@types+node@18.19.110_@vitest+browser@3.2.0_tsx@4.19.4_yaml@2.8.0/node_modules/vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client/node_modules/@azure/abort-controller": { + "resolved": "../../azure-sdk-for-js/sdk/core/abort-controller", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client/node_modules/@azure/core-auth": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-auth", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client/node_modules/@azure/core-rest-pipeline": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-rest-pipeline", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client/node_modules/@azure/core-tracing": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-tracing", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client/node_modules/@azure/core-util": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-util", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client/node_modules/@azure/core-xml": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-xml", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client/node_modules/@azure/dev-tool": { + "resolved": "../../azure-sdk-for-js/common/tools/dev-tool", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client/node_modules/@azure/eslint-plugin-azure-sdk": { + "resolved": "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client/node_modules/@azure/logger": { + "resolved": "../../azure-sdk-for-js/sdk/core/logger", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client/node_modules/@types/node": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+node@18.19.110/node_modules/@types/node", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client/node_modules/@vitest/browser": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+browser@3.2.0_playwright@1.52.0_vite@6.3.5_@types+node@22.7.9_tsx@4.19.4_yaml@2.8.0__vitest@3.2.0/node_modules/@vitest/browser", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client/node_modules/@vitest/coverage-istanbul": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+coverage-istanbul@3.2.0_vitest@3.2.0/node_modules/@vitest/coverage-istanbul", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client/node_modules/eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint@9.28.0/node_modules/eslint", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client/node_modules/playwright": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/playwright@1.52.0/node_modules/playwright", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client/node_modules/tslib": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client/node_modules/typescript": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-client/node_modules/vitest": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/vitest@3.2.0_@types+debug@4.1.12_@types+node@18.19.110_@vitest+browser@3.2.0_tsx@4.19.4_yaml@2.8.0/node_modules/vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-paging": { + "name": "@azure/core-paging", + "version": "1.6.3", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "devDependencies": { + "@azure/dev-tool": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@types/node": "^18.0.0", + "@vitest/browser": "^3.0.9", + "@vitest/coverage-istanbul": "^3.0.9", + "eslint": "^9.9.0", + "playwright": "^1.41.2", + "typescript": "~5.8.2", + "vitest": "^3.0.9" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../azure-sdk-for-js/sdk/core/core-paging/node_modules/@azure/dev-tool": { + "resolved": "../../azure-sdk-for-js/common/tools/dev-tool", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-paging/node_modules/@azure/eslint-plugin-azure-sdk": { + "resolved": "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-paging/node_modules/@types/node": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+node@18.19.110/node_modules/@types/node", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-paging/node_modules/@vitest/browser": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+browser@3.2.0_playwright@1.52.0_vite@6.3.5_@types+node@22.7.9_tsx@4.19.4_yaml@2.8.0__vitest@3.2.0/node_modules/@vitest/browser", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-paging/node_modules/@vitest/coverage-istanbul": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+coverage-istanbul@3.2.0_vitest@3.2.0/node_modules/@vitest/coverage-istanbul", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-paging/node_modules/eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint@9.28.0/node_modules/eslint", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-paging/node_modules/playwright": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/playwright@1.52.0/node_modules/playwright", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-paging/node_modules/tslib": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-paging/node_modules/typescript": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-paging/node_modules/vitest": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/vitest@3.2.0_@types+debug@4.1.12_@types+node@18.19.110_@vitest+browser@3.2.0_tsx@4.19.4_yaml@2.8.0/node_modules/vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-rest-pipeline": { + "name": "@azure/core-rest-pipeline", + "version": "1.20.1", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.8.0", + "@azure/core-tracing": "^1.0.1", + "@azure/core-util": "^1.11.0", + "@azure/logger": "^1.0.0", + "@typespec/ts-http-runtime": "^0.2.2", + "tslib": "^2.6.2" + }, + "devDependencies": { + "@azure-tools/vite-plugin-browser-test-map": "^1.0.0", + "@azure/dev-tool": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@types/node": "^18.0.0", + "@vitest/browser": "^3.0.9", + "@vitest/coverage-istanbul": "^3.0.9", + "eslint": "^9.9.0", + "playwright": "^1.41.2", + "typescript": "~5.8.2", + "vitest": "^3.0.9" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../azure-sdk-for-js/sdk/core/core-rest-pipeline/node_modules/@azure-tools/vite-plugin-browser-test-map": { + "resolved": "../../azure-sdk-for-js/common/tools/vite-plugin-browser-test-map", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-rest-pipeline/node_modules/@azure/abort-controller": { + "resolved": "../../azure-sdk-for-js/sdk/core/abort-controller", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-rest-pipeline/node_modules/@azure/core-auth": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-auth", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-rest-pipeline/node_modules/@azure/core-tracing": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-tracing", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-rest-pipeline/node_modules/@azure/core-util": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-util", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-rest-pipeline/node_modules/@azure/dev-tool": { + "resolved": "../../azure-sdk-for-js/common/tools/dev-tool", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-rest-pipeline/node_modules/@azure/eslint-plugin-azure-sdk": { + "resolved": "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-rest-pipeline/node_modules/@azure/logger": { + "resolved": "../../azure-sdk-for-js/sdk/core/logger", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-rest-pipeline/node_modules/@types/node": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+node@18.19.110/node_modules/@types/node", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-rest-pipeline/node_modules/@typespec/ts-http-runtime": { + "resolved": "../../azure-sdk-for-js/sdk/core/ts-http-runtime", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-rest-pipeline/node_modules/@vitest/browser": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+browser@3.2.0_playwright@1.52.0_vite@6.3.5_@types+node@22.7.9_tsx@4.19.4_yaml@2.8.0__vitest@3.2.0/node_modules/@vitest/browser", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-rest-pipeline/node_modules/@vitest/coverage-istanbul": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+coverage-istanbul@3.2.0_vitest@3.2.0/node_modules/@vitest/coverage-istanbul", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-rest-pipeline/node_modules/eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint@9.28.0/node_modules/eslint", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-rest-pipeline/node_modules/playwright": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/playwright@1.52.0/node_modules/playwright", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-rest-pipeline/node_modules/tslib": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-rest-pipeline/node_modules/typescript": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-rest-pipeline/node_modules/vitest": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/vitest@3.2.0_@types+debug@4.1.12_@types+node@18.19.110_@vitest+browser@3.2.0_tsx@4.19.4_yaml@2.8.0/node_modules/vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-tracing": { + "name": "@azure/core-tracing", + "version": "1.2.1", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "devDependencies": { + "@azure/core-auth": "^1.3.0", + "@azure/dev-tool": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@types/node": "^18.0.0", + "@vitest/browser": "^3.0.9", + "@vitest/coverage-istanbul": "^3.0.9", + "eslint": "^9.9.0", + "playwright": "^1.41.2", + "typescript": "~5.8.2", + "vitest": "^3.0.9" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../azure-sdk-for-js/sdk/core/core-tracing/node_modules/@azure/core-auth": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-auth", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-tracing/node_modules/@azure/dev-tool": { + "resolved": "../../azure-sdk-for-js/common/tools/dev-tool", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-tracing/node_modules/@azure/eslint-plugin-azure-sdk": { + "resolved": "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-tracing/node_modules/@types/node": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+node@18.19.110/node_modules/@types/node", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-tracing/node_modules/@vitest/browser": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+browser@3.2.0_playwright@1.52.0_vite@6.3.5_@types+node@22.7.9_tsx@4.19.4_yaml@2.8.0__vitest@3.2.0/node_modules/@vitest/browser", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-tracing/node_modules/@vitest/coverage-istanbul": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+coverage-istanbul@3.2.0_vitest@3.2.0/node_modules/@vitest/coverage-istanbul", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-tracing/node_modules/eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint@9.28.0/node_modules/eslint", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-tracing/node_modules/playwright": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/playwright@1.52.0/node_modules/playwright", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-tracing/node_modules/tslib": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-tracing/node_modules/typescript": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-tracing/node_modules/vitest": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/vitest@3.2.0_@types+debug@4.1.12_@types+node@18.19.110_@vitest+browser@3.2.0_tsx@4.19.4_yaml@2.8.0/node_modules/vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-util": { + "name": "@azure/core-util", + "version": "1.12.1", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@typespec/ts-http-runtime": "^0.2.2", + "tslib": "^2.6.2" + }, + "devDependencies": { + "@azure-tools/vite-plugin-browser-test-map": "^1.0.0", + "@azure/dev-tool": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@types/node": "^18.0.0", + "@vitest/browser": "^3.0.9", + "@vitest/coverage-istanbul": "^3.0.9", + "eslint": "^9.9.0", + "playwright": "^1.41.2", + "typescript": "~5.8.2", + "vitest": "^3.0.9" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../azure-sdk-for-js/sdk/core/core-util/node_modules/@azure-tools/vite-plugin-browser-test-map": { + "resolved": "../../azure-sdk-for-js/common/tools/vite-plugin-browser-test-map", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-util/node_modules/@azure/abort-controller": { + "resolved": "../../azure-sdk-for-js/sdk/core/abort-controller", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-util/node_modules/@azure/dev-tool": { + "resolved": "../../azure-sdk-for-js/common/tools/dev-tool", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-util/node_modules/@azure/eslint-plugin-azure-sdk": { + "resolved": "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-util/node_modules/@types/node": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+node@18.19.110/node_modules/@types/node", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-util/node_modules/@typespec/ts-http-runtime": { + "resolved": "../../azure-sdk-for-js/sdk/core/ts-http-runtime", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-util/node_modules/@vitest/browser": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+browser@3.2.0_playwright@1.52.0_vite@6.3.5_@types+node@22.7.9_tsx@4.19.4_yaml@2.8.0__vitest@3.2.0/node_modules/@vitest/browser", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-util/node_modules/@vitest/coverage-istanbul": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+coverage-istanbul@3.2.0_vitest@3.2.0/node_modules/@vitest/coverage-istanbul", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-util/node_modules/eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint@9.28.0/node_modules/eslint", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-util/node_modules/playwright": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/playwright@1.52.0/node_modules/playwright", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-util/node_modules/tslib": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-util/node_modules/typescript": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-util/node_modules/vitest": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/vitest@3.2.0_@types+debug@4.1.12_@types+node@18.19.110_@vitest+browser@3.2.0_tsx@4.19.4_yaml@2.8.0/node_modules/vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-xml": { + "name": "@azure/core-xml", + "version": "1.4.6", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-xml-parser": "^5.0.7", + "tslib": "^2.8.1" + }, + "devDependencies": { + "@azure/dev-tool": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@types/node": "^18.0.0", + "@types/trusted-types": "^2.0.0", + "@vitest/browser": "^3.0.9", + "@vitest/coverage-istanbul": "^3.0.9", + "eslint": "^9.9.0", + "playwright": "^1.50.1", + "typescript": "~5.8.2", + "vitest": "^3.0.9" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../azure-sdk-for-js/sdk/core/core-xml/node_modules/@azure/dev-tool": { + "resolved": "../../azure-sdk-for-js/common/tools/dev-tool", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-xml/node_modules/@azure/eslint-plugin-azure-sdk": { + "resolved": "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-xml/node_modules/@types/node": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+node@18.19.110/node_modules/@types/node", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-xml/node_modules/@types/trusted-types": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+trusted-types@2.0.7/node_modules/@types/trusted-types", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-xml/node_modules/@vitest/browser": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+browser@3.2.0_playwright@1.52.0_vite@6.3.5_@types+node@22.7.9_tsx@4.19.4_yaml@2.8.0__vitest@3.2.0/node_modules/@vitest/browser", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-xml/node_modules/@vitest/coverage-istanbul": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+coverage-istanbul@3.2.0_vitest@3.2.0/node_modules/@vitest/coverage-istanbul", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-xml/node_modules/eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint@9.28.0/node_modules/eslint", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-xml/node_modules/fast-xml-parser": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/fast-xml-parser@5.2.3/node_modules/fast-xml-parser", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-xml/node_modules/playwright": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/playwright@1.52.0/node_modules/playwright", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-xml/node_modules/tslib": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-xml/node_modules/typescript": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/core-xml/node_modules/vitest": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/vitest@3.2.0_@types+debug@4.1.12_@types+node@18.19.110_@vitest+browser@3.2.0_tsx@4.19.4_yaml@2.8.0/node_modules/vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/logger": { + "name": "@azure/logger", + "version": "1.2.1", + "license": "MIT", + "dependencies": { + "@typespec/ts-http-runtime": "^0.2.2", + "tslib": "^2.6.2" + }, + "devDependencies": { + "@azure/dev-tool": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@types/node": "^18.0.0", + "@vitest/browser": "^3.0.9", + "@vitest/coverage-istanbul": "^3.0.9", + "dotenv": "^16.3.1", + "eslint": "^9.9.0", + "playwright": "^1.41.2", + "typescript": "~5.8.2", + "vitest": "^3.0.9" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../azure-sdk-for-js/sdk/core/logger/node_modules/@azure/dev-tool": { + "resolved": "../../azure-sdk-for-js/common/tools/dev-tool", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/logger/node_modules/@azure/eslint-plugin-azure-sdk": { + "resolved": "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/logger/node_modules/@types/node": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+node@18.19.110/node_modules/@types/node", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/logger/node_modules/@typespec/ts-http-runtime": { + "resolved": "../../azure-sdk-for-js/sdk/core/ts-http-runtime", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/logger/node_modules/@vitest/browser": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+browser@3.2.0_playwright@1.52.0_vite@6.3.5_@types+node@22.7.9_tsx@4.19.4_yaml@2.8.0__vitest@3.2.0/node_modules/@vitest/browser", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/logger/node_modules/@vitest/coverage-istanbul": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+coverage-istanbul@3.2.0_vitest@3.2.0/node_modules/@vitest/coverage-istanbul", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/logger/node_modules/dotenv": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/dotenv@16.5.0/node_modules/dotenv", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/logger/node_modules/eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint@9.28.0/node_modules/eslint", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/logger/node_modules/playwright": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/playwright@1.52.0/node_modules/playwright", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/logger/node_modules/tslib": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/logger/node_modules/typescript": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/logger/node_modules/vitest": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/vitest@3.2.0_@types+debug@4.1.12_@types+node@18.19.110_@vitest+browser@3.2.0_tsx@4.19.4_yaml@2.8.0/node_modules/vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/ts-http-runtime": { + "name": "@typespec/ts-http-runtime", + "version": "0.2.3", + "license": "MIT", + "dependencies": { + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "tslib": "^2.6.2" + }, + "devDependencies": { + "@azure-tools/vite-plugin-browser-test-map": "^1.0.0", + "@azure/dev-tool": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@types/node": "^18.0.0", + "@vitest/browser": "^3.0.9", + "@vitest/coverage-istanbul": "^3.0.9", + "eslint": "^9.9.0", + "playwright": "^1.41.2", + "tsx": "^4.19.1", + "typescript": "~5.8.2", + "vitest": "^3.0.9" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../azure-sdk-for-js/sdk/core/ts-http-runtime/node_modules/@azure-tools/vite-plugin-browser-test-map": { + "resolved": "../../azure-sdk-for-js/common/tools/vite-plugin-browser-test-map", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/ts-http-runtime/node_modules/@azure/dev-tool": { + "resolved": "../../azure-sdk-for-js/common/tools/dev-tool", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/ts-http-runtime/node_modules/@azure/eslint-plugin-azure-sdk": { + "resolved": "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/ts-http-runtime/node_modules/@types/node": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+node@18.19.110/node_modules/@types/node", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/ts-http-runtime/node_modules/@vitest/browser": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+browser@3.2.0_playwright@1.52.0_vite@6.3.5_@types+node@22.7.9_tsx@4.19.4_yaml@2.8.0__vitest@3.2.0/node_modules/@vitest/browser", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/ts-http-runtime/node_modules/@vitest/coverage-istanbul": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+coverage-istanbul@3.2.0_vitest@3.2.0/node_modules/@vitest/coverage-istanbul", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/ts-http-runtime/node_modules/eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint@9.28.0/node_modules/eslint", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/ts-http-runtime/node_modules/http-proxy-agent": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/http-proxy-agent@7.0.2/node_modules/http-proxy-agent", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/ts-http-runtime/node_modules/https-proxy-agent": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/https-proxy-agent@7.0.6/node_modules/https-proxy-agent", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/ts-http-runtime/node_modules/playwright": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/playwright@1.52.0/node_modules/playwright", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/ts-http-runtime/node_modules/tslib": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/ts-http-runtime/node_modules/tsx": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tsx@4.19.4/node_modules/tsx", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/ts-http-runtime/node_modules/typescript": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript", + "link": true + }, + "../../azure-sdk-for-js/sdk/core/ts-http-runtime/node_modules/vitest": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/vitest@3.2.0_@types+debug@4.1.12_@types+node@18.19.110_@vitest+browser@3.2.0_tsx@4.19.4_yaml@2.8.0/node_modules/vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity": { + "name": "@azure/identity", + "version": "4.10.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.9.0", + "@azure/core-client": "^1.9.2", + "@azure/core-rest-pipeline": "^1.17.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.11.0", + "@azure/logger": "^1.0.0", + "@azure/msal-browser": "^4.2.0", + "@azure/msal-node": "^3.5.0", + "open": "^10.1.0", + "tslib": "^2.2.0" + }, + "devDependencies": { + "@azure-tools/test-recorder": "^4.1.0", + "@azure-tools/test-utils-vitest": "^1.0.0", + "@azure/dev-tool": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@azure/keyvault-keys": "^4.2.0", + "@types/jsonwebtoken": "^9.0.0", + "@types/ms": "^2.1.0", + "@types/node": "^18.0.0", + "@vitest/browser": "^3.0.9", + "@vitest/coverage-istanbul": "^3.0.9", + "assertion-error": "^2.0.1", + "dotenv": "^16.0.0", + "eslint": "^9.9.0", + "jsonwebtoken": "^9.0.0", + "ms": "^2.1.3", + "playwright": "^1.48.2", + "typescript": "~5.8.2", + "vitest": "^3.0.9" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/@azure-tools/test-recorder": { + "resolved": "../../azure-sdk-for-js/sdk/test-utils/recorder", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/@azure-tools/test-utils-vitest": { + "resolved": "../../azure-sdk-for-js/sdk/test-utils/test-utils-vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/@azure/abort-controller": { + "resolved": "../../azure-sdk-for-js/sdk/core/abort-controller", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/@azure/core-auth": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-auth", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/@azure/core-client": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-client", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/@azure/core-rest-pipeline": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-rest-pipeline", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/@azure/core-tracing": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-tracing", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/@azure/core-util": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-util", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/@azure/dev-tool": { + "resolved": "../../azure-sdk-for-js/common/tools/dev-tool", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/@azure/eslint-plugin-azure-sdk": { + "resolved": "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/@azure/keyvault-keys": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@azure+keyvault-keys@4.9.0/node_modules/@azure/keyvault-keys", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/@azure/logger": { + "resolved": "../../azure-sdk-for-js/sdk/core/logger", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/@azure/msal-browser": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@azure+msal-browser@4.13.0/node_modules/@azure/msal-browser", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/@azure/msal-node": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@azure+msal-node@3.6.0/node_modules/@azure/msal-node", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/@types/jsonwebtoken": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+jsonwebtoken@9.0.9/node_modules/@types/jsonwebtoken", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/@types/ms": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+ms@2.1.0/node_modules/@types/ms", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/@types/node": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+node@18.19.110/node_modules/@types/node", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/@vitest/browser": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+browser@3.2.0_playwright@1.52.0_vite@6.3.5_@types+node@22.7.9_tsx@4.19.4_yaml@2.8.0__vitest@3.2.0/node_modules/@vitest/browser", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/@vitest/coverage-istanbul": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+coverage-istanbul@3.2.0_vitest@3.2.0/node_modules/@vitest/coverage-istanbul", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/assertion-error": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/assertion-error@2.0.1/node_modules/assertion-error", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/dotenv": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/dotenv@16.5.0/node_modules/dotenv", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint@9.28.0/node_modules/eslint", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/jsonwebtoken": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/jsonwebtoken@9.0.2/node_modules/jsonwebtoken", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/ms": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/ms@2.1.3/node_modules/ms", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/open": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/open@10.1.2/node_modules/open", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/playwright": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/playwright@1.52.0/node_modules/playwright", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/tslib": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/typescript": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript", + "link": true + }, + "../../azure-sdk-for-js/sdk/identity/identity/node_modules/vitest": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/vitest@3.2.0_@types+debug@4.1.12_@types+node@18.19.110_@vitest+browser@3.2.0_tsx@4.19.4_yaml@2.8.0/node_modules/vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus": { + "name": "@azure/service-bus", + "version": "7.10.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-amqp": "^4.3.2", + "@azure/core-auth": "^1.9.0", + "@azure/core-client": "^1.9.2", + "@azure/core-paging": "^1.6.2", + "@azure/core-rest-pipeline": "^1.19.0", + "@azure/core-tracing": "^1.2.0", + "@azure/core-util": "^1.11.0", + "@azure/core-xml": "^1.4.3", + "@azure/logger": "^1.1.4", + "buffer": "^6.0.3", + "is-buffer": "^2.0.5", + "jssha": "^3.3.1", + "long": "^5.3.1", + "process": "^0.11.10", + "rhea-promise": "^3.0.3", + "tslib": "^2.8.1", + "util": "^0.12.5" + }, + "devDependencies": { + "@azure-tools/test-credential": "^2.1.0", + "@azure-tools/test-recorder": "^4.1.0", + "@azure-tools/test-utils-vitest": "^1.0.0", + "@azure-tools/vite-plugin-browser-test-map": "^1.0.0", + "@azure/arm-servicebus": "^6.1.0", + "@azure/dev-tool": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@azure/identity": "^4.7.0", + "@rollup/plugin-inject": "^5.0.5", + "@types/chai-as-promised": "^8.0.1", + "@types/debug": "^4.1.4", + "@types/is-buffer": "^2.0.0", + "@types/node": "^18.0.0", + "@types/ws": "^7.2.4", + "@vitest/browser": "^3.0.9", + "@vitest/coverage-istanbul": "^3.0.9", + "chai": "^5.1.1", + "chai-as-promised": "^8.0.0", + "chai-exclude": "^3.0.0", + "debug": "^4.1.1", + "dotenv": "^16.0.0", + "eslint": "^9.9.0", + "events": "^3.0.0", + "https-proxy-agent": "^7.0.0", + "playwright": "^1.50.1", + "typescript": "~5.8.2", + "vitest": "^3.0.9", + "ws": "^8.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/@azure-tools/test-credential": { + "resolved": "../../azure-sdk-for-js/sdk/test-utils/test-credential", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/@azure-tools/test-recorder": { + "resolved": "../../azure-sdk-for-js/sdk/test-utils/recorder", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/@azure-tools/test-utils-vitest": { + "resolved": "../../azure-sdk-for-js/sdk/test-utils/test-utils-vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/@azure-tools/vite-plugin-browser-test-map": { + "resolved": "../../azure-sdk-for-js/common/tools/vite-plugin-browser-test-map", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/@azure/abort-controller": { + "resolved": "../../azure-sdk-for-js/sdk/core/abort-controller", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/@azure/arm-servicebus": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@azure+arm-servicebus@6.1.0/node_modules/@azure/arm-servicebus", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/@azure/core-amqp": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-amqp", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/@azure/core-auth": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-auth", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/@azure/core-client": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-client", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/@azure/core-paging": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-paging", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/@azure/core-rest-pipeline": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-rest-pipeline", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/@azure/core-tracing": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-tracing", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/@azure/core-util": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-util", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/@azure/core-xml": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-xml", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/@azure/dev-tool": { + "resolved": "../../azure-sdk-for-js/common/tools/dev-tool", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/@azure/eslint-plugin-azure-sdk": { + "resolved": "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/@azure/identity": { + "resolved": "../../azure-sdk-for-js/sdk/identity/identity", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/@azure/logger": { + "resolved": "../../azure-sdk-for-js/sdk/core/logger", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/@rollup/plugin-inject": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@rollup+plugin-inject@5.0.5_rollup@4.41.1/node_modules/@rollup/plugin-inject", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/@types/chai-as-promised": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+chai-as-promised@8.0.2/node_modules/@types/chai-as-promised", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/@types/debug": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+debug@4.1.12/node_modules/@types/debug", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/@types/is-buffer": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+is-buffer@2.0.2/node_modules/@types/is-buffer", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/@types/node": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+node@18.19.110/node_modules/@types/node", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/@types/ws": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+ws@7.4.7/node_modules/@types/ws", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/@vitest/browser": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+browser@3.2.0_playwright@1.52.0_vite@6.3.5_@types+node@22.7.9_tsx@4.19.4_yaml@2.8.0__vitest@3.2.0/node_modules/@vitest/browser", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/@vitest/coverage-istanbul": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+coverage-istanbul@3.2.0_vitest@3.2.0/node_modules/@vitest/coverage-istanbul", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/buffer": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/buffer@6.0.3/node_modules/buffer", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/chai": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/chai@5.2.0/node_modules/chai", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/chai-as-promised": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/chai-as-promised@8.0.1_chai@5.2.0/node_modules/chai-as-promised", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/chai-exclude": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/chai-exclude@3.0.1_chai@5.2.0/node_modules/chai-exclude", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/debug": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/debug@4.4.1/node_modules/debug", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/dotenv": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/dotenv@16.5.0/node_modules/dotenv", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint@9.28.0/node_modules/eslint", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/events": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/events@3.3.0/node_modules/events", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/https-proxy-agent": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/https-proxy-agent@7.0.6/node_modules/https-proxy-agent", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/is-buffer": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/is-buffer@2.0.5/node_modules/is-buffer", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/jssha": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/jssha@3.3.1/node_modules/jssha", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/long": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/long@5.3.2/node_modules/long", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/playwright": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/playwright@1.52.0/node_modules/playwright", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/process": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/process@0.11.10/node_modules/process", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/rhea-promise": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/rhea-promise@3.0.3/node_modules/rhea-promise", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/tslib": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/typescript": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/util": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/util@0.12.5/node_modules/util", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/vitest": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/vitest@3.2.0_@types+debug@4.1.12_@types+node@18.19.110_@vitest+browser@3.2.0_tsx@4.19.4_yaml@2.8.0/node_modules/vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/servicebus/service-bus/node_modules/ws": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/ws@8.18.2/node_modules/ws", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/recorder": { + "name": "@azure-tools/test-recorder", + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/core-auth": "^1.3.2", + "@azure/core-client": "^1.9.2", + "@azure/core-rest-pipeline": "^1.13.0", + "@azure/core-util": "^1.6.1", + "@azure/logger": "^1.0.0" + }, + "devDependencies": { + "@azure-tools/vite-plugin-browser-test-map": "^1.0.0", + "@azure/dev-tool": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@types/node": "^18.0.0", + "@vitest/browser": "^3.0.9", + "@vitest/coverage-istanbul": "^3.0.9", + "concurrently": "^8.2.0", + "eslint": "^9.9.0", + "express": "^4.19.2", + "playwright": "^1.41.2", + "tslib": "^2.6.2", + "typescript": "~5.8.2", + "vitest": "^3.0.9" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../azure-sdk-for-js/sdk/test-utils/recorder/node_modules/@azure-tools/vite-plugin-browser-test-map": { + "resolved": "../../azure-sdk-for-js/common/tools/vite-plugin-browser-test-map", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/recorder/node_modules/@azure/core-auth": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-auth", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/recorder/node_modules/@azure/core-client": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-client", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/recorder/node_modules/@azure/core-rest-pipeline": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-rest-pipeline", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/recorder/node_modules/@azure/core-util": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-util", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/recorder/node_modules/@azure/dev-tool": { + "resolved": "../../azure-sdk-for-js/common/tools/dev-tool", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/recorder/node_modules/@azure/eslint-plugin-azure-sdk": { + "resolved": "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/recorder/node_modules/@azure/logger": { + "resolved": "../../azure-sdk-for-js/sdk/core/logger", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/recorder/node_modules/@types/node": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+node@18.19.110/node_modules/@types/node", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/recorder/node_modules/@vitest/browser": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+browser@3.2.0_playwright@1.52.0_vite@6.3.5_@types+node@22.7.9_tsx@4.19.4_yaml@2.8.0__vitest@3.2.0/node_modules/@vitest/browser", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/recorder/node_modules/@vitest/coverage-istanbul": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+coverage-istanbul@3.2.0_vitest@3.2.0/node_modules/@vitest/coverage-istanbul", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/recorder/node_modules/concurrently": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/concurrently@8.2.2/node_modules/concurrently", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/recorder/node_modules/eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint@9.28.0/node_modules/eslint", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/recorder/node_modules/express": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/express@4.21.2/node_modules/express", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/recorder/node_modules/playwright": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/playwright@1.52.0/node_modules/playwright", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/recorder/node_modules/tslib": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/recorder/node_modules/typescript": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/recorder/node_modules/vitest": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/vitest@3.2.0_@types+debug@4.1.12_@types+node@18.19.110_@vitest+browser@3.2.0_tsx@4.19.4_yaml@2.8.0/node_modules/vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-credential": { + "name": "@azure-tools/test-credential", + "version": "2.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure-tools/test-recorder": "^4.0.0", + "@azure/core-auth": "^1.9.0", + "@azure/core-util": "^1.11.0", + "@azure/identity": "^4.5.0", + "tslib": "^2.8.1" + }, + "devDependencies": { + "@azure-tools/test-utils-vitest": "^1.0.0", + "@azure/dev-tool": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@types/node": "^18.0.0", + "@vitest/browser": "^3.0.9", + "@vitest/coverage-istanbul": "^3.0.9", + "eslint": "^9.9.0", + "playwright": "^1.49.1", + "typescript": "~5.8.2", + "vitest": "^3.0.9" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../azure-sdk-for-js/sdk/test-utils/test-credential/node_modules/@azure-tools/test-recorder": { + "resolved": "../../azure-sdk-for-js/sdk/test-utils/recorder", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-credential/node_modules/@azure-tools/test-utils-vitest": { + "resolved": "../../azure-sdk-for-js/sdk/test-utils/test-utils-vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-credential/node_modules/@azure/core-auth": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-auth", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-credential/node_modules/@azure/core-util": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-util", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-credential/node_modules/@azure/dev-tool": { + "resolved": "../../azure-sdk-for-js/common/tools/dev-tool", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-credential/node_modules/@azure/eslint-plugin-azure-sdk": { + "resolved": "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-credential/node_modules/@azure/identity": { + "resolved": "../../azure-sdk-for-js/sdk/identity/identity", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-credential/node_modules/@types/node": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+node@18.19.110/node_modules/@types/node", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-credential/node_modules/@vitest/browser": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+browser@3.2.0_playwright@1.52.0_vite@6.3.5_@types+node@22.7.9_tsx@4.19.4_yaml@2.8.0__vitest@3.2.0/node_modules/@vitest/browser", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-credential/node_modules/@vitest/coverage-istanbul": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+coverage-istanbul@3.2.0_vitest@3.2.0/node_modules/@vitest/coverage-istanbul", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-credential/node_modules/eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint@9.28.0/node_modules/eslint", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-credential/node_modules/playwright": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/playwright@1.52.0/node_modules/playwright", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-credential/node_modules/tslib": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-credential/node_modules/typescript": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-credential/node_modules/vitest": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/vitest@3.2.0_@types+debug@4.1.12_@types+node@18.19.110_@vitest+browser@3.2.0_tsx@4.19.4_yaml@2.8.0/node_modules/vitest", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-utils-vitest": { + "name": "@azure-tools/test-utils-vitest", + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure-tools/test-recorder": "^4.0.0", + "@azure/abort-controller": "^2.1.2", + "@azure/core-rest-pipeline": "^1.16.3", + "@azure/core-tracing": "^1.1.2", + "@opentelemetry/api": "^1.9.0", + "tslib": "^2.6.3", + "vitest": "^3.0.9" + }, + "devDependencies": { + "@azure/dev-tool": "^1.0.0", + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@types/node": "^18.0.0", + "@vitest/browser": "^3.0.9", + "@vitest/coverage-istanbul": "^3.0.9", + "@vitest/expect": "^3.0.9", + "eslint": "^9.9.0", + "playwright": "^1.46.0", + "typescript": "~5.8.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../azure-sdk-for-js/sdk/test-utils/test-utils-vitest/node_modules/@azure-tools/test-recorder": { + "resolved": "../../azure-sdk-for-js/sdk/test-utils/recorder", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-utils-vitest/node_modules/@azure/abort-controller": { + "resolved": "../../azure-sdk-for-js/sdk/core/abort-controller", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-utils-vitest/node_modules/@azure/core-rest-pipeline": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-rest-pipeline", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-utils-vitest/node_modules/@azure/core-tracing": { + "resolved": "../../azure-sdk-for-js/sdk/core/core-tracing", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-utils-vitest/node_modules/@azure/dev-tool": { + "resolved": "../../azure-sdk-for-js/common/tools/dev-tool", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-utils-vitest/node_modules/@azure/eslint-plugin-azure-sdk": { + "resolved": "../../azure-sdk-for-js/common/tools/eslint-plugin-azure-sdk", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-utils-vitest/node_modules/@opentelemetry/api": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@opentelemetry+api@1.9.0/node_modules/@opentelemetry/api", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-utils-vitest/node_modules/@types/node": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@types+node@18.19.110/node_modules/@types/node", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-utils-vitest/node_modules/@vitest/browser": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+browser@3.2.0_playwright@1.52.0_vite@6.3.5_@types+node@22.7.9_tsx@4.19.4_yaml@2.8.0__vitest@3.2.0/node_modules/@vitest/browser", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-utils-vitest/node_modules/@vitest/coverage-istanbul": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+coverage-istanbul@3.2.0_vitest@3.2.0/node_modules/@vitest/coverage-istanbul", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-utils-vitest/node_modules/@vitest/expect": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/@vitest+expect@3.2.0/node_modules/@vitest/expect", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-utils-vitest/node_modules/eslint": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/eslint@9.28.0/node_modules/eslint", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-utils-vitest/node_modules/playwright": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/playwright@1.52.0/node_modules/playwright", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-utils-vitest/node_modules/tslib": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/tslib@2.8.1/node_modules/tslib", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-utils-vitest/node_modules/typescript": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/typescript@5.8.3/node_modules/typescript", + "link": true + }, + "../../azure-sdk-for-js/sdk/test-utils/test-utils-vitest/node_modules/vitest": { + "resolved": "../../azure-sdk-for-js/common/temp/node_modules/.pnpm/vitest@3.2.0_@types+debug@4.1.12_@types+node@18.19.110_@vitest+browser@3.2.0_tsx@4.19.4_yaml@2.8.0/node_modules/vitest", + "link": true + }, + "node_modules/@azure-rest/core-client": { + "version": "2.4.0", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.3.0", + "@azure/core-rest-pipeline": "^1.5.0", + "@azure/core-tracing": "^1.0.1", + "@typespec/ts-http-runtime": "^0.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/abort-controller": { + "version": "2.1.2", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/communication-call-automation": { + "resolved": "../../azure-sdk-for-js/sdk/communication/communication-call-automation", + "link": true + }, + "node_modules/@azure/communication-common": { + "version": "2.4.0", + "license": "MIT", + "dependencies": { + "@azure-rest/core-client": "^2.3.3", + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.9.0", + "@azure/core-rest-pipeline": "^1.17.0", + "@azure/core-tracing": "^1.2.0", + "@azure/core-util": "^1.11.0", + "events": "^3.3.0", + "jwt-decode": "^4.0.0", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/communication-identity": { + "version": "1.3.1", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "@azure/communication-common": "^2.3.1", + "@azure/core-auth": "^1.3.0", + "@azure/core-client": "^1.3.0", + "@azure/core-lro": "^2.2.0", + "@azure/core-paging": "^1.1.1", + "@azure/core-rest-pipeline": "^1.3.0", + "@azure/core-tracing": "^1.0.0", + "@azure/logger": "^1.0.0", + "events": "^3.0.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/communication-identity/node_modules/@azure/abort-controller": { + "version": "1.1.0", + "license": "MIT", + "dependencies": { + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@azure/communication-rooms": { + "version": "1.2.0", + "license": "MIT", + "dependencies": { + "@azure/communication-common": "^2.3.1", + "@azure/core-auth": "^1.9.0", + "@azure/core-client": "^1.9.2", + "@azure/core-paging": "^1.6.2", + "@azure/core-rest-pipeline": "^1.18.0", + "@azure/core-tracing": "^1.2.0", + "@azure/core-util": "^1.11.0", + "@azure/logger": "^1.1.4", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-auth": { + "version": "1.9.0", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-util": "^1.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-client": { + "version": "1.9.4", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.4.0", + "@azure/core-rest-pipeline": "^1.20.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.6.1", + "@azure/logger": "^1.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-lro": { + "version": "2.7.2", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-util": "^1.2.0", + "@azure/logger": "^1.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-paging": { + "version": "1.6.2", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline": { + "version": "1.21.0", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.8.0", + "@azure/core-tracing": "^1.0.1", + "@azure/core-util": "^1.11.0", + "@azure/logger": "^1.0.0", + "@typespec/ts-http-runtime": "^0.2.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-tracing": { + "version": "1.2.0", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-util": { + "version": "1.12.0", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@typespec/ts-http-runtime": "^0.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/eventgrid": { + "version": "4.15.0", + "license": "MIT", + "dependencies": { + "@azure/core-auth": "^1.3.0", + "@azure/core-client": "^1.5.0", + "@azure/core-rest-pipeline": "^1.1.0", + "@azure/core-tracing": "^1.0.0", + "@azure/logger": "^1.0.0", + "tslib": "^2.2.0", + "uuid": "^8.3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@azure/logger": { + "version": "1.2.0", + "license": "MIT", + "dependencies": { + "@typespec/ts-http-runtime": "^0.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.23", + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.6", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.1", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/qs": { + "version": "6.14.0", + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.5", + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.8", + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@typespec/ts-http-runtime": { + "version": "0.2.3", + "license": "MIT", + "dependencies": { + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.3", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "1.20.3", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.1", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "license": "MIT" + }, + "node_modules/create-require": { + "version": "1.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "2.6.9", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dotenv": { + "version": "16.5.0", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/express": { + "version": "4.21.2", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http-proxy-agent/node_modules/debug": { + "version": "4.4.1", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/http-proxy-agent/node_modules/ms": { + "version": "2.1.3", + "license": "MIT" + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.4.1", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.3", + "license": "MIT" + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "dev": true, + "license": "ISC" + }, + "node_modules/inherits": { + "version": "2.0.4", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/jwt-decode": { + "version": "4.0.0", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "dev": true, + "license": "ISC" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/nodemon": { + "version": "2.0.22", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/nodemon/node_modules/ms": { + "version": "2.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "license": "MIT" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "dev": true, + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.13.0", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "license": "MIT" + }, + "node_modules/semver": { + "version": "5.7.2", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/send": { + "version": "0.19.0", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "license": "MIT" + }, + "node_modules/serve-static": { + "version": "1.16.2", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "license": "ISC" + }, + "node_modules/side-channel": { + "version": "1.1.0", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/simple-update-notifier": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "~7.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/touch": { + "version": "3.1.1", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "license": "0BSD" + }, + "node_modules/type-is": { + "version": "1.6.18", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/vary": { + "version": "1.1.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + } + } +} From 395f9b828dae067d22fc9b10f0341a00cedba4c3 Mon Sep 17 00:00:00 2001 From: nageshy Date: Sun, 27 Jul 2025 12:32:56 +0530 Subject: [PATCH 05/12] Updated code --- callautomation-lobbycall-sample/src/app.ts | 595 +++++++----------- .../src/app.ts.xxx | 277 -------- .../src/webpage/index.html | 83 +-- 3 files changed, 235 insertions(+), 720 deletions(-) delete mode 100644 callautomation-lobbycall-sample/src/app.ts.xxx diff --git a/callautomation-lobbycall-sample/src/app.ts b/callautomation-lobbycall-sample/src/app.ts index bd19a61e..3b2114c1 100644 --- a/callautomation-lobbycall-sample/src/app.ts +++ b/callautomation-lobbycall-sample/src/app.ts @@ -1,10 +1,11 @@ import { config } from 'dotenv'; import express, { Application } from 'express'; -import { CommunicationUserIdentifier, PhoneNumberIdentifier } from "@azure/communication-common"; +import { CommunicationUserIdentifier, getIdentifierRawId } from "@azure/communication-common"; import { CallAutomationClient, CallInvite, - AnswerCallOptions, + TextSource, + PlayOptions, MoveParticipantsOptions } from "@azure/communication-call-automation"; @@ -24,6 +25,7 @@ let lobbyCallerId: string; const callbackUriHost = process.env.CALLBACK_URI || ""; const connectionString = process.env.CONNECTION_STRING || "" const endpoint = process.env.PMA_ENDPOINT || "" +// let webSocket = null; async function createAcsClient() { lobbyCallConnectionId = ""; @@ -35,10 +37,93 @@ async function createAcsClient() { console.log("Initialized ACS Client."); } -app.get('/TargetCallToAcsUser(Create)', async (req, res) => { - const acsTarget = req.body.acsTarget; // expects { "acsTarget": "" } +const http = require('http'); +// const WebSocket = require('ws'); +// const server = http.createServer(app); + +// WebSocket server setup +// const wss = new WebSocket.Server({ noServer: true }); + +// server.on('upgrade', (request, socket, head) => { +// // Only accept connections to the correct path +// const url = request.url || ''; +// if (url === `/ws/${process.env.SOCKET_TOKEN}`) { +// wss.handleUpgrade(request, socket, head, function done(ws) { +// wss.emit('connection', ws, request); +// }); +// } else { +// socket.destroy(); +// } +// }); + +// wss.on('connection', (ws) => { +// webSocket = ws; +// console.log('Received WEB SOCKET request.'); + +// ws.on('message', async (message) => { +// const jsResponse = message.toString(); +// console.log(`Received from JS: ${jsResponse}`); + +// // Move participant to target call if response is "yes" +// if (jsResponse.trim().toLowerCase() === 'yes') { +// console.log('TODO: Move Participant'); +// try { +// console.log(` +// ~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~ +// Move Participant operation started.. +// Source Caller Id: ${lobbyCallerId} +// Source Connection Id: ${lobbyCallConnectionId} +// Target Connection Id: ${targetCallConnectionId} +// `); + +// // Get the target connection +// const targetConnection = acsClient.getCallConnection(targetCallConnectionId); + +// // Get participants from source connection for reference +// // const sourceConnection = client.getCallConnection(lobbyConnectionId); + +// // Create participant identifier based on the input +// let participantToMove; +// if (lobbyCallerId.startsWith('+')) { +// // Phone number +// participantToMove = { phoneNumber: lobbyCallerId }; +// console.log(`Moving phone number participant: ${lobbyCallerId}`); +// } else if (lobbyCallerId.startsWith('8:acs:')) { +// // ACS Communication User +// participantToMove = { communicationUserId: lobbyCallerId }; +// console.log(`Moving ACS user participant: ${lobbyCallerId}`); +// } else { +// console.log("Invalid participant format. Use phone number (+1234567890) or ACS user ID (8:acs:...)"); +// } + +// // Prepare move participants options +// const options : MoveParticipantsOptions = { +// operationContext: "MoveParticipant2" +// }; + +// // Call the ACS SDK to move participants +// await targetConnection.moveParticipants([participantToMove], lobbyCallConnectionId, options); + +// console.log('Move Participants operation completed successfully.'); +// } catch (ex) { +// console.log(`Error in manual move participants operation: ${ex.message}`); +// } +// } +// }); + +// ws.on('close', () => { +// webSocket = null; +// }); +// }); + +app.get('/targetCallToAcsUser', async (req, res) => { + const acsTarget = req.query.acsTarget as string; // expects ?acsTarget= console.log('\n~~~~~~~~~~~~ /TargetCall(Create) ~~~~~~~~~~~~\n'); + if (!acsTarget) { + return res.status(400).send('Missing acsTarget query parameter'); + } + try { const callbackUri = `${callbackUriHost}/api/callbacks`; const callee : CommunicationUserIdentifier = { @@ -75,321 +160,65 @@ app.get('/TargetCallToAcsUser(Create)', async (req, res) => { } }); -app.get('/GetParticipants/:callConnectionId', async (req, res) => { - const callConnectionId = req.params.callConnectionId; - console.log(`\n~~~~~~~~~~~~ /GetParticipants/${callConnectionId} ~~~~~~~~~~~~\n`); - try { - const callConnection = acsClient.getCallConnection(callConnectionId); - const participantsResponse = await callConnection.getAllParticipant(); - const participants = participantsResponse.value; - - // Format participant info - const participantInfo = participants.map(p => { - let type = p.identifier.kind || p.identifier.constructor.name; - let rawId = p.identifier.rawId; - let phoneNumber = p.identifier.phoneNumber || null; - let acsUserId = p.identifier.communicationUserId || null; - - return { - rawId, - type, - phoneNumber, - acsUserId - }; - }); - - // Sort: phone numbers first, then ACS users - participantInfo.sort((a, b) => { - if (!a.acsUserId && b.acsUserId) return -1; - if (a.acsUserId && !b.acsUserId) return 1; - return 0; - }); - - // Format output - if (participantInfo.length === 0) { - return res.status(404).json({ - message: "No participants found for the specified call connection.", - callConnectionId - }); - } else { - let msg = `\nNo of Participants: ${participantInfo.length}\nParticipants: \n-------------\n`; - msg += participantInfo.map((p, i) => { - if (p.acsUserId) { - return `${i + 1}. ${p.type} - RawId: ${p.acsUserId}`; - } else { - return `${i + 1}. ${p.type} - RawId: ${p.rawId}, Phone: ${p.phoneNumber}`; - } - }).join('\n'); - console.log(msg); - return res.type('text/plain').send(msg); - } - } catch (ex) { - console.error(`Error getting participants for call ${callConnectionId}: ${ex.message}`); - return res.status(400).json({ - error: ex.message, - callConnectionId - }); - } -}); - -app.get('/userCallToCallAutomation', async (req, res) => { - console.log("--------- UserCallToCallAutomation - Call 1 API Endpoint -------------------"); - try { - const callbackUri = new URL('/api/callbacks', callbackUriHost).toString(); - const callee : PhoneNumberIdentifier = { - phoneNumber: acsInboundPhoneNumber - }; - const callInvite : CallInvite = { - targetParticipant: callee, - sourceCallIdNumber: { - phoneNumber: userPhoneNumber, - }, - }; - const options = { - callIntelligenceOptions: { - cognitiveServicesEndpoint: process.env.COGNITIVE_SERVICES_ENDPOINT - }, - operationContext: 'CallOne' - }; - var createCallResult = await acsClient.createCall(callInvite, callbackUri, options); - callConnectionId1 = createCallResult.callConnectionProperties.callConnectionId; - callerId1 = userPhoneNumber; - calleeId1 = acsInboundPhoneNumber; - - console.log("=== Call From User to Call Automation ==="); - console.log(`Created call from ${userPhoneNumber} to ${acsOutboundPhoneNumber}`); - console.log(`Connection ID: ${callConnectionId1}`); - console.log("=== END WORKFLOW INITIATION ==="); - } catch (err) { - console.error('Error creating call:', err); - } - res.redirect('/'); -}); - -app.get('/createCall2', async (req, res) => { - console.log('--------- createCall2 - Call 2 API Endpoint " -------------------'); - try { - const callbackUri = new URL('/api/callbacks', callbackUriHost).toString(); - const callee : PhoneNumberIdentifier = { - phoneNumber: acsOutboundPhoneNumber - }; - const callInvite : CallInvite = { - targetParticipant: callee, - sourceCallIdNumber: { - phoneNumber: acsInboundPhoneNumber, - }, - }; - const options = { - callIntelligenceOptions: { - cognitiveServicesEndpoint: process.env.COGNITIVE_SERVICES_ENDPOINT - }, - operationContext: 'CallTwo' - }; - var createCallResult = await acsClient.createCall(callInvite, callbackUri, options); - callConnectionId2 = createCallResult.callConnectionProperties.callConnectionId; - // Track this as Call 2 - lastWorkflowCallType = "CallTwo"; - callerId2 = acsInboundPhoneNumber; - calleeId2 = acsOutboundPhoneNumber; - - console.log('=== CALL TWO WORKFLOW INITIATED ==='); - console.log(`Created call from ${acsInboundPhoneNumber} to ${acsOutboundPhoneNumber}`); - console.log(`Connection ID: ${callConnectionId2}`); - console.log(`This call should trigger MoveParticipantEvent (Scenario 2) which will redirect to ACS user ${acsTestIdentity2}`); - console.log('Operation Context: CallTwo'); - console.log('=== END WORKFLOW INITIATION ==='); - } catch (err) { - console.error('Error creating call:', err); - } - res.redirect('/'); -}); - -app.get('/createCall3', async (req, res) => { - console.log('--------- createCall3 - Call 3 API Endpoint " -------------------'); - try { - const callbackUri = new URL('/api/callbacks', callbackUriHost).toString(); - const callee : PhoneNumberIdentifier = { - phoneNumber: acsOutboundPhoneNumber - }; - const callInvite : CallInvite = { - targetParticipant: callee, - sourceCallIdNumber: { - phoneNumber: acsInboundPhoneNumber, - }, - }; - const options = { - callIntelligenceOptions: { - cognitiveServicesEndpoint: process.env.COGNITIVE_SERVICES_ENDPOINT - }, - operationContext: 'CallThree' - }; - var createCallResult = await acsClient.createCall(callInvite, callbackUri, options); - callConnectionId3 = createCallResult.callConnectionProperties.callConnectionId; - // Track this as Call 2 - lastWorkflowCallType = "CallThree"; - callerId3 = acsInboundPhoneNumber; - calleeId3 = acsOutboundPhoneNumber; - - console.log('=== CALL THREE WORKFLOW INITIATED ==='); - console.log(`Created call from ${acsInboundPhoneNumber} to ${acsOutboundPhoneNumber}`); - console.log(`Connection ID: ${callConnectionId3}`); - console.log(`This call should trigger MoveParticipantEvent (Scenario 3) which will redirect to ACS user ${acsTestIdentity3}`); - console.log('Operation Context: CallThree'); - console.log('=== END WORKFLOW INITIATION ==='); - } catch (err) { - console.error('Error creating call:', err); - } - res.redirect('/'); -}); - -app.get('/moveParticipant2', async (req, res) => { - console.log('--------- MoveParticipant API End Point -------------------'); - - try { - const request = req.body; - console.log('=== MANUAL MOVE PARTICIPANT REQUESTED ==='); - console.log(`Source Connection ID: ${callConnectionId2}`); - console.log(`Target Connection ID: ${callConnectionId1}`); - console.log(`Participant to Move: ${acsOutboundPhoneNumber}`); - - // Get the target connection (where we want to move participants to) - const targetConnection = acsClient.getCallConnection(callConnectionId1); - - // Get participants from source connection for reference (optional) - const sourceConnection = acsClient.getCallConnection(callConnectionId2); - - // Create participant identifier based on the input - let participantToMove; - if (acsOutboundPhoneNumber.startsWith('+')) { - // Phone number - participantToMove = { phoneNumber: acsOutboundPhoneNumber }; - console.log(`Moving phone number participant: ${acsOutboundPhoneNumber}`); - } else if (acsOutboundPhoneNumber.startsWith('8:acs:')) { - // ACS Communication User - participantToMove = { communicationUserId: acsOutboundPhoneNumber }; - console.log(`Moving ACS user participant: ${acsOutboundPhoneNumber}`); - } else { - console.log("Invalid participant format. Use phone number (+1234567890) or ACS user ID (8:acs:...)"); - } - - // Prepare move participants options - const options : MoveParticipantsOptions = { - operationContext: "MoveParticipant2" - }; - - // Call the ACS SDK to move participants - await targetConnection.moveParticipants([participantToMove], callConnectionId2, options); - callConnectionId2 = ""; - callerId2 = ""; - calleeId2 = ""; - calleeId1 = acsTestIdentity2; - - // For demonstration, assume success - console.log('Move Participants operation completed successfully'); - console.log(`Moved ${acsTestIdentity2} from ${callConnectionId2} to ${callConnectionId1}`); - console.log('=== MOVE PARTICIPANTS OPERATION COMPLETE ==='); - } catch (err) { - console.error(`Error in manual move participant operation: ${err.message}`); - } - res.redirect('/'); -}); - -app.get('/moveParticipant3', async (req, res) => { - console.log('--------- MoveParticipant API End Point -------------------'); - - try { - const request = req.body; - console.log('=== MANUAL MOVE PARTICIPANT REQUESTED ==='); - console.log(`Source Connection ID: ${callConnectionId3}`); - console.log(`Target Connection ID: ${callConnectionId1}`); - console.log(`Participant to Move: ${acsOutboundPhoneNumber}`); - - // Get the target connection (where we want to move participants to) - const targetConnection = acsClient.getCallConnection(callConnectionId1); - - // Get participants from source connection for reference (optional) - const sourceConnection = acsClient.getCallConnection(callConnectionId3); - - // Create participant identifier based on the input - let participantToMove; - if (acsOutboundPhoneNumber.startsWith('+')) { - // Phone number - participantToMove = { phoneNumber: acsOutboundPhoneNumber }; - console.log(`Moving phone number participant: ${acsOutboundPhoneNumber}`); - } else if (acsOutboundPhoneNumber.startsWith('8:acs:')) { - // ACS Communication User - participantToMove = { communicationUserId: acsOutboundPhoneNumber }; - console.log(`Moving ACS user participant: ${acsOutboundPhoneNumber}`); - } else { - console.log("Invalid participant format. Use phone number (+1234567890) or ACS user ID (8:acs:...)"); - } - - // Prepare move participants options - const options : MoveParticipantsOptions = { - operationContext: "MoveParticipant3" - }; - - // Call the ACS SDK to move participants - await targetConnection.moveParticipants([participantToMove], callConnectionId3, options); - callConnectionId3 = ""; - callerId3 = ""; - calleeId3 = ""; - calleeId1 = acsTestIdentity3; - - // For demonstration, assume success - console.log('Move Participants operation completed successfully'); - console.log(`Moved ${acsTestIdentity3} from ${callConnectionId3} to ${callConnectionId1}`); - console.log('=== MOVE PARTICIPANTS OPERATION COMPLETE ==='); - } catch (err) { - console.error(`Error in manual move participant operation: ${err.message}`); - } - res.redirect('/'); -}); - -app.get('/terminateCalls', async (req, res) => { - console.log(`calls 1: ${callConnectionId1}, 2: ${callConnectionId2}, 3: ${callConnectionId3}`); - if (callConnectionId1) { +app.get('/call-data', async (req, res) => { + let participantId1 = ""; + let participantId2 = ""; + let participantId3 = ""; + if (lobbyCallConnectionId) { + console.log(`\n~~~~~~~~~~~~ /GetParticipants/${lobbyCallConnectionId} ~~~~~~~~~~~~\n`); try { - console.log(`Terminating Call 1 with ID: ${callConnectionId1}`); - const callConnection1 = acsClient.getCallConnection(callConnectionId1); - await callConnection1.hangUp(true); - } catch (error) { - console.error(`Error terminating Call 1: ${error.message}`); + const callConnection = acsClient.getCallConnection(lobbyCallConnectionId); + const participantsResponse = await callConnection.listParticipants(); + const participants = participantsResponse.values; + + if (participants.length === 0) { + console.log(`No participants found in call ${lobbyCallConnectionId}`); + } else if (participants.length === 1) { + participantId1 = participants[0].identifier.toString(); + } else if (participants.length === 2) { + participantId1 = participants[0].identifier.toString(); + participantId2 = participants[1].identifier.toString(); + } else if (participants.length === 3) { + participantId1 = participants[0].identifier.toString(); + participantId2 = participants[1].identifier.toString(); + participantId3 = participants[2].identifier.toString(); + } + } catch (ex) { + console.error(`Error getting participants for call ${lobbyCallConnectionId}: ${ex.message}`); } } - if (callConnectionId2) { + res.json({ participantId1, participantId2, participantId3 }); +}); + +app.get('/terminateCalls', async (req, res) => { + console.log(`calls 1: ${lobbyCallConnectionId}, 2: ${targetCallConnectionId}`); + if (lobbyCallConnectionId) { try { - console.log(`Terminating Call 2 with ID: ${callConnectionId2}`); - const callConnection2 = acsClient.getCallConnection(callConnectionId2); - await callConnection2.hangUp(true); + console.log(`Terminating Lobby Call with ID: ${lobbyCallConnectionId}`); + const lobbyConnection = acsClient.getCallConnection(lobbyCallConnectionId); + await lobbyConnection.hangUp(true); } catch (error) { - console.error(`Error terminating Call 2: ${error.message}`); + console.error(`Error terminating Lobby Call: ${error.message}`); } } - if (callConnectionId3) { + if (targetCallConnectionId) { try { - console.log(`Terminating Call 3 with ID: ${callConnectionId3}`); - const callConnection3 = acsClient.getCallConnection(callConnectionId3); - await callConnection3.hangUp(true); + console.log(`Terminating Target Call with ID: ${targetCallConnectionId}`); + const targetConnection = acsClient.getCallConnection(targetCallConnectionId); + await targetConnection.hangUp(true); } catch (error) { - console.error(`Error terminating Call 3: ${error.message}`); + console.error(`Error terminating Target Call: ${error.message}`); } } console.log("Calls hung up successfully."); - callConnectionId1 = ""; - callConnectionId2 = ""; - callConnectionId3 = ""; - callerId1 = ""; - callerId2 = ""; - callerId3 = ""; - calleeId1 = ""; - calleeId2 = ""; - calleeId3 = ""; + lobbyCallConnectionId = ""; + targetCallConnectionId = ""; + lobbyCallerId = ""; res.redirect('/'); }); -app.post('/api/moveParticipantEvent', async (req, res) => { - console.log('--------- /api/moveParticipantEvent -------------------'); +app.post('/api/lobbyCallSupportEventHandler', async (req, res) => { + console.log('--------- /api/lobbyCallSupportEventHandler -------------------'); const event = req.body[0]; const eventData = event.data; if (event.eventType === "Microsoft.EventGrid.SubscriptionValidationEvent") { @@ -408,59 +237,34 @@ app.post('/api/moveParticipantEvent', async (req, res) => { console.log(`From Caller Id: ${fromCallerId}`); console.log(`To Caller Id : ${toCallerId}`); - // Scenario 1: User calls from their phone number to ACS inbound number - if (fromCallerId.includes(userPhoneNumber)) { - console.log('=== SCENARIO 1: USER INCOMING CALL ==='); - - const callbackUri = new URL('/api/callbacks', callbackUriHost).toString(); - const options : AnswerCallOptions = { - operationContext: "CallOne" + // Lobby Call: Answer + if (toCallerId.includes(acsGeneratedId)) { + const callbackUri = `${callbackUriHost}/api/callbacks`; + const options = { + operationContext: 'LobbyCall', + callIntelligenceOptions: { + cognitiveServicesEndpoint: process.env.COGNITIVE_SERVICES_ENDPOINT + } }; - //console.log(`Incoming call context: ${eventData.incomingCallContext}`); - var answerCallResult = await acsClient.answerCall(eventData.incomingCallContext, callbackUri, options); - callConnectionId1 = answerCallResult.callConnectionProperties.callConnectionId; - - console.log(`User Call Answered - CallConnectionId: ${callConnectionId1}`); - console.log(`Correlation Id: ${eventData.correlationId}`); - console.log('Operation Context: CallOne'); - console.log('=== END SCENARIO 1 ==='); - } - // Scenario 2: ACS inbound number calls ACS outbound number (workflow triggered) - else if (fromCallerId.includes(acsInboundPhoneNumber)) { - console.log('=== SCENARIO 2: WORKFLOW CALL TO BE REDIRECTED ==='); - console.log(`Last Workflow Call Type: ${lastWorkflowCallType}`); - - // Check which type of workflow call this is and redirect accordingly - let redirectTarget; - if (lastWorkflowCallType === 'CallTwo') { - // Redirect the call to ACS User Identity 2 - redirectTarget = acsTestIdentity2; - const callee : CommunicationUserIdentifier = { - communicationUserId: redirectTarget - }; - const callInvite : CallInvite = { - targetParticipant: callee - }; - //console.log(`Incoming call context: ${eventData.incomingCallContext}`); - var redirectCallResult = await acsClient.redirectCall(eventData.incomingCallContext, callInvite); - console.log('PROCESSING CALL TWO - Redirecting to ACS User Identity 2'); - } else if (lastWorkflowCallType === 'CallThree') { - // Redirect the call to ACS User Identity 3 - redirectTarget = acsTestIdentity3; - const callee : CommunicationUserIdentifier = { - communicationUserId: redirectTarget - }; - const callInvite : CallInvite = { - targetParticipant: callee - }; - //console.log(`Incoming call context: ${eventData.incomingCallContext}`); - var redirectCallResult = await acsClient.redirectCall(eventData.incomingCallContext, callInvite); - console.log('PROCESSING CALL THREE - Redirecting to ACS User Identity 3'); - } - console.log('=== END SCENARIO 2 ==='); + const answerCallResult = await acsClient.answerCall( + eventData.incomingCallContext, + callbackUri, + options + ); + lobbyCallConnectionId = answerCallResult.callConnectionProperties.callConnectionId; + + console.log( + `User Call(Inbound) Answered by Call Automation.`, + `From Caller Raw Id: ${fromCallerId}`, + `To Caller Raw Id: ${toCallerId}`, + `Lobby Call Connection Id: ${lobbyCallConnectionId}`, + `Correlation Id: ${eventData.correlationId}`, + `Lobby Call answered successfully.` + ); } } + res.status(200).send(); }); @@ -471,43 +275,64 @@ app.post('/api/callbacks', async (req, res) => { // For demonstration, log the event type and IDs console.log(`Received call event: ${event.type}`); console.log(`Correlation id:-> ${eventData.correlationId}`) + if (event.type === "Microsoft.Communication.CallConnected") { console.log('\n--------- CallConnected Event Block -------------------'); - switch (eventData.operationContext) { - case 'CallOne': - //callConnectionId1 = callConnectionId; - console.log('=== CALL ONE CONNECTED ==='); - console.log('User call connected'); - console.log('=== END CALL ONE CONNECTED ==='); - break; - case 'CallTwo': - //callConnectionId2 = callConnectionId; - calleeId2 = acsTestIdentity2; - console.log('=== CALL TWO CONNECTED ==='); - console.log('User call connected'); - console.log('=== END CALL TWO CONNECTED ==='); - break; - case 'CallThree': - //callConnectionId3 = callConnectionId; - calleeId3 = acsTestIdentity3; - console.log('=== CALL THREE CONNECTED ==='); - console.log('User call connected'); - console.log('=== END CALL THREE CONNECTED ==='); - break; + + if ((eventData.operationContext || '') === 'LobbyCall') { + console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); + console.log(`Received call event : ${event.type}`); + console.log(`Lobby Call Connection Id: ${eventData.callConnectionId}`); + console.log(`Correlation Id: ${eventData.correlationId}`); + + // Record lobby caller id and connection id + const lobbyCallConnection = acsClient.getCallConnection(eventData.callConnectionId); + const callConnectionProperties = await lobbyCallConnection.getCallConnectionProperties(); + lobbyCallerId = getIdentifierRawId(callConnectionProperties.source); + lobbyCallConnectionId = callConnectionProperties.callConnectionId; + console.log(`Lobby Caller Id: ${lobbyCallerId}`); + console.log(`Lobby Connection Id: ${lobbyCallConnectionId}`); + + // Play lobby waiting message + const callMedia = acsClient.getCallConnection(eventData.callConnectionId).getCallMedia(); + const textSource: TextSource = { + text: "You are currently in a lobby call, we will notify the admin that you are waiting.", + voiceName: "en-US-NancyNeural", + kind: "textSource", + }; + const playTo: CommunicationUserIdentifier[] = [{ communicationUserId: lobbyCallerId }]; + const playOptions: PlayOptions = { + operationContext: "playToContext", + }; + await callMedia.play([textSource], playTo, playOptions); } - } else if (event.type === 'Microsoft.Communication.CallDisconnected') { - console.log(`Call disconnected: ${eventData.callConnectionId}`); - } else { - // Log other events but don't process them for Move Participants scenario - console.log(`Received event: ${event.type} - No action needed for Move Participants scenario`); + } else if (event.type === "Microsoft.Communication.PlayCompleted") { + console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); + console.log(`Received event: ${event.type}`); + + // // Notify Target Call user via websocket + // if (!webSocket || webSocket.readyState !== 1) { // 1 = OPEN + // console.log("ERROR: Web socket is not available."); + // return res.status(404).send("Message sent"); + // } + + const confirmMessageToTargetCall = "A user is waiting in lobby, do you want to add the user to your call?"; + // // Notify Client + // webSocket.send(confirmMessageToTargetCall); + console.log(`Target Call notified with message: ${confirmMessageToTargetCall}`); + return res.status(200).send(`Target Call notified with message: ${confirmMessageToTargetCall}`); + } else if (event.type === "Microsoft.Communication.MoveParticipantsSucceeded") { + console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); + console.log(`Received event: ${event.type}`); + console.log(`Call Connection Id: ${eventData.callConnectionId}`); + console.log(`Correlation Id: ${eventData.correlationId}`); + } else if (event.type === "Microsoft.Communication.CallDisconnected") { + console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); + console.log(`Received event: ${event.type}`); + console.log(`Call Connection Id: ${eventData.callConnectionId}`); } - res.status(200).send(); -}); -app.get('/call-data', (req, res) => { - console.log("Call Data Endpoint Hit"); - console.log(`call 1: ${callConnectionId1}, call 2: ${callConnectionId2}, call 3: ${callConnectionId3}`); - res.json({ callConnectionId1, callConnectionId2, callConnectionId3, callerId1, callerId2, callerId3, calleeId1, calleeId2, calleeId3 }); + res.status(200).send(); }); // GET endpoint to serve the webpage diff --git a/callautomation-lobbycall-sample/src/app.ts.xxx b/callautomation-lobbycall-sample/src/app.ts.xxx deleted file mode 100644 index 1cc06e64..00000000 --- a/callautomation-lobbycall-sample/src/app.ts.xxx +++ /dev/null @@ -1,277 +0,0 @@ -import { config } from 'dotenv'; -import express, { Application } from 'express'; -import { CommunicationUserIdentifier, PhoneNumberIdentifier } from "@azure/communication-common"; -import { - CallAutomationClient, - CallInvite, - AnswerCallOptions, - MoveParticipantsOptions -} from "@azure/communication-call-automation"; - -config(); - -const PORT = process.env.PORT; -const app: Application = express(); -app.use(express.static('webpage')); -app.use(express.urlencoded({ extended: true })); -app.use(express.json()); - -let lobbyCallConnectionId: string; -let targetCallConnectionId: string; -let acsGeneratedId: string; -let acsClient: CallAutomationClient; -let lobbyCallerId: string; -const callbackUriHost = process.env.CALLBACK_URI || ""; -const connectionString = process.env.CONNECTION_STRING || "" -const endpoint = process.env.PMA_ENDPOINT || "" - -async function createAcsClient() { - lobbyCallConnectionId = ""; - targetCallConnectionId = ""; - acsGeneratedId = process.env.ACS_GENERATED_ID || ""; - lobbyCallerId = ""; - // acsClient = new CallAutomationClient(endpoint, connectionString); - acsClient = new CallAutomationClient(connectionString); - console.log("Initialized ACS Client."); -} - -app.get('/TargetCallToAcsUser(Create)', async (req, res) => { - const acsTarget = req.body.acsTarget; // expects { "acsTarget": "" } - console.log('\n~~~~~~~~~~~~ /TargetCall(Create) ~~~~~~~~~~~~\n'); - - try { - const callbackUri = `${callbackUriHost}/api/callbacks`; - const callInvite = new CommunicationUserIdentifier(acsTarget); - const createCallOptions = { - callInvite, - callbackUri, - callIntelligenceOptions: { - cognitiveServicesEndpoint: 'https://cognitive-service-waferwire.cognitiveservices.azure.com/' - } - }; - - const createCallResult = await acsClient.createCall(createCallOptions); - targetCallConnectionId = createCallResult.callConnectionProperties.callConnectionId; - - const logMsg = ` - TargetCall: - ----------- - From: Call Automation - To: ${acsTarget} - Target Call Connection Id: ${targetCallConnectionId} - Correlation Id: ${createCallResult.callConnectionProperties.correlationId} - `; - console.log(logMsg); - res.type('text/plain').send(logMsg); - } catch (err) { - console.error('Error creating call:', err); - res.status(500).send('Error creating call: ' + err.message); - } -}); - -app.get('/GetParticipants/:callConnectionId', async (req, res) => { - const callConnectionId = req.params.callConnectionId; - console.log(`\n~~~~~~~~~~~~ /GetParticipants/${callConnectionId} ~~~~~~~~~~~~\n`); - try { - const callConnection = acsClient.getCallConnection(callConnectionId); - const participantsResponse = await callConnection.getParticipants(); - const participants = participantsResponse.value; - - // Format participant info - const participantInfo = participants.map(p => { - let type = p.identifier.kind || p.identifier.constructor.name; - let rawId = p.identifier.rawId; - let phoneNumber = p.identifier.phoneNumber || null; - let acsUserId = p.identifier.communicationUserId || null; - - return { - rawId, - type, - phoneNumber, - acsUserId - }; - }); - - // Sort: phone numbers first, then ACS users - participantInfo.sort((a, b) => { - if (!a.acsUserId && b.acsUserId) return -1; - if (a.acsUserId && !b.acsUserId) return 1; - return 0; - }); - - // Format output - if (participantInfo.length === 0) { - return res.status(404).json({ - message: "No participants found for the specified call connection.", - callConnectionId - }); - } else { - let msg = `\nNo of Participants: ${participantInfo.length}\nParticipants: \n-------------\n`; - msg += participantInfo.map((p, i) => { - if (p.acsUserId) { - return `${i + 1}. ${p.type} - RawId: ${p.acsUserId}`; - } else { - return `${i + 1}. ${p.type} - RawId: ${p.rawId}, Phone: ${p.phoneNumber}`; - } - }).join('\n'); - console.log(msg); - return res.type('text/plain').send(msg); - } - } catch (ex) { - console.error(`Error getting participants for call ${callConnectionId}: ${ex.message}`); - return res.status(400).json({ - error: ex.message, - callConnectionId - }); - } -}); - -app.get('/terminateCalls', async (req, res) => { - console.log(`calls 1: ${lobbyCallConnectionId}, 2: ${targetCallConnectionId}`); - if (lobbyCallConnectionId) { - try { - console.log(`Terminating Lobby Call with ID: ${lobbyCallConnectionId}`); - const lobbyConnection = acsClient.getCallConnection(lobbyCallConnectionId); - await lobbyConnection.hangUp(true); - } catch (error) { - console.error(`Error terminating Lobby Call: ${error.message}`); - } - } - if (targetCallConnectionId) { - try { - console.log(`Terminating Target Call with ID: ${targetCallConnectionId}`); - const targetConnection = acsClient.getCallConnection(targetCallConnectionId); - await targetConnection.hangUp(true); - } catch (error) { - console.error(`Error terminating Target Call: ${error.message}`); - } - } - console.log("Calls hung up successfully."); - lobbyCallConnectionId = ""; - targetCallConnectionId = ""; - lobbyCallerId = ""; - res.redirect('/'); -}); - -app.post('/api/LobbyCallSupportEventHandler', async (req, res) => { - console.log('--------- /api/moveParticipantEvent -------------------'); - const event = req.body[0]; - const eventData = event.data; - if (event.eventType === "Microsoft.EventGrid.SubscriptionValidationEvent") { - console.log("SubscriptionValidation event"); - res.status(200).json({ - validationResponse: eventData.validationCode, - }); - return; - } - - // ACS Incoming Call event - if (event.eventType === 'Microsoft.Communication.IncomingCall') { - const fromCallerId = eventData.from.rawId; - const toCallerId = eventData.to.rawId; - - console.log(`From Caller Id: ${fromCallerId}`); - console.log(`To Caller Id : ${toCallerId}`); - - // Lobby Call: Answer - if (toCallerId.includes(acsGeneratedId)) { - const callbackUri = `${callbackUriHost}/api/callbacks`; - const options = { - incomingCallContext: eventData.incomingCallContext, - callbackUri: callbackUri, - operationContext: 'LobbyCall', - callIntelligenceOptions: { - cognitiveServicesEndpoint: process.env.COGNITIVE_SERVICES_ENDPOINT - } - }; - - const answerCallResult = await acsClient.answerCall(options); - lobbyCallConnectionId = answerCallResult.callConnectionProperties.callConnectionId; - - console.log( - `User Call(Inbound) Answered by Call Automation.`, - `From Caller Raw Id: ${fromCallerId}`, - `To Caller Raw Id: ${toCallerId}`, - `Lobby Call Connection Id: ${lobbyCallConnectionId}`, - `Correlation Id: ${eventData.correlationId}`, - `Lobby Call answered successfully.` - ); - } - } - - res.status(200).send(); -}); - -app.post('/api/callbacks', async (req, res) => { - console.log('--------- /api/callbacks -------------------'); - const event = req.body[0]; - const eventData = event.data; - // For demonstration, log the event type and IDs - console.log(`Received call event: ${event.type}`); - console.log(`Correlation id:-> ${eventData.correlationId}`) - - if (event.type === "Microsoft.Communication.CallConnected") { - console.log('\n--------- CallConnected Event Block -------------------'); - - if ((eventData.operationContext || '') === 'LobbyCall') { - console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); - console.log(`Received call event : ${event.type}`); - console.log(`Lobby Call Connection Id: ${eventData.callConnectionId}`); - console.log(`Correlation Id: ${eventData.correlationId}`); - - // Record lobby caller id and connection id - const lobbyCallConnection = acsClient.getCallConnection(eventData.callConnectionId); - const callConnectionProperties = await lobbyCallConnection.getCallConnectionProperties(); - lobbyCallerId = callConnectionProperties.source.rawId; - lobbyCallConnectionId = callConnectionProperties.callConnectionId; - console.log(`Lobby Caller Id: ${lobbyCallerId}`); - console.log(`Lobby Connection Id: ${lobbyCallConnectionId}`); - - // Play lobby waiting message - const callMedia = acsClient.getCallConnection(eventData.callConnectionId).getCallMedia(); - const textSource = new TextSource("You are currently in a lobby call, we will notify the admin that you are waiting."); - textSource.voiceName = "en-US-NancyNeural"; - const playTo = [new CommunicationUserIdentifier(acsIdentity)]; - const playToOptions = new PlayOptions({ playSource: textSource, playTo }); - playToOptions.operationContext = "playToContext"; - await callMedia.play(playToOptions); - } - } else if (event.type === "Microsoft.Communication.PlayCompleted") { - console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); - console.log(`Received event: ${event.type}`); - - // Notify Target Call user via websocket - if (!webSocket || webSocket.readyState !== 1) { // 1 = OPEN - console.log("ERROR: Web socket is not available."); - return res.status(404).send("Message sent"); - } - - const confirmMessageToTargetCall = "A user is waiting in lobby, do you want to add the user to your call?"; - // Notify Client - webSocket.send(confirmMessageToTargetCall); - console.log(`Target Call notified with message: ${confirmMessageToTargetCall}`); - return res.status(200).send(`Target Call notified with message: ${confirmMessageToTargetCall}`); - } else if (event.type === "Microsoft.Communication.MoveParticipantsSucceeded") { - console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); - console.log(`Received event: ${event.type}`); - console.log(`Call Connection Id: ${eventData.callConnectionId}`); - console.log(`Correlation Id: ${eventData.correlationId}`); - } else if (event.type === "Microsoft.Communication.CallDisconnected") { - console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); - console.log(`Received event: ${event.type}`); - console.log(`Call Connection Id: ${eventData.callConnectionId}`); - } - - res.status(200).send(); -}); - -// GET endpoint to serve the webpage -app.get('/', (req, res) => { - res.sendFile('index.html', { root: 'src/webpage' }); -}); - -// Start the server -app.listen(PORT, async () => { - console.log(`Server is listening on port ${PORT}`); - await createAcsClient(); -}); diff --git a/callautomation-lobbycall-sample/src/webpage/index.html b/callautomation-lobbycall-sample/src/webpage/index.html index 30f53350..df1bd9f0 100644 --- a/callautomation-lobbycall-sample/src/webpage/index.html +++ b/callautomation-lobbycall-sample/src/webpage/index.html @@ -33,58 +33,38 @@

Lobby Call Sample

STEP 1. Configure Webhook
-
Configure Event Grid webhook to point to /api/MoveParticipantEvent endpoint
+
Configure Event Grid webhook to point to /api/lobbyCallSupportEventHandler endpoint

-

STEP 2. Make a Call
-
Make a call from User Phone Number to ACS Inbound Phone Number by clicking on this button
- +
STEP 2. Configure a Lobby Call
+
Make a Lobby call from Web Client App to ACS Generated ACS Identity manually. Once done, lobby call will be in a waiting state.

-

STEP 3a. Create Call 2
-
Create a Call for ACS Test Identity 2 by clicking on this button and answer it manually from Web Client App
- +
STEP 3. Create User Call
+
Create a Call for ACS Identity by clicking on this button and answer it manually from Web Client App
+

-

STEP 3b. Create Call 3
-
Create a Call for ACS Test Identity 3 by clicking on this button and answer it manually from Web Client App
- +
STEP 4. Answer User Call
+
Once User call is connected, a message is played in Lobby asking to answer the User's call. You can accept it or reject it. Accept it manually from Web Client App. Now User is connected to Lobby call.

-

STEP 4a. Move Call
-
Move Call for ACS Test Identity 2 to Initial Call
- +
STEP 5. Get Participants List in Lobby Call
+
The list of all the participants in the Lobby call are automatically refreshed on the right panel.

-

STEP 4b. Move Call
-
Move Call for ACS Test Identity 3 to Initial Call
- -

-

-

STEP 5. Terminate Calls
+
STEP 6. Terminate Calls
Terminate all Calls created so far

-
-
Call Connection 1
-
Call Connection Id: Loading call Id...
-
Caller Id: Loading caller Id...
-
Callee Id: Loading callee Id...
+
+
Lobby Call Info
+
Participant Id 1: Loading participant Id...
+
Participant Id 2: Loading participant Id...
+
Participant Id 3: Loading participant Id...
-

-

Call Connection 2
-
Call Connection Id: Loading call Id...
-
Caller Id: Loading caller Id...
-
Callee Id: Loading callee Id...
-

-

-

Call Connection 3
-
Call Connection Id: Loading call Id...
-
Caller Id: Loading caller Id...
-
Callee Id: Loading callee Id...
-

@@ -97,29 +77,16 @@

Lobby Call Sample

fetch('/call-data') .then(response => response.json()) .then(data => { - console.log('Call Connection Id 1:', data.callConnectionId1); - console.log('Call Connection Id 2:', data.callConnectionId2); - console.log('Call Connection Id 3:', data.callConnectionId3); - if (data.callConnectionId1) document.getElementById('callIdA-text').innerText = `${data.callConnectionId1}`; - if (data.callerId1) document.getElementById('callerIdA-text').innerText = `${data.callerId1}`; - if (data.calleeId1) document.getElementById('calleeIdA-text').innerText = `${data.calleeId1}`; - if (data.callConnectionId2) document.getElementById('callIdB-text').innerText = `${data.callConnectionId2}`; - if (data.callerId2) document.getElementById('callerIdB-text').innerText = `${data.callerId2}`; - if (data.calleeId2) document.getElementById('calleeIdB-text').innerText = `${data.calleeId2}`; - if (data.callConnectionId3) document.getElementById('callIdC-text').innerText = `${data.callConnectionId3}`; - if (data.callerId3) document.getElementById('callerIdC-text').innerText = `${data.callerId3}`; - if (data.calleeId3) document.getElementById('calleeIdC-text').innerText = `${data.calleeId3}`; - document.querySelector('input[formaction="/moveParticipant2"]').disabled = true; - document.querySelector('input[formaction="/moveParticipant3"]').disabled = true; - document.querySelector('input[formaction="/terminateCalls"]').disabled = true; - if (data.callConnectionId1 && data.callConnectionId2) { - document.querySelector('input[formaction="/moveParticipant2"]').disabled = false; - } - if (data.callConnectionId1 && data.callConnectionId3) { - document.querySelector('input[formaction="/moveParticipant3"]').disabled = false; - } - if (data.callConnectionId1 || data.callConnectionId2 || data.callConnectionId3) { + console.log('Participant Id 1:', data.participantId1); + console.log('Participant Id 2:', data.participantId2); + console.log('Participant Id 3:', data.participantId3); + if (data.participantId1) document.getElementById('pIdA-text').innerText = `${data.participantId1}`; + if (data.participantId2) document.getElementById('pIdB-text').innerText = `${data.participantId2}`; + if (data.participantId3) document.getElementById('pIdC-text').innerText = `${data.participantId3}`; + if (data.participantId1) { document.querySelector('input[formaction="/terminateCalls"]').disabled = false; + } else { + document.querySelector('input[formaction="/terminateCalls"]').disabled = true; } }) .catch(error => { From 92ef4159949051070ae049732d7bec04ef34d67f Mon Sep 17 00:00:00 2001 From: nageshy Date: Mon, 28 Jul 2025 11:21:36 +0530 Subject: [PATCH 06/12] Updated code --- callautomation-lobbycall-sample/README.md | 2 +- callautomation-lobbycall-sample/src/app.ts | 2 +- .../src/webpage/index.html | 39 ++++++++++++++++--- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/callautomation-lobbycall-sample/README.md b/callautomation-lobbycall-sample/README.md index 22595677..9bc2b95d 100644 --- a/callautomation-lobbycall-sample/README.md +++ b/callautomation-lobbycall-sample/README.md @@ -3,7 +3,7 @@ |---|---|---| |sample|
Typescript
|
azureazure-communication-services
| -# Lobbay Call Sample using Call Automation SDK +# Lobby Call Sample using Call Automation SDK In this quickstart sample, we cover how you can use the Call Automation SDK to perform lobby calls using Azure Communication Services (ACS) calls. This involves creating and managing several outgoing calls simultaneously and dynamically moving participants between these active calls. diff --git a/callautomation-lobbycall-sample/src/app.ts b/callautomation-lobbycall-sample/src/app.ts index 3b2114c1..a24bb6a6 100644 --- a/callautomation-lobbycall-sample/src/app.ts +++ b/callautomation-lobbycall-sample/src/app.ts @@ -160,7 +160,7 @@ app.get('/targetCallToAcsUser', async (req, res) => { } }); -app.get('/call-data', async (req, res) => { +app.get('/getParticipants', async (req, res) => { let participantId1 = ""; let participantId2 = ""; let participantId3 = ""; diff --git a/callautomation-lobbycall-sample/src/webpage/index.html b/callautomation-lobbycall-sample/src/webpage/index.html index df1bd9f0..0b876792 100644 --- a/callautomation-lobbycall-sample/src/webpage/index.html +++ b/callautomation-lobbycall-sample/src/webpage/index.html @@ -41,8 +41,12 @@

Lobby Call Sample

STEP 3. Create User Call
-
Create a Call for ACS Identity by clicking on this button and answer it manually from Web Client App
- +
Create a Call for ACS Identity by entering the target ACS User ID and clicking the button. Answer it manually from Web Client App
+
+
+ +
+

STEP 4. Answer User Call
@@ -73,8 +77,31 @@

Lobby Call Sample

let fetchInterval; let fetchCount = 0; - function fetchCallData() { - fetch('/call-data') + function createTargetCall() { + const acsTarget = document.getElementById('acsTarget').value.trim(); + + if (!acsTarget) { + alert('Please enter an ACS Target User ID'); + return; + } + + // Call the API endpoint with the query parameter + fetch(`/TargetCallToAcsUser(Create)?acsTarget=${encodeURIComponent(acsTarget)}`) + .then(response => response.text()) + .then(data => { + console.log('API Response:', data); + alert('Call created successfully!'); + // Optionally refresh the call data + fetchParticipantData(); + }) + .catch(error => { + console.error('Error creating call:', error); + alert('Error creating call: ' + error.message); + }); + } + + function fetchParticipantData() { + fetch('/getParticipants') .then(response => response.json()) .then(data => { console.log('Participant Id 1:', data.participantId1); @@ -98,7 +125,7 @@

Lobby Call Sample

fetchCount++; console.log(`Periodic fetch #${fetchCount}`); - fetchCallData(); + fetchParticipantData(); } function startPeriodicFetch() { @@ -113,7 +140,7 @@

Lobby Call Sample

} // Initial fetch on page load - fetchCallData(); + fetchParticipantData(); // Add event listener to all form submit buttons document.addEventListener('DOMContentLoaded', () => { From 42483ddb725c7cd1a040dec388f4ff39204f04e7 Mon Sep 17 00:00:00 2001 From: nageshy Date: Mon, 28 Jul 2025 11:33:16 +0530 Subject: [PATCH 07/12] updated code --- callautomation-lobbycall-sample/README.md | 2 +- callautomation-lobbycall-sample/src/webpage/index.html | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/callautomation-lobbycall-sample/README.md b/callautomation-lobbycall-sample/README.md index 9bc2b95d..aec8a2d9 100644 --- a/callautomation-lobbycall-sample/README.md +++ b/callautomation-lobbycall-sample/README.md @@ -1,7 +1,7 @@ |page_type|languages|products |---|---|---| -|sample|
Typescript
|
azureazure-communication-services
| +|sample|
Typescript
|
azureazure-communication-services
| # Lobby Call Sample using Call Automation SDK diff --git a/callautomation-lobbycall-sample/src/webpage/index.html b/callautomation-lobbycall-sample/src/webpage/index.html index 0b876792..3cd8bc6f 100644 --- a/callautomation-lobbycall-sample/src/webpage/index.html +++ b/callautomation-lobbycall-sample/src/webpage/index.html @@ -37,7 +37,7 @@

Lobby Call Sample

STEP 2. Configure a Lobby Call
-
Make a Lobby call from Web Client App to ACS Generated ACS Identity manually. Once done, lobby call will be in a waiting state.
+
Make a Lobby call from Web Client App to ACS Generated Identity manually. Once done, lobby call will be in a waiting state.

STEP 3. Create User Call
@@ -86,7 +86,7 @@

Lobby Call Sample

} // Call the API endpoint with the query parameter - fetch(`/TargetCallToAcsUser(Create)?acsTarget=${encodeURIComponent(acsTarget)}`) + fetch(`/targetCallToAcsUser?acsTarget=${encodeURIComponent(acsTarget)}`) .then(response => response.text()) .then(data => { console.log('API Response:', data); From b04554ebfda092a881dda861f416d34a6ef59159 Mon Sep 17 00:00:00 2001 From: nageshy Date: Mon, 28 Jul 2025 13:54:50 +0530 Subject: [PATCH 08/12] updated code --- callautomation-lobbycall-sample/package.json | 4 +- callautomation-lobbycall-sample/src/app.ts | 172 +++++++++--------- .../src/webpage/index.html | 2 +- 3 files changed, 90 insertions(+), 88 deletions(-) diff --git a/callautomation-lobbycall-sample/package.json b/callautomation-lobbycall-sample/package.json index d49147a0..31ae0036 100644 --- a/callautomation-lobbycall-sample/package.json +++ b/callautomation-lobbycall-sample/package.json @@ -18,8 +18,10 @@ "@azure/eventgrid": "^4.12.0", "@types/express": "^4.17.17", "@types/node": "^20.2.1", + "@types/ws": "^8.18.1", "dotenv": "^16.0.3", - "express": "^4.18.2" + "express": "^4.18.2", + "ws": "^8.18.3" }, "devDependencies": { "nodemon": "^2.0.22", diff --git a/callautomation-lobbycall-sample/src/app.ts b/callautomation-lobbycall-sample/src/app.ts index a24bb6a6..73a8d47d 100644 --- a/callautomation-lobbycall-sample/src/app.ts +++ b/callautomation-lobbycall-sample/src/app.ts @@ -8,6 +8,8 @@ import { PlayOptions, MoveParticipantsOptions } from "@azure/communication-call-automation"; +import * as http from 'http'; +import * as WebSocket from 'ws'; config(); @@ -25,7 +27,7 @@ let lobbyCallerId: string; const callbackUriHost = process.env.CALLBACK_URI || ""; const connectionString = process.env.CONNECTION_STRING || "" const endpoint = process.env.PMA_ENDPOINT || "" -// let webSocket = null; +let webSocket = null; async function createAcsClient() { lobbyCallConnectionId = ""; @@ -37,84 +39,82 @@ async function createAcsClient() { console.log("Initialized ACS Client."); } -const http = require('http'); -// const WebSocket = require('ws'); -// const server = http.createServer(app); +const server = http.createServer(app); // WebSocket server setup -// const wss = new WebSocket.Server({ noServer: true }); - -// server.on('upgrade', (request, socket, head) => { -// // Only accept connections to the correct path -// const url = request.url || ''; -// if (url === `/ws/${process.env.SOCKET_TOKEN}`) { -// wss.handleUpgrade(request, socket, head, function done(ws) { -// wss.emit('connection', ws, request); -// }); -// } else { -// socket.destroy(); -// } -// }); - -// wss.on('connection', (ws) => { -// webSocket = ws; -// console.log('Received WEB SOCKET request.'); - -// ws.on('message', async (message) => { -// const jsResponse = message.toString(); -// console.log(`Received from JS: ${jsResponse}`); - -// // Move participant to target call if response is "yes" -// if (jsResponse.trim().toLowerCase() === 'yes') { -// console.log('TODO: Move Participant'); -// try { -// console.log(` -// ~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~ -// Move Participant operation started.. -// Source Caller Id: ${lobbyCallerId} -// Source Connection Id: ${lobbyCallConnectionId} -// Target Connection Id: ${targetCallConnectionId} -// `); - -// // Get the target connection -// const targetConnection = acsClient.getCallConnection(targetCallConnectionId); - -// // Get participants from source connection for reference -// // const sourceConnection = client.getCallConnection(lobbyConnectionId); - -// // Create participant identifier based on the input -// let participantToMove; -// if (lobbyCallerId.startsWith('+')) { -// // Phone number -// participantToMove = { phoneNumber: lobbyCallerId }; -// console.log(`Moving phone number participant: ${lobbyCallerId}`); -// } else if (lobbyCallerId.startsWith('8:acs:')) { -// // ACS Communication User -// participantToMove = { communicationUserId: lobbyCallerId }; -// console.log(`Moving ACS user participant: ${lobbyCallerId}`); -// } else { -// console.log("Invalid participant format. Use phone number (+1234567890) or ACS user ID (8:acs:...)"); -// } - -// // Prepare move participants options -// const options : MoveParticipantsOptions = { -// operationContext: "MoveParticipant2" -// }; - -// // Call the ACS SDK to move participants -// await targetConnection.moveParticipants([participantToMove], lobbyCallConnectionId, options); - -// console.log('Move Participants operation completed successfully.'); -// } catch (ex) { -// console.log(`Error in manual move participants operation: ${ex.message}`); -// } -// } -// }); - -// ws.on('close', () => { -// webSocket = null; -// }); -// }); +const wss = new WebSocket.Server({ noServer: true }); + +server.on('upgrade', (request, socket, head) => { + // Only accept connections to the correct path + const url = request.url || ''; + if (url === `/ws/${process.env.SOCKET_TOKEN}`) { + wss.handleUpgrade(request, socket, head, function done(ws) { + wss.emit('connection', ws, request); + }); + } else { + socket.destroy(); + } +}); + +wss.on('connection', (ws) => { + webSocket = ws; + console.log('Received WEB SOCKET request.'); + + ws.on('message', async (message) => { + const jsResponse = message.toString(); + console.log(`Received from JS: ${jsResponse}`); + + // Move participant to target call if response is "yes" + if (jsResponse.trim().toLowerCase() === 'yes') { + console.log('TODO: Move Participant'); + try { + console.log(` + ~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~ + Move Participant operation started.. + Source Caller Id: ${lobbyCallerId} + Source Connection Id: ${lobbyCallConnectionId} + Target Connection Id: ${targetCallConnectionId} + `); + + // Get the target connection + const targetConnection = acsClient.getCallConnection(targetCallConnectionId); + + // Get participants from source connection for reference + // const sourceConnection = client.getCallConnection(lobbyConnectionId); + + // Create participant identifier based on the input + let participantToMove; + if (lobbyCallerId.startsWith('+')) { + // Phone number + participantToMove = { phoneNumber: lobbyCallerId }; + console.log(`Moving phone number participant: ${lobbyCallerId}`); + } else if (lobbyCallerId.startsWith('8:acs:')) { + // ACS Communication User + participantToMove = { communicationUserId: lobbyCallerId }; + console.log(`Moving ACS user participant: ${lobbyCallerId}`); + } else { + console.log("Invalid participant format. Use phone number (+1234567890) or ACS user ID (8:acs:...)"); + } + + // Prepare move participants options + const options : MoveParticipantsOptions = { + operationContext: "MoveParticipant2" + }; + + // Call the ACS SDK to move participants + await targetConnection.moveParticipants([participantToMove], lobbyCallConnectionId, options); + + console.log('Move Participants operation completed successfully.'); + } catch (ex) { + console.log(`Error in manual move participants operation: ${ex.message}`); + } + } + }); + + ws.on('close', () => { + webSocket = null; + }); +}); app.get('/targetCallToAcsUser', async (req, res) => { const acsTarget = req.query.acsTarget as string; // expects ?acsTarget= @@ -217,8 +217,8 @@ app.get('/terminateCalls', async (req, res) => { res.redirect('/'); }); -app.post('/api/lobbyCallSupportEventHandler', async (req, res) => { - console.log('--------- /api/lobbyCallSupportEventHandler -------------------'); +app.post('/api/lobbyCallEventHandler', async (req, res) => { + console.log('--------- /api/lobbyCallEventHandler -------------------'); const event = req.body[0]; const eventData = event.data; if (event.eventType === "Microsoft.EventGrid.SubscriptionValidationEvent") { @@ -310,15 +310,15 @@ app.post('/api/callbacks', async (req, res) => { console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); console.log(`Received event: ${event.type}`); - // // Notify Target Call user via websocket - // if (!webSocket || webSocket.readyState !== 1) { // 1 = OPEN - // console.log("ERROR: Web socket is not available."); - // return res.status(404).send("Message sent"); - // } + // Notify Target Call user via websocket + if (!webSocket || webSocket.readyState !== 1) { // 1 = OPEN + console.log("ERROR: Web socket is not available."); + return res.status(404).send("Message sent"); + } const confirmMessageToTargetCall = "A user is waiting in lobby, do you want to add the user to your call?"; - // // Notify Client - // webSocket.send(confirmMessageToTargetCall); + // Notify Client + webSocket.send(confirmMessageToTargetCall); console.log(`Target Call notified with message: ${confirmMessageToTargetCall}`); return res.status(200).send(`Target Call notified with message: ${confirmMessageToTargetCall}`); } else if (event.type === "Microsoft.Communication.MoveParticipantsSucceeded") { diff --git a/callautomation-lobbycall-sample/src/webpage/index.html b/callautomation-lobbycall-sample/src/webpage/index.html index 3cd8bc6f..2c1b44e0 100644 --- a/callautomation-lobbycall-sample/src/webpage/index.html +++ b/callautomation-lobbycall-sample/src/webpage/index.html @@ -33,7 +33,7 @@

Lobby Call Sample

STEP 1. Configure Webhook
-
Configure Event Grid webhook to point to /api/lobbyCallSupportEventHandler endpoint
+
Configure Event Grid webhook to point to /api/lobbyCallEventHandler endpoint

STEP 2. Configure a Lobby Call
From 954c348ae474a2cd020af269f37a85c1adc9e08a Mon Sep 17 00:00:00 2001 From: nageshy Date: Tue, 29 Jul 2025 13:33:06 +0530 Subject: [PATCH 09/12] Updated code --- callautomation-lobbycall-sample/README.md | 6 +- callautomation-lobbycall-sample/src/app.ts | 182 +++++++++++++++--- .../src/webpage/index.html | 4 +- 3 files changed, 158 insertions(+), 34 deletions(-) diff --git a/callautomation-lobbycall-sample/README.md b/callautomation-lobbycall-sample/README.md index aec8a2d9..c1a88c8d 100644 --- a/callautomation-lobbycall-sample/README.md +++ b/callautomation-lobbycall-sample/README.md @@ -28,7 +28,7 @@ In this quickstart sample, we cover how you can use the Call Automation SDK to p ```bash devtunnel create --allow-anonymous -devtunnel port create -p 8080 +devtunnel port create -p 8443 devtunnel host ``` @@ -36,7 +36,7 @@ devtunnel host Create/Open the `.env` file to configure the following settings -1. `PORT`: Assign constant 8080 +1. `PORT`: Assign constant 8443 2. `CONNECTION_STRING`: Azure Communication Service resource's connection string. 3. `COGNITIVE_SERVICES_ENDPOINT` : Cognitive service endpoint. 4. `CALLBACK_URI`: Base url of the app. (For local development replace the dev tunnel url) @@ -47,5 +47,5 @@ Create/Open the `.env` file to configure the following settings ### Run app locally 1. Open a new Powershell window, cd into the `callautomation-lobbycall-sample` folder and run `npm run dev` -2. Browser should pop up with the below page. If not navigate it to `http://localhost:8080/` +2. Browser should pop up with the below page. If not navigate it to `http://localhost:8443/` 3. Follow the steps. diff --git a/callautomation-lobbycall-sample/src/app.ts b/callautomation-lobbycall-sample/src/app.ts index 73a8d47d..8c064e92 100644 --- a/callautomation-lobbycall-sample/src/app.ts +++ b/callautomation-lobbycall-sample/src/app.ts @@ -1,6 +1,6 @@ import { config } from 'dotenv'; import express, { Application } from 'express'; -import { CommunicationUserIdentifier, getIdentifierRawId } from "@azure/communication-common"; +import { CommunicationUserIdentifier, getIdentifierRawId, isCommunicationUserIdentifier, isPhoneNumberIdentifier, isMicrosoftTeamsUserIdentifier } from "@azure/communication-common"; import { CallAutomationClient, CallInvite, @@ -15,7 +15,7 @@ config(); const PORT = process.env.PORT; const app: Application = express(); -app.use(express.static('webpage')); +app.use(express.static('src/webpage')); app.use(express.urlencoded({ extended: true })); app.use(express.json()); @@ -164,27 +164,55 @@ app.get('/getParticipants', async (req, res) => { let participantId1 = ""; let participantId2 = ""; let participantId3 = ""; - if (lobbyCallConnectionId) { - console.log(`\n~~~~~~~~~~~~ /GetParticipants/${lobbyCallConnectionId} ~~~~~~~~~~~~\n`); + if (targetCallConnectionId) { + console.log(`\n~~~~~~~~~~~~ /GetParticipants/${targetCallConnectionId} ~~~~~~~~~~~~\n`); try { - const callConnection = acsClient.getCallConnection(lobbyCallConnectionId); + const callConnection = acsClient.getCallConnection(targetCallConnectionId); const participantsResponse = await callConnection.listParticipants(); const participants = participantsResponse.values; + // alert(`JSON.stringify(participants)`); + console.log(`Participants: ${JSON.stringify(participants)}`); if (participants.length === 0) { - console.log(`No participants found in call ${lobbyCallConnectionId}`); - } else if (participants.length === 1) { - participantId1 = participants[0].identifier.toString(); - } else if (participants.length === 2) { - participantId1 = participants[0].identifier.toString(); - participantId2 = participants[1].identifier.toString(); - } else if (participants.length === 3) { - participantId1 = participants[0].identifier.toString(); - participantId2 = participants[1].identifier.toString(); - participantId3 = participants[2].identifier.toString(); + console.log(`No participants found in call ${targetCallConnectionId}`); + } else if (participants.length >= 1) { + const id1 = participants[0].identifier; + if (isCommunicationUserIdentifier(id1)) { + participantId1 = id1.communicationUserId; + } else if (isPhoneNumberIdentifier(id1)) { + participantId1 = id1.phoneNumber; + } else if (isMicrosoftTeamsUserIdentifier(id1)) { + participantId1 = id1.microsoftTeamsUserId; + } else { + participantId1 = "Unknown"; + } + } + if (participants.length >= 2) { + const id2 = participants[1].identifier; + if (isCommunicationUserIdentifier(id2)) { + participantId2 = id2.communicationUserId; + } else if (isPhoneNumberIdentifier(id2)) { + participantId2 = id2.phoneNumber; + } else if (isMicrosoftTeamsUserIdentifier(id2)) { + participantId2 = id2.microsoftTeamsUserId; + } else { + participantId2 = "Unknown"; + } + } + if (participants.length >= 3) { + const id3 = participants[2].identifier; + if (isCommunicationUserIdentifier(id3)) { + participantId3 = id3.communicationUserId; + } else if (isPhoneNumberIdentifier(id3)) { + participantId3 = id3.phoneNumber; + } else if (isMicrosoftTeamsUserIdentifier(id3)) { + participantId3 = id3.microsoftTeamsUserId; + } else { + participantId3 = "Unknown"; + } } } catch (ex) { - console.error(`Error getting participants for call ${lobbyCallConnectionId}: ${ex.message}`); + console.error(`Error getting participants for call ${targetCallConnectionId}: ${ex.message}`); } } res.json({ participantId1, participantId2, participantId3 }); @@ -268,6 +296,73 @@ app.post('/api/lobbyCallEventHandler', async (req, res) => { res.status(200).send(); }); +// app.post('/api/callbacks', async (req, res) => { +// console.log('--------- /api/callbacks -------------------'); +// const event = req.body[0]; +// const eventData = event.data; +// // For demonstration, log the event type and IDs +// console.log(`Received call event: ${event.type}`); +// console.log(`Correlation id:-> ${eventData.correlationId}`) + +// if (event.type === "Microsoft.Communication.CallConnected") { +// console.log('\n--------- CallConnected Event Block -------------------'); + +// if ((eventData.operationContext || '') === 'LobbyCall') { +// console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); +// console.log(`Received call event : ${event.type}`); +// console.log(`Lobby Call Connection Id: ${eventData.callConnectionId}`); +// console.log(`Correlation Id: ${eventData.correlationId}`); + +// // Record lobby caller id and connection id +// const lobbyCallConnection = acsClient.getCallConnection(eventData.callConnectionId); +// const callConnectionProperties = await lobbyCallConnection.getCallConnectionProperties(); +// lobbyCallerId = getIdentifierRawId(callConnectionProperties.source); +// lobbyCallConnectionId = callConnectionProperties.callConnectionId; +// console.log(`Lobby Caller Id: ${lobbyCallerId}`); +// console.log(`Lobby Connection Id: ${lobbyCallConnectionId}`); + +// // Play lobby waiting message +// const callMedia = acsClient.getCallConnection(eventData.callConnectionId).getCallMedia(); +// const textSource: TextSource = { +// text: "You are currently in a lobby call, we will notify the admin that you are waiting.", +// voiceName: "en-US-NancyNeural", +// kind: "textSource", +// }; +// const playTo: CommunicationUserIdentifier[] = [{ communicationUserId: lobbyCallerId }]; +// const playOptions: PlayOptions = { +// operationContext: "playToContext", +// }; +// await callMedia.play([textSource], playTo, playOptions); +// } +// } else if (event.type === "Microsoft.Communication.PlayCompleted") { +// console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); +// console.log(`Received event: ${event.type}`); + +// // Notify Target Call user via websocket +// if (!webSocket || webSocket.readyState !== 1) { // 1 = OPEN +// console.log("ERROR: Web socket is not available."); +// return res.status(404).send("Message sent"); +// } + +// const confirmMessageToTargetCall = "A user is waiting in lobby, do you want to add the user to your call?"; +// // Notify Client +// webSocket.send(confirmMessageToTargetCall); +// console.log(`Target Call notified with message: ${confirmMessageToTargetCall}`); +// return res.status(200).send(`Target Call notified with message: ${confirmMessageToTargetCall}`); +// } else if (event.type === "Microsoft.Communication.MoveParticipantsSucceeded") { +// console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); +// console.log(`Received event: ${event.type}`); +// console.log(`Call Connection Id: ${eventData.callConnectionId}`); +// console.log(`Correlation Id: ${eventData.correlationId}`); +// } else if (event.type === "Microsoft.Communication.CallDisconnected") { +// console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); +// console.log(`Received event: ${event.type}`); +// console.log(`Call Connection Id: ${eventData.callConnectionId}`); +// } + +// res.status(200).send(); +// }); + app.post('/api/callbacks', async (req, res) => { console.log('--------- /api/callbacks -------------------'); const event = req.body[0]; @@ -307,20 +402,49 @@ app.post('/api/callbacks', async (req, res) => { await callMedia.play([textSource], playTo, playOptions); } } else if (event.type === "Microsoft.Communication.PlayCompleted") { + // Log event console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); console.log(`Received event: ${event.type}`); - // Notify Target Call user via websocket - if (!webSocket || webSocket.readyState !== 1) { // 1 = OPEN - console.log("ERROR: Web socket is not available."); - return res.status(404).send("Message sent"); - } + // Move Participant logic + try { + console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); + console.log('Move Participant operation started..'); + console.log(`Source Caller Id: ${lobbyCallerId}`); + console.log(`Source Connection Id: ${lobbyCallConnectionId}`); + console.log(`Target Connection Id: ${targetCallConnectionId}`); + + // Get the target connection + const targetConnection = acsClient.getCallConnection(targetCallConnectionId); - const confirmMessageToTargetCall = "A user is waiting in lobby, do you want to add the user to your call?"; - // Notify Client - webSocket.send(confirmMessageToTargetCall); - console.log(`Target Call notified with message: ${confirmMessageToTargetCall}`); - return res.status(200).send(`Target Call notified with message: ${confirmMessageToTargetCall}`); + // Get participants from source connection for reference (optional) + // const sourceConnection = client.getCallConnection(lobbyConnectionId); + + // Create participant identifier based on the input + let participantToMove; + if (lobbyCallerId.startsWith('+')) { + // Phone number + participantToMove = { kind: 'phoneNumber', phoneNumber: lobbyCallerId }; + } else if (lobbyCallerId.startsWith('8:acs:')) { + // ACS Communication User + participantToMove = { kind: 'communicationUser', communicationUserId: lobbyCallerId }; + } else { + res.status(400).send('Invalid participant format. Use phone number (+1234567890) or ACS user ID (8:acs:...)'); + return; + } + + // Move participant + const response = await targetConnection.moveParticipants([participantToMove], lobbyCallConnectionId); + + console.log('\nMove Participants operation completed successfully.'); + } catch (ex) { + console.log(`Error in manual move participants operation: ${ex.message}`); + res.status(400).json({ + Success: false, + Error: ex.message, + Message: 'Move participants operation failed.' + }); + } } else if (event.type === "Microsoft.Communication.MoveParticipantsSucceeded") { console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); console.log(`Received event: ${event.type}`); @@ -340,8 +464,8 @@ app.get('/', (req, res) => { res.sendFile('index.html', { root: 'src/webpage' }); }); -// Start the server -app.listen(PORT, async () => { - console.log(`Server is listening on port ${PORT}`); +// Start the server using the HTTP server (not app.listen) +server.listen(Number(PORT), '0.0.0.0', async () => { + console.log(`Server is listening on port ${PORT} on all interfaces`); await createAcsClient(); }); diff --git a/callautomation-lobbycall-sample/src/webpage/index.html b/callautomation-lobbycall-sample/src/webpage/index.html index 2c1b44e0..08d7aa62 100644 --- a/callautomation-lobbycall-sample/src/webpage/index.html +++ b/callautomation-lobbycall-sample/src/webpage/index.html @@ -42,9 +42,9 @@

Lobby Call Sample

STEP 3. Create User Call
Create a Call for ACS Identity by entering the target ACS User ID and clicking the button. Answer it manually from Web Client App
-
+

- +

From 8954cd7f1218176dd9af1293a0822e624372f1eb Mon Sep 17 00:00:00 2001 From: nageshy Date: Mon, 4 Aug 2025 15:31:07 +0530 Subject: [PATCH 10/12] Code updated --- callautomation-lobbycall-sample/README.md | 53 +++- .../Resources/Lobby_Call_Support_Scenario.jpg | Bin 0 -> 128065 bytes callautomation-lobbycall-sample/src/app.ts | 244 +++++++++--------- .../src/webpage/index.html | 2 +- 4 files changed, 171 insertions(+), 128 deletions(-) create mode 100644 callautomation-lobbycall-sample/Resources/Lobby_Call_Support_Scenario.jpg diff --git a/callautomation-lobbycall-sample/README.md b/callautomation-lobbycall-sample/README.md index c1a88c8d..549c2e65 100644 --- a/callautomation-lobbycall-sample/README.md +++ b/callautomation-lobbycall-sample/README.md @@ -3,9 +3,13 @@ |---|---|---| |sample|
Typescript
|
azureazure-communication-services
| -# Lobby Call Sample using Call Automation SDK +# Call Automation - Lobby Call Support Sample -In this quickstart sample, we cover how you can use the Call Automation SDK to perform lobby calls using Azure Communication Services (ACS) calls. This involves creating and managing several outgoing calls simultaneously and dynamically moving participants between these active calls. +In this sample, we cover how you can use Call Automation SDK to support Lobby Call where we join Lobby call users to a target call upon confirmation of admin in the target call. + +# Design + +![Lobby Call Support](./Resources/Lobby_Call_Support_Scenario.jpg) ## Prerequisites @@ -22,6 +26,16 @@ In this quickstart sample, we cover how you can use the Call Automation SDK to p 3. cd into the `callautomation-lobbycall-sample` folder. 4. From the root of the above folder, and with node installed, run `npm install` +## Running the client App for the sample + +1. Open the web client app at [JS Client Sample](https://github.com/Azure-Samples/communication-services-javascript-quickstarts/tree/users/v-kuppu/LobbyCallConfirmSample) and sign in with your Azure Communication Services identity. +2. Clone the sample repository by running `git clone https://github.com/Azure-Samples/communication-services-javascript-quickstarts.git`. +3. Run the application and observe logs at console, keep this application running. + + ``` + npx webpack serve --config webpack.config.js + ``` + ### Setup and host your Azure DevTunnel [Azure DevTunnels](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/get-started?tabs=windows) is an Azure service that enables you to share local web services hosted on the internet. Use the commands below to connect your local development environment to the public internet. This creates a tunnel with a persistent endpoint URL and which allows anonymous access. We will then use this endpoint to notify your application of calling events from the ACS Call Automation service. @@ -40,12 +54,39 @@ Create/Open the `.env` file to configure the following settings 2. `CONNECTION_STRING`: Azure Communication Service resource's connection string. 3. `COGNITIVE_SERVICES_ENDPOINT` : Cognitive service endpoint. 4. `CALLBACK_URI`: Base url of the app. (For local development replace the dev tunnel url) -5. `PMA_ENDPOINT`: PMA endpoint url -6. `ACS_GENERATED_ID`: ACS Generated Id -7. `SOCKET_TOKEN`: Web Socket Token Key +5. `ACS_ID_FOR_LOBBY_CALL_RECEIVER`: ACS Inbound Phone Number +6. `ACS_ID_FOR_TARGET_CALL_RECEIVER`: ACS Phone Number to make the first call, external user number in real time +7. `ACS_ID_FOR_TARGET_CALL_SENDER`: ACS identity generated using web client +8. `SOCKET_TOKEN`: ACS identity generated using web client -### Run app locally +### To Run app 1. Open a new Powershell window, cd into the `callautomation-lobbycall-sample` folder and run `npm run dev` 2. Browser should pop up with the below page. If not navigate it to `http://localhost:8443/` 3. Follow the steps. + +## Run app locally + +1. Setup EventSubscription(Incoming) with filter for `TO.DATA.RAWID = , `. +2. Setup the following keys in the config/constants + ```"acsConnectionString": "", + "cognitiveServiceEndpoint": "", + "callbackUriHost": "", + "textToPlayToLobbyUser": "You are currently in a lobby call, we will notify the admin that you are waiting.", + "confirmMessageToTargetCall": "A user is waiting in lobby, do you want to add the lobby user to your call?", + "acsGeneratedIdForLobbyCallReceiver": "",(Generate Voice Calling Identity in Azure Portal) + "acsGeneratedIdForTargetCallReceiver": "",(Generate Voice Calling Identity in Azure Portal) + "acsGeneratedIdForTargetCallSender": "",(Generate Voice Calling Identity in Azure Portal) + "socketToken": ""(Token associated with in Azure Portal)``` +3. Define a websocket in your application(program.cs) to send and receive messages from and to client application(JS Hero App in this case). +4. Define a Client application that receives and responds to server notifications. Client application is available at . +5. Enter and validate user token in client app to send calls. +6. Start call to ``. +7. Expect Call Connected evennt in /callbacks +8. Start a call from ACS Test app(angular) to acsGeneratedIdForLobbyCallReceiver +9. Call will be answered and automated voice will be played to lobby user with the text ``. +10. Once the play completed, Target call will be notified with ``. +11. Once the Target call confirms from client application, Move `` in the backend sample. +12. If Target user says no, then no MOVE will be performed. +13. Ensure MoveParticipantSucceeded event is received in `/callbacks` endpoint. +14. Check `/Getparticipants` endpoint be called with Target call id, Target call must have the recent lobby user in the call. \ No newline at end of file diff --git a/callautomation-lobbycall-sample/Resources/Lobby_Call_Support_Scenario.jpg b/callautomation-lobbycall-sample/Resources/Lobby_Call_Support_Scenario.jpg new file mode 100644 index 0000000000000000000000000000000000000000..92225d4e602310278e4a69aed681d388a4290064 GIT binary patch literal 128065 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

AUR$p1PMe$*`cVx3$&410_zLaO77Iz7D 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 z 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 literal 0 HcmV?d00001 diff --git a/callautomation-lobbycall-sample/src/app.ts b/callautomation-lobbycall-sample/src/app.ts index 8c064e92..67791f6e 100644 --- a/callautomation-lobbycall-sample/src/app.ts +++ b/callautomation-lobbycall-sample/src/app.ts @@ -19,22 +19,24 @@ app.use(express.static('src/webpage')); app.use(express.urlencoded({ extended: true })); app.use(express.json()); +const connectionString = process.env.CONNECTION_STRING || "" +const callbackUriHost = process.env.CALLBACK_URI || ""; +const acsGeneratedIdForLobbyCallReceiver = process.env.ACS_GENERATED_ID_FOR_LOBBY_CALL_RECEIVER || ""; +const acsGeneratedIdForTargetCallReceiver = process.env.ACS_GENERATED_ID_FOR_TARGET_CALL_RECEIVER || ""; +const acsGeneratedIdForTargetCallSender = process.env.ACS_GENERATED_ID_FOR_TARGET_CALL_SENDER || ""; +const textToPlayToLobbyUser = "You are currently in a lobby call, we will notify the admin that you are waiting."; +const confirmMessageToTargetCall = "A user is waiting in lobby, do you want to add the lobby user to your call?"; + let lobbyCallConnectionId: string; let targetCallConnectionId: string; -let acsGeneratedId: string; let acsClient: CallAutomationClient; let lobbyCallerId: string; -const callbackUriHost = process.env.CALLBACK_URI || ""; -const connectionString = process.env.CONNECTION_STRING || "" -const endpoint = process.env.PMA_ENDPOINT || "" let webSocket = null; async function createAcsClient() { lobbyCallConnectionId = ""; targetCallConnectionId = ""; - acsGeneratedId = process.env.ACS_GENERATED_ID || ""; lobbyCallerId = ""; - // acsClient = new CallAutomationClient(endpoint, connectionString); acsClient = new CallAutomationClient(connectionString); console.log("Initialized ACS Client."); } @@ -45,9 +47,9 @@ const server = http.createServer(app); const wss = new WebSocket.Server({ noServer: true }); server.on('upgrade', (request, socket, head) => { - // Only accept connections to the correct path + // Accept connections to the /ws path without token validation const url = request.url || ''; - if (url === `/ws/${process.env.SOCKET_TOKEN}`) { + if (url === '/ws') { wss.handleUpgrade(request, socket, head, function done(ws) { wss.emit('connection', ws, request); }); @@ -66,7 +68,7 @@ wss.on('connection', (ws) => { // Move participant to target call if response is "yes" if (jsResponse.trim().toLowerCase() === 'yes') { - console.log('TODO: Move Participant'); + console.log('Move Participant'); try { console.log(` ~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~ @@ -164,17 +166,17 @@ app.get('/getParticipants', async (req, res) => { let participantId1 = ""; let participantId2 = ""; let participantId3 = ""; - if (targetCallConnectionId) { - console.log(`\n~~~~~~~~~~~~ /GetParticipants/${targetCallConnectionId} ~~~~~~~~~~~~\n`); + if (lobbyCallConnectionId) { + console.log(`\n~~~~~~~~~~~~ /GetParticipants/${lobbyCallConnectionId} ~~~~~~~~~~~~\n`); try { - const callConnection = acsClient.getCallConnection(targetCallConnectionId); + const callConnection = acsClient.getCallConnection(lobbyCallConnectionId); const participantsResponse = await callConnection.listParticipants(); const participants = participantsResponse.values; // alert(`JSON.stringify(participants)`); console.log(`Participants: ${JSON.stringify(participants)}`); if (participants.length === 0) { - console.log(`No participants found in call ${targetCallConnectionId}`); + console.log(`No participants found in call ${lobbyCallConnectionId}`); } else if (participants.length >= 1) { const id1 = participants[0].identifier; if (isCommunicationUserIdentifier(id1)) { @@ -212,7 +214,7 @@ app.get('/getParticipants', async (req, res) => { } } } catch (ex) { - console.error(`Error getting participants for call ${targetCallConnectionId}: ${ex.message}`); + console.error(`Error getting participants for call ${lobbyCallConnectionId}: ${ex.message}`); } } res.json({ participantId1, participantId2, participantId3 }); @@ -266,7 +268,7 @@ app.post('/api/lobbyCallEventHandler', async (req, res) => { console.log(`To Caller Id : ${toCallerId}`); // Lobby Call: Answer - if (toCallerId.includes(acsGeneratedId)) { + if (toCallerId.includes(acsGeneratedIdForLobbyCallReceiver)) { const callbackUri = `${callbackUriHost}/api/callbacks`; const options = { operationContext: 'LobbyCall', @@ -296,73 +298,6 @@ app.post('/api/lobbyCallEventHandler', async (req, res) => { res.status(200).send(); }); -// app.post('/api/callbacks', async (req, res) => { -// console.log('--------- /api/callbacks -------------------'); -// const event = req.body[0]; -// const eventData = event.data; -// // For demonstration, log the event type and IDs -// console.log(`Received call event: ${event.type}`); -// console.log(`Correlation id:-> ${eventData.correlationId}`) - -// if (event.type === "Microsoft.Communication.CallConnected") { -// console.log('\n--------- CallConnected Event Block -------------------'); - -// if ((eventData.operationContext || '') === 'LobbyCall') { -// console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); -// console.log(`Received call event : ${event.type}`); -// console.log(`Lobby Call Connection Id: ${eventData.callConnectionId}`); -// console.log(`Correlation Id: ${eventData.correlationId}`); - -// // Record lobby caller id and connection id -// const lobbyCallConnection = acsClient.getCallConnection(eventData.callConnectionId); -// const callConnectionProperties = await lobbyCallConnection.getCallConnectionProperties(); -// lobbyCallerId = getIdentifierRawId(callConnectionProperties.source); -// lobbyCallConnectionId = callConnectionProperties.callConnectionId; -// console.log(`Lobby Caller Id: ${lobbyCallerId}`); -// console.log(`Lobby Connection Id: ${lobbyCallConnectionId}`); - -// // Play lobby waiting message -// const callMedia = acsClient.getCallConnection(eventData.callConnectionId).getCallMedia(); -// const textSource: TextSource = { -// text: "You are currently in a lobby call, we will notify the admin that you are waiting.", -// voiceName: "en-US-NancyNeural", -// kind: "textSource", -// }; -// const playTo: CommunicationUserIdentifier[] = [{ communicationUserId: lobbyCallerId }]; -// const playOptions: PlayOptions = { -// operationContext: "playToContext", -// }; -// await callMedia.play([textSource], playTo, playOptions); -// } -// } else if (event.type === "Microsoft.Communication.PlayCompleted") { -// console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); -// console.log(`Received event: ${event.type}`); - -// // Notify Target Call user via websocket -// if (!webSocket || webSocket.readyState !== 1) { // 1 = OPEN -// console.log("ERROR: Web socket is not available."); -// return res.status(404).send("Message sent"); -// } - -// const confirmMessageToTargetCall = "A user is waiting in lobby, do you want to add the user to your call?"; -// // Notify Client -// webSocket.send(confirmMessageToTargetCall); -// console.log(`Target Call notified with message: ${confirmMessageToTargetCall}`); -// return res.status(200).send(`Target Call notified with message: ${confirmMessageToTargetCall}`); -// } else if (event.type === "Microsoft.Communication.MoveParticipantsSucceeded") { -// console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); -// console.log(`Received event: ${event.type}`); -// console.log(`Call Connection Id: ${eventData.callConnectionId}`); -// console.log(`Correlation Id: ${eventData.correlationId}`); -// } else if (event.type === "Microsoft.Communication.CallDisconnected") { -// console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); -// console.log(`Received event: ${event.type}`); -// console.log(`Call Connection Id: ${eventData.callConnectionId}`); -// } - -// res.status(200).send(); -// }); - app.post('/api/callbacks', async (req, res) => { console.log('--------- /api/callbacks -------------------'); const event = req.body[0]; @@ -402,49 +337,20 @@ app.post('/api/callbacks', async (req, res) => { await callMedia.play([textSource], playTo, playOptions); } } else if (event.type === "Microsoft.Communication.PlayCompleted") { - // Log event console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); console.log(`Received event: ${event.type}`); - // Move Participant logic - try { - console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); - console.log('Move Participant operation started..'); - console.log(`Source Caller Id: ${lobbyCallerId}`); - console.log(`Source Connection Id: ${lobbyCallConnectionId}`); - console.log(`Target Connection Id: ${targetCallConnectionId}`); - - // Get the target connection - const targetConnection = acsClient.getCallConnection(targetCallConnectionId); - - // Get participants from source connection for reference (optional) - // const sourceConnection = client.getCallConnection(lobbyConnectionId); - - // Create participant identifier based on the input - let participantToMove; - if (lobbyCallerId.startsWith('+')) { - // Phone number - participantToMove = { kind: 'phoneNumber', phoneNumber: lobbyCallerId }; - } else if (lobbyCallerId.startsWith('8:acs:')) { - // ACS Communication User - participantToMove = { kind: 'communicationUser', communicationUserId: lobbyCallerId }; - } else { - res.status(400).send('Invalid participant format. Use phone number (+1234567890) or ACS user ID (8:acs:...)'); - return; - } - - // Move participant - const response = await targetConnection.moveParticipants([participantToMove], lobbyCallConnectionId); - - console.log('\nMove Participants operation completed successfully.'); - } catch (ex) { - console.log(`Error in manual move participants operation: ${ex.message}`); - res.status(400).json({ - Success: false, - Error: ex.message, - Message: 'Move participants operation failed.' - }); + // Notify Target Call user via websocket + if (!webSocket || webSocket.readyState !== 1) { // 1 = OPEN + console.log("ERROR: Web socket is not available."); + return res.status(404).send("Message sent"); } + + const confirmMessageToTargetCall = "A user is waiting in lobby, do you want to add the user to your call?"; + // Notify Client + webSocket.send(confirmMessageToTargetCall); + console.log(`Target Call notified with message: ${confirmMessageToTargetCall}`); + return res.status(200).send(`Target Call notified with message: ${confirmMessageToTargetCall}`); } else if (event.type === "Microsoft.Communication.MoveParticipantsSucceeded") { console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); console.log(`Received event: ${event.type}`); @@ -459,6 +365,102 @@ app.post('/api/callbacks', async (req, res) => { res.status(200).send(); }); +// app.post('/api/callbacks', async (req, res) => { +// console.log('--------- /api/callbacks -------------------'); +// const event = req.body[0]; +// const eventData = event.data; +// // For demonstration, log the event type and IDs +// console.log(`Received call event: ${event.type}`); +// console.log(`Correlation id:-> ${eventData.correlationId}`) + +// if (event.type === "Microsoft.Communication.CallConnected") { +// console.log('\n--------- CallConnected Event Block -------------------'); + +// if ((eventData.operationContext || '') === 'LobbyCall') { +// console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); +// console.log(`Received call event : ${event.type}`); +// console.log(`Lobby Call Connection Id: ${eventData.callConnectionId}`); +// console.log(`Correlation Id: ${eventData.correlationId}`); + +// // Record lobby caller id and connection id +// const lobbyCallConnection = acsClient.getCallConnection(eventData.callConnectionId); +// const callConnectionProperties = await lobbyCallConnection.getCallConnectionProperties(); +// lobbyCallerId = getIdentifierRawId(callConnectionProperties.source); +// lobbyCallConnectionId = callConnectionProperties.callConnectionId; +// console.log(`Lobby Caller Id: ${lobbyCallerId}`); +// console.log(`Lobby Connection Id: ${lobbyCallConnectionId}`); + +// // Play lobby waiting message +// const callMedia = acsClient.getCallConnection(eventData.callConnectionId).getCallMedia(); +// const textSource: TextSource = { +// text: "You are currently in a lobby call, we will notify the admin that you are waiting.", +// voiceName: "en-US-NancyNeural", +// kind: "textSource", +// }; +// const playTo: CommunicationUserIdentifier[] = [{ communicationUserId: lobbyCallerId }]; +// const playOptions: PlayOptions = { +// operationContext: "playToContext", +// }; +// await callMedia.play([textSource], playTo, playOptions); +// } +// } else if (event.type === "Microsoft.Communication.PlayCompleted") { +// // Log event +// console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); +// console.log(`Received event: ${event.type}`); + +// // Move Participant logic +// try { +// console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); +// console.log('Move Participant operation started..'); +// console.log(`Source Caller Id: ${lobbyCallerId}`); +// console.log(`Source Connection Id: ${lobbyCallConnectionId}`); +// console.log(`Target Connection Id: ${targetCallConnectionId}`); + +// // Get the target connection +// const targetConnection = acsClient.getCallConnection(targetCallConnectionId); + +// // Get participants from source connection for reference (optional) +// // const sourceConnection = client.getCallConnection(lobbyConnectionId); + +// // Create participant identifier based on the input +// let participantToMove; +// if (lobbyCallerId.startsWith('+')) { +// // Phone number +// participantToMove = { kind: 'phoneNumber', phoneNumber: lobbyCallerId }; +// } else if (lobbyCallerId.startsWith('8:acs:')) { +// // ACS Communication User +// participantToMove = { kind: 'communicationUser', communicationUserId: lobbyCallerId }; +// } else { +// res.status(400).send('Invalid participant format. Use phone number (+1234567890) or ACS user ID (8:acs:...)'); +// return; +// } + +// // Move participant +// const response = await targetConnection.moveParticipants([participantToMove], lobbyCallConnectionId); + +// console.log('\nMove Participants operation completed successfully.'); +// } catch (ex) { +// console.log(`Error in manual move participants operation: ${ex.message}`); +// res.status(400).json({ +// Success: false, +// Error: ex.message, +// Message: 'Move participants operation failed.' +// }); +// } +// } else if (event.type === "Microsoft.Communication.MoveParticipantsSucceeded") { +// console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); +// console.log(`Received event: ${event.type}`); +// console.log(`Call Connection Id: ${eventData.callConnectionId}`); +// console.log(`Correlation Id: ${eventData.correlationId}`); +// } else if (event.type === "Microsoft.Communication.CallDisconnected") { +// console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); +// console.log(`Received event: ${event.type}`); +// console.log(`Call Connection Id: ${eventData.callConnectionId}`); +// } + +// res.status(200).send(); +// }); + // GET endpoint to serve the webpage app.get('/', (req, res) => { res.sendFile('index.html', { root: 'src/webpage' }); diff --git a/callautomation-lobbycall-sample/src/webpage/index.html b/callautomation-lobbycall-sample/src/webpage/index.html index 08d7aa62..9790fd60 100644 --- a/callautomation-lobbycall-sample/src/webpage/index.html +++ b/callautomation-lobbycall-sample/src/webpage/index.html @@ -146,7 +146,7 @@

Lobby Call Sample

document.addEventListener('DOMContentLoaded', () => { const form = document.querySelector('form'); form.addEventListener('submit', (event) => { - alert('Call submitted!'); + alert('Submitted!'); }); setTimeout(() => { startPeriodicFetch(); From ff24ef3c67fd64b21abee8f65df358201ded4e58 Mon Sep 17 00:00:00 2001 From: nageshy Date: Mon, 4 Aug 2025 15:44:43 +0530 Subject: [PATCH 11/12] code updated --- callautomation-lobbycall-sample/package.json | 2 +- callautomation-lobbycall-sample/src/app.ts | 99 +------------------- 2 files changed, 2 insertions(+), 99 deletions(-) diff --git a/callautomation-lobbycall-sample/package.json b/callautomation-lobbycall-sample/package.json index 31ae0036..b6144004 100644 --- a/callautomation-lobbycall-sample/package.json +++ b/callautomation-lobbycall-sample/package.json @@ -11,7 +11,7 @@ "author": "", "license": "ISC", "dependencies": { - "@azure/communication-call-automation": "file:../../azure-sdk-for-js/sdk/communication/communication-call-automation", + "@azure/communication-call-automation": "^1.6.0", "@azure/communication-common": "^2.2.0", "@azure/communication-identity": "^1.3.1", "@azure/communication-rooms": "^1.1.1", diff --git a/callautomation-lobbycall-sample/src/app.ts b/callautomation-lobbycall-sample/src/app.ts index 67791f6e..c393cf05 100644 --- a/callautomation-lobbycall-sample/src/app.ts +++ b/callautomation-lobbycall-sample/src/app.ts @@ -326,7 +326,7 @@ app.post('/api/callbacks', async (req, res) => { // Play lobby waiting message const callMedia = acsClient.getCallConnection(eventData.callConnectionId).getCallMedia(); const textSource: TextSource = { - text: "You are currently in a lobby call, we will notify the admin that you are waiting.", + text: textToPlayToLobbyUser, voiceName: "en-US-NancyNeural", kind: "textSource", }; @@ -346,7 +346,6 @@ app.post('/api/callbacks', async (req, res) => { return res.status(404).send("Message sent"); } - const confirmMessageToTargetCall = "A user is waiting in lobby, do you want to add the user to your call?"; // Notify Client webSocket.send(confirmMessageToTargetCall); console.log(`Target Call notified with message: ${confirmMessageToTargetCall}`); @@ -365,102 +364,6 @@ app.post('/api/callbacks', async (req, res) => { res.status(200).send(); }); -// app.post('/api/callbacks', async (req, res) => { -// console.log('--------- /api/callbacks -------------------'); -// const event = req.body[0]; -// const eventData = event.data; -// // For demonstration, log the event type and IDs -// console.log(`Received call event: ${event.type}`); -// console.log(`Correlation id:-> ${eventData.correlationId}`) - -// if (event.type === "Microsoft.Communication.CallConnected") { -// console.log('\n--------- CallConnected Event Block -------------------'); - -// if ((eventData.operationContext || '') === 'LobbyCall') { -// console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); -// console.log(`Received call event : ${event.type}`); -// console.log(`Lobby Call Connection Id: ${eventData.callConnectionId}`); -// console.log(`Correlation Id: ${eventData.correlationId}`); - -// // Record lobby caller id and connection id -// const lobbyCallConnection = acsClient.getCallConnection(eventData.callConnectionId); -// const callConnectionProperties = await lobbyCallConnection.getCallConnectionProperties(); -// lobbyCallerId = getIdentifierRawId(callConnectionProperties.source); -// lobbyCallConnectionId = callConnectionProperties.callConnectionId; -// console.log(`Lobby Caller Id: ${lobbyCallerId}`); -// console.log(`Lobby Connection Id: ${lobbyCallConnectionId}`); - -// // Play lobby waiting message -// const callMedia = acsClient.getCallConnection(eventData.callConnectionId).getCallMedia(); -// const textSource: TextSource = { -// text: "You are currently in a lobby call, we will notify the admin that you are waiting.", -// voiceName: "en-US-NancyNeural", -// kind: "textSource", -// }; -// const playTo: CommunicationUserIdentifier[] = [{ communicationUserId: lobbyCallerId }]; -// const playOptions: PlayOptions = { -// operationContext: "playToContext", -// }; -// await callMedia.play([textSource], playTo, playOptions); -// } -// } else if (event.type === "Microsoft.Communication.PlayCompleted") { -// // Log event -// console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); -// console.log(`Received event: ${event.type}`); - -// // Move Participant logic -// try { -// console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); -// console.log('Move Participant operation started..'); -// console.log(`Source Caller Id: ${lobbyCallerId}`); -// console.log(`Source Connection Id: ${lobbyCallConnectionId}`); -// console.log(`Target Connection Id: ${targetCallConnectionId}`); - -// // Get the target connection -// const targetConnection = acsClient.getCallConnection(targetCallConnectionId); - -// // Get participants from source connection for reference (optional) -// // const sourceConnection = client.getCallConnection(lobbyConnectionId); - -// // Create participant identifier based on the input -// let participantToMove; -// if (lobbyCallerId.startsWith('+')) { -// // Phone number -// participantToMove = { kind: 'phoneNumber', phoneNumber: lobbyCallerId }; -// } else if (lobbyCallerId.startsWith('8:acs:')) { -// // ACS Communication User -// participantToMove = { kind: 'communicationUser', communicationUserId: lobbyCallerId }; -// } else { -// res.status(400).send('Invalid participant format. Use phone number (+1234567890) or ACS user ID (8:acs:...)'); -// return; -// } - -// // Move participant -// const response = await targetConnection.moveParticipants([participantToMove], lobbyCallConnectionId); - -// console.log('\nMove Participants operation completed successfully.'); -// } catch (ex) { -// console.log(`Error in manual move participants operation: ${ex.message}`); -// res.status(400).json({ -// Success: false, -// Error: ex.message, -// Message: 'Move participants operation failed.' -// }); -// } -// } else if (event.type === "Microsoft.Communication.MoveParticipantsSucceeded") { -// console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); -// console.log(`Received event: ${event.type}`); -// console.log(`Call Connection Id: ${eventData.callConnectionId}`); -// console.log(`Correlation Id: ${eventData.correlationId}`); -// } else if (event.type === "Microsoft.Communication.CallDisconnected") { -// console.log('~~~~~~~~~~~~ /api/callbacks ~~~~~~~~~~~~'); -// console.log(`Received event: ${event.type}`); -// console.log(`Call Connection Id: ${eventData.callConnectionId}`); -// } - -// res.status(200).send(); -// }); - // GET endpoint to serve the webpage app.get('/', (req, res) => { res.sendFile('index.html', { root: 'src/webpage' }); From f173cbb91f978e21d59e5e21258e026fb9f8b646 Mon Sep 17 00:00:00 2001 From: nageshy Date: Thu, 23 Oct 2025 09:42:56 +0530 Subject: [PATCH 12/12] Updated Readme --- callautomation-lobbycall-sample/README.md | 204 ++++++++++++++-------- 1 file changed, 129 insertions(+), 75 deletions(-) diff --git a/callautomation-lobbycall-sample/README.md b/callautomation-lobbycall-sample/README.md index 549c2e65..088b6b60 100644 --- a/callautomation-lobbycall-sample/README.md +++ b/callautomation-lobbycall-sample/README.md @@ -5,88 +5,142 @@ # Call Automation - Lobby Call Support Sample -In this sample, we cover how you can use Call Automation SDK to support Lobby Call where we join Lobby call users to a target call upon confirmation of admin in the target call. - -# Design +This sample demonstrates how to use Azure Communication Services Call Automation SDK to support a "Lobby Call" scenario, where users wait in a lobby and can be joined to a target call by an admin. ![Lobby Call Support](./Resources/Lobby_Call_Support_Scenario.jpg) ## Prerequisites -- Create an Azure account with an active subscription. For details, see [Create an account for free](https://azure.microsoft.com/free/) +- Azure account with active subscription. For details, see [Create an account for free](https://azure.microsoft.com/free/) - [Visual Studio Code](https://code.visualstudio.com/download) installed - [Node.js](https://nodejs.org/en/download) installed - Create an Azure Communication Services resource. For details, see [Create an Azure Communication Resource](https://docs.microsoft.com/azure/communication-services/quickstarts/create-communication-resource). You will need to record your resource **connection string** for this sample. - Get a phone number for your new Azure Communication Services resource. For details, see [Get a phone number](https://learn.microsoft.com/azure/communication-services/quickstarts/telephony/get-phone-number?tabs=windows&pivots=programming-language-csharp) -## Before running the sample for the first time - -1. Open an instance of PowerShell, Windows Terminal, Command Prompt or equivalent and navigate to the directory that you would like to clone the sample to. -2. git clone `https://github.com/Azure-Samples/communication-services-javascript-quickstarts.git`. -3. cd into the `callautomation-lobbycall-sample` folder. -4. From the root of the above folder, and with node installed, run `npm install` - -## Running the client App for the sample - -1. Open the web client app at [JS Client Sample](https://github.com/Azure-Samples/communication-services-javascript-quickstarts/tree/users/v-kuppu/LobbyCallConfirmSample) and sign in with your Azure Communication Services identity. -2. Clone the sample repository by running `git clone https://github.com/Azure-Samples/communication-services-javascript-quickstarts.git`. -3. Run the application and observe logs at console, keep this application running. - - ``` - npx webpack serve --config webpack.config.js - ``` - -### Setup and host your Azure DevTunnel - -[Azure DevTunnels](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/get-started?tabs=windows) is an Azure service that enables you to share local web services hosted on the internet. Use the commands below to connect your local development environment to the public internet. This creates a tunnel with a persistent endpoint URL and which allows anonymous access. We will then use this endpoint to notify your application of calling events from the ACS Call Automation service. - -```bash -devtunnel create --allow-anonymous -devtunnel port create -p 8443 -devtunnel host -``` - -### Configuring application - -Create/Open the `.env` file to configure the following settings - -1. `PORT`: Assign constant 8443 -2. `CONNECTION_STRING`: Azure Communication Service resource's connection string. -3. `COGNITIVE_SERVICES_ENDPOINT` : Cognitive service endpoint. -4. `CALLBACK_URI`: Base url of the app. (For local development replace the dev tunnel url) -5. `ACS_ID_FOR_LOBBY_CALL_RECEIVER`: ACS Inbound Phone Number -6. `ACS_ID_FOR_TARGET_CALL_RECEIVER`: ACS Phone Number to make the first call, external user number in real time -7. `ACS_ID_FOR_TARGET_CALL_SENDER`: ACS identity generated using web client -8. `SOCKET_TOKEN`: ACS identity generated using web client - -### To Run app - -1. Open a new Powershell window, cd into the `callautomation-lobbycall-sample` folder and run `npm run dev` -2. Browser should pop up with the below page. If not navigate it to `http://localhost:8443/` -3. Follow the steps. - -## Run app locally - -1. Setup EventSubscription(Incoming) with filter for `TO.DATA.RAWID = , `. -2. Setup the following keys in the config/constants - ```"acsConnectionString": "", - "cognitiveServiceEndpoint": "", - "callbackUriHost": "", - "textToPlayToLobbyUser": "You are currently in a lobby call, we will notify the admin that you are waiting.", - "confirmMessageToTargetCall": "A user is waiting in lobby, do you want to add the lobby user to your call?", - "acsGeneratedIdForLobbyCallReceiver": "",(Generate Voice Calling Identity in Azure Portal) - "acsGeneratedIdForTargetCallReceiver": "",(Generate Voice Calling Identity in Azure Portal) - "acsGeneratedIdForTargetCallSender": "",(Generate Voice Calling Identity in Azure Portal) - "socketToken": ""(Token associated with in Azure Portal)``` -3. Define a websocket in your application(program.cs) to send and receive messages from and to client application(JS Hero App in this case). -4. Define a Client application that receives and responds to server notifications. Client application is available at . -5. Enter and validate user token in client app to send calls. -6. Start call to ``. -7. Expect Call Connected evennt in /callbacks -8. Start a call from ACS Test app(angular) to acsGeneratedIdForLobbyCallReceiver -9. Call will be answered and automated voice will be played to lobby user with the text ``. -10. Once the play completed, Target call will be notified with ``. -11. Once the Target call confirms from client application, Move `` in the backend sample. -12. If Target user says no, then no MOVE will be performed. -13. Ensure MoveParticipantSucceeded event is received in `/callbacks` endpoint. -14. Check `/Getparticipants` endpoint be called with Target call id, Target call must have the recent lobby user in the call. \ No newline at end of file +## Setup + +1. **Clone the repository and install dependencies:** + ```bash + git clone https://github.com/Azure-Samples/communication-services-javascript-quickstarts.git + cd communication-services-javascript-quickstarts/callautomation-lobbycall-sample + npm install + ``` + +2. **Configure environment variables:** + Create a `.env` file in the project root with the following keys: + ```env + PORT=8443 + CONNECTION_STRING="" + COGNITIVE_SERVICES_ENDPOINT="" + CALLBACK_URI="" + PMA_ENDPOINT="" + ACS_GENERATED_ID="" + SOCKET_TOKEN="" + ``` + +3. **Set up Azure DevTunnels (for webhook callbacks):** + [Azure DevTunnels](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/get-started?tabs=windows) enables you to share local web services on the internet for webhook callbacks. + ```bash + devtunnel create --allow-anonymous + devtunnel port create -p 8443 + devtunnel host + ``` + Update your `CALLBACK_URI` in `.env` with the generated tunnel URL. + +## Running the Application + +1. **Start the backend server:** + ```bash + npm run dev + ``` + +2. **Access the web interface:** + - Local: `http://localhost:8443/` + - Public: Your DevTunnel URL (e.g., `https://your-tunnel.inc1.devtunnels.ms`) + +## Web Interface Usage + +The web page provides a step-by-step interface for the lobby call workflow: + +### Steps: +1. **Configure Environment Variables** - Ensure your `.env` file is properly set up +2. **Configure Webhook** - Point Event Grid webhook to `/api/lobbyCallEventHandler` endpoint +3. **Configure Lobby Call** - Make a lobby call from your ACS client app to the generated ACS identity +4. **Create Target Call** - Enter an ACS Target User ID and click "Create Call!" +5. **Answer User Call** - Answer the call manually from your ACS client app +6. **View Participants** - The right panel shows participant IDs in the target call (auto-refreshed) +7. **Terminate Calls** - Use the "Terminate Calls!" button to end all active calls + +## API Endpoints + +| Method | Endpoint | Description | +|--------|----------|-------------| +| `GET` | `/targetCallToAcsUser?acsTarget=` | Initiates a call to the specified ACS user | +| `GET` | `/getParticipants` | Returns participant list in the current target call | +| `GET` | `/terminateCalls` | Terminates all active calls and resets state | +| `POST` | `/api/lobbyCallEventHandler` | Handles incoming Event Grid webhook events for lobby calls | +| `POST` | `/api/callbacks` | Handles ACS call automation callbacks (CallConnected, PlayCompleted, etc.) | +| `GET` | `/` | Serves the main web interface | + +## Workflow Overview + +1. **Lobby Call Setup**: User calls the ACS generated identity for lobby +2. **Call Answered**: Call Automation answers and plays waiting message +3. **Target Call Creation**: Admin creates a target call via web interface +4. **Automatic Join**: After play completes, lobby user is automatically moved to target call +5. **Participant Management**: View and manage participants through the web interface + +## Event Handling + +The application handles these key ACS events: +- **IncomingCall**: Automatically answers lobby calls +- **CallConnected**: Records caller information and plays lobby message +- **PlayCompleted**: Triggers automatic move of lobby user to target call +- **MoveParticipantsSucceeded**: Confirms successful participant transfer +- **CallDisconnected**: Handles call cleanup + +## Features + +- **Automatic Lobby Management**: Users are automatically placed in lobby with custom message +- **Real-time Participant Tracking**: Web interface shows current participants +- **Automatic Call Transfer**: Lobby users automatically join target call after message plays +- **Call State Management**: Proper cleanup and state management for all calls +- **Event Grid Integration**: Webhook support for incoming call events + +## Development Notes + +- The sample uses HTTP-only communication (no WebSocket client in the web interface) +- Participant information refreshes every 50 seconds automatically +- All call events and operations are logged to the console +- The server handles both HTTP requests and WebSocket upgrade for future extensibility + +## Troubleshooting + +### Common Issues: +- **Port already in use**: Kill existing Node.js processes with `taskkill /F /IM node.exe` +- **WebSocket connection errors**: Ensure DevTunnel is running and CALLBACK_URI is correct +- **Call not connecting**: Verify ACS connection string and cognitive services endpoint +- **Event Grid webhooks not working**: Check that webhook URL points to your public DevTunnel URL + +### Debugging: +- Check browser console for client-side errors +- Monitor server console for API call logs and ACS events +- Verify Event Grid webhook configuration in Azure portal +- Test endpoints individually using tools like Postman + +## Architecture + +The application consists of: +- **Express.js Backend**: Handles ACS Call Automation and webhook events +- **Web Interface**: Simple HTML/JavaScript frontend for call management +- **Azure Communication Services**: Provides calling capabilities +- **Azure Cognitive Services**: Powers text-to-speech for lobby messages +- **Azure Event Grid**: Delivers incoming call webhooks + +## Security Considerations + +- Store sensitive keys in environment variables, not in code +- Use HTTPS for production deployments +- Implement proper authentication for production use +- Validate webhook signatures from Azure Event Grid +- Restrict DevTunnel access in production environments \ No newline at end of file