@crvouga/mockingbird-service-livekit 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -4
- package/README.md +8 -4
- package/SUPPORT.md +6 -3
- package/dist/{chunk-RIGGRABC.js → chunk-FPXRYSAN.js} +122 -8
- package/dist/{chunk-RIGGRABC.js.map → chunk-FPXRYSAN.js.map} +2 -2
- package/dist/{chunk-2GG6WCKV.js → chunk-LCGGA6VQ.js} +2 -2
- package/dist/cli.js +2 -2
- package/dist/index.d.ts +47 -3
- package/dist/index.js +1 -1
- package/dist/server.d.ts +44 -0
- package/dist/server.js +2 -2
- package/openapi.yaml +183 -1
- package/package.json +3 -2
- /package/dist/{chunk-2GG6WCKV.js.map → chunk-LCGGA6VQ.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog — @crvouga/mockingbird-service-livekit
|
|
2
2
|
|
|
3
|
+
## 2.2.0 (2026-10-05)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- add scripted local API mock ([4a76a11](https://github.com/crvouga/mockingbird/commit/4a76a114e2efad45934e0a93cf29576fd418e15c))
|
|
8
|
+
- model room agent dispatches ([fb3bcf1](https://github.com/crvouga/mockingbird/commit/fb3bcf1f1d04975fa4533d95b69e6ba0e348f635))
|
|
9
|
+
|
|
10
|
+
### Fixes and improvements
|
|
11
|
+
|
|
12
|
+
- support embedded route parameters ([127cad9](https://github.com/crvouga/mockingbird/commit/127cad997ef106950c1b866070eea191ba54403f))
|
|
13
|
+
- preserve namespace URLs after main sync ([62a15ce](https://github.com/crvouga/mockingbird/commit/62a15ce9bd453069bde69e3a30c91efc01f8871b))
|
|
14
|
+
|
|
3
15
|
## 2.1.0 (2026-10-04)
|
|
4
16
|
|
|
5
17
|
### Features
|
|
@@ -12,10 +24,6 @@
|
|
|
12
24
|
- fill the embedded viewport ([c1a35a4](https://github.com/crvouga/mockingbird/commit/c1a35a4789389ee9cd06c286d09bd47c4d06c71e))
|
|
13
25
|
- make dialog cleanup immediate ([0c1a3c5](https://github.com/crvouga/mockingbird/commit/0c1a3c5b12584d50c19dcae595b951b8e5417b9c))
|
|
14
26
|
|
|
15
|
-
### Dependencies
|
|
16
|
-
|
|
17
|
-
- `@crvouga/mockingbird-service-sqlite`
|
|
18
|
-
|
|
19
27
|
## 2.0.0 (2026-10-04)
|
|
20
28
|
|
|
21
29
|
### ⚠️ Breaking changes
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> Familiar calls. Faithful echoes. Part of [Mockingbird](https://github.com/crvouga/mockingbird).
|
|
4
4
|
|
|
5
|
-
Stateful LiveKit mock for `livekit-server-sdk`. It serves Twirp JSON room APIs, validates genuine HS256 LiveKit grants, models participant/track/data state, exposes deterministic SIP and egress controls, and emits correctly signed lifecycle webhooks.
|
|
5
|
+
Stateful LiveKit mock for `livekit-server-sdk`. It serves Twirp JSON room and agent-dispatch APIs, validates genuine HS256 LiveKit grants, models participant/track/data state, exposes deterministic SIP and egress controls, and emits correctly signed lifecycle webhooks.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -25,6 +25,8 @@ const health = await fetch(`${mock.url}/__admin/health`)
|
|
|
25
25
|
|
|
26
26
|
Point `RoomServiceClient` at `mock.url`. Supported RoomService calls include CreateRoom, ListRooms, DeleteRoom, UpdateRoomMetadata, ListParticipants, GetParticipant, RemoveParticipant, UpdateParticipant, MutePublishedTrack, and SendData. Room creation is idempotent by name and participant identity is unique within a room.
|
|
27
27
|
|
|
28
|
+
`AgentDispatchClient` uses the same URL and genuine `roomAdmin` JWTs for `createDispatch`, `listDispatch`, `getDispatch`, and `deleteDispatch`. Both snake_case and camelCase request fields work. A dispatch creates a missing room, starts with no assigned jobs, and preserves its agent name and opaque metadata. Lists read shared room dispatch state, with an optional dispatch-id filter; deleting a dispatch removes its membership. Deleting or expiring a room removes its dispatches. Dispatch/job timestamps are mock-clock Unix seconds encoded as protobuf JSON strings (the SDK exposes bigint values). Tests exercise the existing 2.19.1 SDK and the reporter's exact 2.19.0 over HTTP.
|
|
29
|
+
|
|
28
30
|
## Controls
|
|
29
31
|
|
|
30
32
|
- `POST /__admin/rooms/:room/participants` joins a synthetic participant.
|
|
@@ -32,6 +34,8 @@ Point `RoomServiceClient` at `mock.url`. Supported RoomService calls include Cre
|
|
|
32
34
|
- `POST /__admin/rooms/:room/participants/:identity/tracks` publishes a track.
|
|
33
35
|
- `GET /__admin/rooms/:room/participants/:identity/inbox` inspects targeted data.
|
|
34
36
|
- `GET /__admin/resources` and `POST /__admin/resources/:id/transition` inspect and advance SIP/egress state.
|
|
37
|
+
- `POST /__admin/dispatches/:id/jobs` scripts one room job with `{status?: "JS_PENDING"|"JS_RUNNING"|"JS_SUCCESS"|"JS_FAILED", workerId?, agentId?, participantIdentity?, error?}`. First assignment creates a stable job id; later calls update it and stamp its start/end/update times. The default status is running.
|
|
38
|
+
- Dispatches and jobs participate in namespaces, reset, snapshots, Timeline and fault recovery alongside room state.
|
|
35
39
|
- Fault presets include rate limiting, network loss, and webhook duplicate/reorder/drop delivery.
|
|
36
40
|
|
|
37
41
|
Webhooks cover room, participant, track, egress, and SIP transitions. Each raw body is signed by a short-lived LiveKit access token whose `sha256` claim is accepted by the official `WebhookReceiver`.
|
|
@@ -39,7 +43,7 @@ Webhooks cover room, participant, track, egress, and SIP transitions. Each raw b
|
|
|
39
43
|
## API
|
|
40
44
|
|
|
41
45
|
- `LiveKitAPI`, `LiveKitAPIOptions`, `LiveKitEvent`: handler and event contract.
|
|
42
|
-
- `LiveKitRoom`, `LiveKitParticipant`, `LiveKitTrack`, `DataMessage`, `AsyncResource`: durable state.
|
|
46
|
+
- `LiveKitRoom`, `LiveKitParticipant`, `LiveKitTrack`, `DataMessage`, `AsyncResource`, `AgentDispatch`, `AgentJob`, `JobStatus`: durable state.
|
|
43
47
|
- `createRuntime`, `LiveKitRuntime`, `LiveKitRuntimeOptions`: full runtime and webhook hub.
|
|
44
48
|
- `LIVEKIT_NAMESPACE`, `LIVEKIT_PRESETS`: constants and fault controls.
|
|
45
49
|
- `document`, `operationIds`, `supportedOperationIds`: generated OpenAPI metadata.
|
|
@@ -47,6 +51,6 @@ Webhooks cover room, participant, track, egress, and SIP transitions. Each raw b
|
|
|
47
51
|
|
|
48
52
|
## Deliberately not modelled
|
|
49
53
|
|
|
50
|
-
WebRTC media transport, signaling sockets, transcoding, PSTN calls, production scaling, billing, and dashboards are not modelled. The deterministic server API and lifecycle contract is the initial fidelity boundary.
|
|
54
|
+
Real agent worker registration, job execution, publisher dispatch, restart/deployment policies, WebRTC media transport, signaling sockets, transcoding, PSTN calls, production scaling, billing, and dashboards are not modelled. The deterministic server API and lifecycle contract is the initial fidelity boundary.
|
|
51
55
|
|
|
52
|
-
Official
|
|
56
|
+
Official oracles: [LiveKit RoomService API](https://docs.livekit.io/reference/other/roomservice-api/) and [AgentDispatchService API](https://docs.livekit.io/reference/agents/agent-dispatch-service-api/).
|
package/SUPPORT.md
CHANGED
|
@@ -2,12 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
Generated from `openapi.yaml`; do not edit by hand.
|
|
4
4
|
|
|
5
|
-
- operations in spec: **
|
|
6
|
-
- supported by the mock: **
|
|
7
|
-
- parity enabled: **
|
|
5
|
+
- operations in spec: **6**
|
|
6
|
+
- supported by the mock: **6**
|
|
7
|
+
- parity enabled: **6**
|
|
8
8
|
|
|
9
9
|
| operationId | route | mock | parity | notes |
|
|
10
10
|
| --- | --- | --- | --- | --- |
|
|
11
|
+
| `CreateDispatch` | `POST /twirp/livekit.AgentDispatchService/CreateDispatch` | ✅ supported | ⚠️ unsafe (opt-in) | |
|
|
12
|
+
| `ListDispatch` | `POST /twirp/livekit.AgentDispatchService/ListDispatch` | ✅ supported | ✅ | |
|
|
13
|
+
| `DeleteDispatch` | `POST /twirp/livekit.AgentDispatchService/DeleteDispatch` | ✅ supported | ⚠️ unsafe (opt-in) | |
|
|
11
14
|
| `RoomService` | `POST /twirp/livekit.RoomService/{method}` | ✅ supported | ⚠️ unsafe (opt-in) | |
|
|
12
15
|
| `EgressService` | `POST /twirp/livekit.Egress/{method}` | ✅ supported | ⚠️ unsafe (opt-in) | |
|
|
13
16
|
| `SipService` | `POST /twirp/livekit.SIP/{method}` | ✅ supported | ⚠️ unsafe (opt-in) | |
|
|
@@ -2138,7 +2138,7 @@ var stateAdminRoutes = (routes) => {
|
|
|
2138
2138
|
};
|
|
2139
2139
|
|
|
2140
2140
|
// ../core/dist/version.js
|
|
2141
|
-
var PACKAGE_VERSION = true ? "2.
|
|
2141
|
+
var PACKAGE_VERSION = true ? "2.2.0" : UNRELEASED_VERSION;
|
|
2142
2142
|
|
|
2143
2143
|
// ../core/dist/signing.js
|
|
2144
2144
|
var encoder = new TextEncoder();
|
|
@@ -3369,19 +3369,22 @@ var verifyJwt = async (token, secrets, now) => {
|
|
|
3369
3369
|
var bodySha256 = async (body) => bytesToBase64(new Uint8Array(await crypto.subtle.digest("SHA-256", encoder2.encode(body))));
|
|
3370
3370
|
|
|
3371
3371
|
// src/generated/openapi.ts
|
|
3372
|
-
var document = JSON.parse(`{"openapi":"3.1.0","info":{"title":"LiveKit Server API (Mockingbird subset)","version":"2.19.1","description":"Twirp JSON room, participant, egress, and SIP contract."},"servers":[{"url":"https://example.livekit.cloud"}],"paths":{"/twirp/livekit.RoomService/{method}":{"post":{"operationId":"RoomService","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"parameters":[{"name":"method","in":"path","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Protobuf JSON response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Twirp error","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/twirp/livekit.Egress/{method}":{"post":{"operationId":"EgressService","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"parameters":[{"name":"method","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Protobuf JSON response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/twirp/livekit.SIP/{method}":{"post":{"operationId":"SipService","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"parameters":[{"name":"method","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Protobuf JSON response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}}}}`);
|
|
3373
|
-
var operationIds = ["RoomService", "EgressService", "SipService"];
|
|
3374
|
-
var supportedOperationIds = ["RoomService", "EgressService", "SipService"];
|
|
3372
|
+
var document = JSON.parse(`{"openapi":"3.1.0","info":{"title":"LiveKit Server API (Mockingbird subset)","version":"2.19.1","description":"Twirp JSON room, participant, agent dispatch, egress, and SIP contract."},"servers":[{"url":"https://example.livekit.cloud"}],"paths":{"/twirp/livekit.AgentDispatchService/CreateDispatch":{"post":{"operationId":"CreateDispatch","description":"Agent dispatch with a signed roomAdmin JWT; protobuf JSON names accept snake_case or camelCase.","security":[{"bearerAuth":[]}],"x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDispatchRequest"}}}},"responses":{"200":{"description":"Protobuf JSON result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentDispatch"}}}},"400":{"$ref":"#/components/responses/TwirpError"},"401":{"$ref":"#/components/responses/TwirpError"},"404":{"$ref":"#/components/responses/TwirpError"},"429":{"$ref":"#/components/responses/TwirpError"},"500":{"$ref":"#/components/responses/TwirpError"}}}},"/twirp/livekit.AgentDispatchService/ListDispatch":{"post":{"operationId":"ListDispatch","description":"Agent dispatch with a signed roomAdmin JWT; protobuf JSON names accept snake_case or camelCase.","security":[{"bearerAuth":[]}],"x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListDispatchRequest"}}}},"responses":{"200":{"description":"Protobuf JSON result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DispatchPage"}}}},"400":{"$ref":"#/components/responses/TwirpError"},"401":{"$ref":"#/components/responses/TwirpError"},"404":{"$ref":"#/components/responses/TwirpError"},"429":{"$ref":"#/components/responses/TwirpError"},"500":{"$ref":"#/components/responses/TwirpError"}}}},"/twirp/livekit.AgentDispatchService/DeleteDispatch":{"post":{"operationId":"DeleteDispatch","description":"Agent dispatch with a signed roomAdmin JWT; protobuf JSON names accept snake_case or camelCase.","security":[{"bearerAuth":[]}],"x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteDispatchRequest"}}}},"responses":{"200":{"description":"Protobuf JSON result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentDispatch"}}}},"400":{"$ref":"#/components/responses/TwirpError"},"401":{"$ref":"#/components/responses/TwirpError"},"404":{"$ref":"#/components/responses/TwirpError"},"429":{"$ref":"#/components/responses/TwirpError"},"500":{"$ref":"#/components/responses/TwirpError"}}}},"/twirp/livekit.RoomService/{method}":{"post":{"operationId":"RoomService","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"parameters":[{"name":"method","in":"path","required":true,"schema":{"type":"string"}},{"name":"Authorization","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Protobuf JSON response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Twirp error","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/twirp/livekit.Egress/{method}":{"post":{"operationId":"EgressService","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"parameters":[{"name":"method","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Protobuf JSON response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/twirp/livekit.SIP/{method}":{"post":{"operationId":"SipService","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":false}},"parameters":[{"name":"method","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Protobuf JSON response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"responses":{"TwirpError":{"description":"Twirp error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TwirpError"}}}}},"schemas":{"TwirpError":{"type":"object","required":["code","msg","meta"],"properties":{"code":{"type":"string"},"msg":{"type":"string"},"meta":{"type":"object","additionalProperties":{"type":"string"}}}},"RoomName":{"type":"string","minLength":1,"maxLength":128},"CreateDispatchRequest":{"type":"object","required":["room"],"anyOf":[{"required":["agentName"]},{"required":["agent_name"]}],"properties":{"room":{"$ref":"#/components/schemas/RoomName"},"agentName":{"type":"string","minLength":1,"maxLength":128},"agent_name":{"type":"string","minLength":1,"maxLength":128},"metadata":{"type":"string","maxLength":1024}}},"ListDispatchRequest":{"type":"object","required":["room"],"properties":{"room":{"$ref":"#/components/schemas/RoomName"},"dispatchId":{"type":"string","x-mockingbird-resource-ref":{"type":"agent_dispatch","missing":"AD_missing"}},"dispatch_id":{"type":"string","x-mockingbird-resource-ref":{"type":"agent_dispatch","missing":"AD_missing"}}}},"DeleteDispatchRequest":{"allOf":[{"$ref":"#/components/schemas/ListDispatchRequest"},{"type":"object","anyOf":[{"required":["dispatchId"]},{"required":["dispatch_id"]}]}]},"AgentDispatch":{"type":"object","required":["id","agentName","room","metadata","state"],"properties":{"id":{"type":"string","x-mockingbird-resource":{"type":"agent_dispatch","identity":true}},"agentName":{"type":"string"},"room":{"type":"string"},"metadata":{"type":"string"},"state":{"type":"object","required":["jobs","createdAt","deletedAt"],"properties":{"createdAt":{"type":"string","pattern":"^[0-9]+$","x-mockingbird-volatile":{"kind":"timestamp"}},"deletedAt":{"type":"string","pattern":"^[0-9]+$","x-mockingbird-volatile":{"kind":"timestamp"}},"jobs":{"type":"array","items":{"$ref":"#/components/schemas/AgentJob"}}}}}},"AgentJob":{"type":"object","required":["id","dispatchId","type","room","metadata","agentName","state"],"properties":{"id":{"type":"string"},"dispatchId":{"type":"string"},"type":{"type":"string","enum":["JT_ROOM"]},"room":{"type":"object","required":["sid","name","creationTime"],"properties":{"sid":{"type":"string"},"name":{"type":"string"},"creationTime":{"type":"string"}}},"metadata":{"type":"string"},"agentName":{"type":"string"},"state":{"type":"object","required":["status","error","startedAt","endedAt","updatedAt","participantIdentity","workerId","agentId"],"properties":{"status":{"type":"string","enum":["JS_PENDING","JS_RUNNING","JS_SUCCESS","JS_FAILED"]},"error":{"type":"string"},"startedAt":{"type":"string"},"endedAt":{"type":"string"},"updatedAt":{"type":"string"},"participantIdentity":{"type":"string"},"workerId":{"type":"string"},"agentId":{"type":"string"}}}}},"DispatchPage":{"type":"object","required":["agentDispatches"],"properties":{"agentDispatches":{"type":"array","items":{"$ref":"#/components/schemas/AgentDispatch"}}}}}}}`);
|
|
3373
|
+
var operationIds = ["CreateDispatch", "ListDispatch", "DeleteDispatch", "RoomService", "EgressService", "SipService"];
|
|
3374
|
+
var supportedOperationIds = ["CreateDispatch", "ListDispatch", "DeleteDispatch", "RoomService", "EgressService", "SipService"];
|
|
3375
3375
|
|
|
3376
3376
|
// src/state.ts
|
|
3377
|
+
var JOB_STATUSES = ["JS_PENDING", "JS_RUNNING", "JS_SUCCESS", "JS_FAILED"];
|
|
3377
3378
|
var LiveKitState = class {
|
|
3378
3379
|
rooms;
|
|
3380
|
+
dispatches;
|
|
3379
3381
|
participants;
|
|
3380
3382
|
inbox;
|
|
3381
3383
|
resources;
|
|
3382
3384
|
ids;
|
|
3383
3385
|
constructor(sqlite, namespace) {
|
|
3384
3386
|
this.rooms = new Collection(sqlite, namespace, "livekit_rooms");
|
|
3387
|
+
this.dispatches = new Collection(sqlite, namespace, "livekit_dispatches");
|
|
3385
3388
|
this.participants = new Collection(sqlite, namespace, "livekit_participants");
|
|
3386
3389
|
this.inbox = new Collection(sqlite, namespace, "livekit_inbox");
|
|
3387
3390
|
this.resources = new Collection(sqlite, namespace, "livekit_resources");
|
|
@@ -3417,6 +3420,18 @@ var LIVEKIT_PRESETS = {
|
|
|
3417
3420
|
};
|
|
3418
3421
|
var error = (status, message) => Response.json({ error: { type: "mockingbird_admin", message } }, { status });
|
|
3419
3422
|
var admin = (runtime) => ({
|
|
3423
|
+
"POST /dispatches/:id/jobs": ({ namespace, params, body }) => {
|
|
3424
|
+
if (!body || typeof body !== "object" || Array.isArray(body))
|
|
3425
|
+
return error(400, "expected a JSON object");
|
|
3426
|
+
const input = body;
|
|
3427
|
+
if (input.status !== void 0 && !JOB_STATUSES.includes(input.status))
|
|
3428
|
+
return error(400, "invalid job status");
|
|
3429
|
+
for (const key of ["workerId", "agentId", "participantIdentity", "error"])
|
|
3430
|
+
if (input[key] !== void 0 && typeof input[key] !== "string")
|
|
3431
|
+
return error(400, `${key} must be a string`);
|
|
3432
|
+
const job = runtime.instance(namespace).assignJob(params.id, input);
|
|
3433
|
+
return job ? Response.json(job) : error(404, "dispatch not found");
|
|
3434
|
+
},
|
|
3420
3435
|
"GET /rooms": ({ namespace }) => Response.json({
|
|
3421
3436
|
rooms: runtime.instance(namespace).state.rooms.list({ order: "oldest" }).map(({ value }) => value)
|
|
3422
3437
|
}),
|
|
@@ -3649,6 +3664,10 @@ var LiveKitAPI = class {
|
|
|
3649
3664
|
if (!room) return void 0;
|
|
3650
3665
|
for (const { value } of this.state.participants.list({ where: (p) => p.room === name }))
|
|
3651
3666
|
this.remove(name, value.identity);
|
|
3667
|
+
for (const { id } of this.state.dispatches.list({
|
|
3668
|
+
where: (dispatch) => dispatch.room === name
|
|
3669
|
+
}))
|
|
3670
|
+
this.state.dispatches.delete(id);
|
|
3652
3671
|
this.state.rooms.delete(name);
|
|
3653
3672
|
this.emit({ event: "room_finished", room: this.publicRoom(room) });
|
|
3654
3673
|
return room;
|
|
@@ -3699,6 +3718,98 @@ var LiveKitAPI = class {
|
|
|
3699
3718
|
);
|
|
3700
3719
|
return next;
|
|
3701
3720
|
}
|
|
3721
|
+
/** Script a single room job; workers and media transport are outside the mock. */
|
|
3722
|
+
assignJob(dispatchId, input) {
|
|
3723
|
+
const dispatch = this.state.dispatches.get(dispatchId);
|
|
3724
|
+
const room = dispatch && this.state.rooms.get(dispatch.room);
|
|
3725
|
+
if (!dispatch || !room) return void 0;
|
|
3726
|
+
const prior = dispatch.state.jobs[0];
|
|
3727
|
+
const at = String(Math.floor(this.now() / 1e3));
|
|
3728
|
+
const status = input.status ?? "JS_RUNNING";
|
|
3729
|
+
const job = {
|
|
3730
|
+
id: prior?.id ?? this.state.ids.next("AJ_", 24),
|
|
3731
|
+
dispatchId,
|
|
3732
|
+
type: "JT_ROOM",
|
|
3733
|
+
room: this.publicRoom(room),
|
|
3734
|
+
metadata: dispatch.metadata,
|
|
3735
|
+
agentName: dispatch.agentName,
|
|
3736
|
+
state: {
|
|
3737
|
+
status,
|
|
3738
|
+
error: input.error ?? prior?.state.error ?? "",
|
|
3739
|
+
startedAt: prior?.state.startedAt && prior.state.startedAt !== "0" ? prior.state.startedAt : status === "JS_PENDING" ? "0" : at,
|
|
3740
|
+
endedAt: status === "JS_SUCCESS" || status === "JS_FAILED" ? at : "0",
|
|
3741
|
+
updatedAt: at,
|
|
3742
|
+
participantIdentity: input.participantIdentity ?? prior?.state.participantIdentity ?? "",
|
|
3743
|
+
workerId: input.workerId ?? prior?.state.workerId ?? "",
|
|
3744
|
+
agentId: input.agentId ?? prior?.state.agentId ?? ""
|
|
3745
|
+
}
|
|
3746
|
+
};
|
|
3747
|
+
this.state.dispatches.update(dispatchId, {
|
|
3748
|
+
...dispatch,
|
|
3749
|
+
state: { ...dispatch.state, jobs: [job] }
|
|
3750
|
+
});
|
|
3751
|
+
return job;
|
|
3752
|
+
}
|
|
3753
|
+
dispatchView(dispatch) {
|
|
3754
|
+
const room = this.state.rooms.get(dispatch.room);
|
|
3755
|
+
return {
|
|
3756
|
+
...dispatch,
|
|
3757
|
+
state: {
|
|
3758
|
+
...dispatch.state,
|
|
3759
|
+
jobs: dispatch.state.jobs.map((job) => ({
|
|
3760
|
+
...job,
|
|
3761
|
+
...room ? { room: this.publicRoom(room) } : {}
|
|
3762
|
+
}))
|
|
3763
|
+
}
|
|
3764
|
+
};
|
|
3765
|
+
}
|
|
3766
|
+
dispatchService(method, input) {
|
|
3767
|
+
if (typeof input.room !== "string" || !input.room)
|
|
3768
|
+
return this.error("invalid_argument", "room is required");
|
|
3769
|
+
const roomName = input.room;
|
|
3770
|
+
const dispatchId = input.dispatchId ?? input.dispatch_id;
|
|
3771
|
+
if (dispatchId !== void 0 && typeof dispatchId !== "string")
|
|
3772
|
+
return this.error("invalid_argument", "dispatch_id must be a string");
|
|
3773
|
+
if (method === "CreateDispatch") {
|
|
3774
|
+
const agentName = input.agentName ?? input.agent_name;
|
|
3775
|
+
if (typeof agentName !== "string" || !agentName)
|
|
3776
|
+
return this.error("invalid_argument", "agent_name is required");
|
|
3777
|
+
if (input.metadata !== void 0 && typeof input.metadata !== "string")
|
|
3778
|
+
return this.error("invalid_argument", "metadata must be a string");
|
|
3779
|
+
this.createRoom({ name: roomName });
|
|
3780
|
+
const dispatch = {
|
|
3781
|
+
id: this.state.ids.next("AD_", 24),
|
|
3782
|
+
agentName,
|
|
3783
|
+
room: roomName,
|
|
3784
|
+
metadata: typeof input.metadata === "string" ? input.metadata : "",
|
|
3785
|
+
state: { jobs: [], createdAt: String(Math.floor(this.now() / 1e3)), deletedAt: "0" }
|
|
3786
|
+
};
|
|
3787
|
+
this.state.dispatches.insert(dispatch.id, dispatch);
|
|
3788
|
+
return this.json(this.dispatchView(dispatch));
|
|
3789
|
+
}
|
|
3790
|
+
if (method === "ListDispatch")
|
|
3791
|
+
return this.json({
|
|
3792
|
+
agentDispatches: this.state.dispatches.list({
|
|
3793
|
+
order: "oldest",
|
|
3794
|
+
where: (dispatch) => dispatch.room === roomName && (!dispatchId || dispatch.id === dispatchId)
|
|
3795
|
+
}).map(({ value }) => this.dispatchView(value))
|
|
3796
|
+
});
|
|
3797
|
+
if (method === "DeleteDispatch") {
|
|
3798
|
+
if (typeof dispatchId !== "string" || !dispatchId)
|
|
3799
|
+
return this.error("invalid_argument", "dispatch_id is required");
|
|
3800
|
+
const dispatch = this.state.dispatches.get(dispatchId);
|
|
3801
|
+
if (!dispatch || dispatch.room !== roomName)
|
|
3802
|
+
return this.error("not_found", "dispatch not found", 404);
|
|
3803
|
+
this.state.dispatches.delete(dispatchId);
|
|
3804
|
+
return this.json(
|
|
3805
|
+
this.dispatchView({
|
|
3806
|
+
...dispatch,
|
|
3807
|
+
state: { ...dispatch.state, deletedAt: String(Math.floor(this.now() / 1e3)) }
|
|
3808
|
+
})
|
|
3809
|
+
);
|
|
3810
|
+
}
|
|
3811
|
+
return this.error("unimplemented", `AgentDispatchService.${method} is not implemented`, 501);
|
|
3812
|
+
}
|
|
3702
3813
|
async authorize(request, service, method, input) {
|
|
3703
3814
|
const raw = request.headers.get("authorization")?.replace(/^Bearer\s+/i, "");
|
|
3704
3815
|
const claims = raw ? await verifyJwt(raw, this.keys, this.now()) : void 0;
|
|
@@ -3854,15 +3965,18 @@ var LiveKitAPI = class {
|
|
|
3854
3965
|
if (request.method !== "POST")
|
|
3855
3966
|
return this.error("bad_route", "Twirp endpoints require POST", 404);
|
|
3856
3967
|
const match2 = new URL(request.url).pathname.match(
|
|
3857
|
-
/^\/twirp\/livekit\.(RoomService|Egress|SIP)\/([^/]+)$/
|
|
3968
|
+
/^\/twirp\/livekit\.(RoomService|AgentDispatchService|Egress|SIP)\/([^/]+)$/
|
|
3858
3969
|
);
|
|
3859
3970
|
if (!match2) return this.error("bad_route", "unknown Twirp route", 404);
|
|
3860
3971
|
const service = match2[1];
|
|
3861
3972
|
const method = match2[2];
|
|
3862
|
-
const
|
|
3973
|
+
const parsed = await request.json().catch(() => ({}));
|
|
3974
|
+
if (service === "AgentDispatchService" && (!parsed || typeof parsed !== "object" || Array.isArray(parsed)))
|
|
3975
|
+
return this.error("invalid_argument", "expected a JSON object");
|
|
3976
|
+
const input = parsed;
|
|
3863
3977
|
if (!await this.authorize(request, service, method, input))
|
|
3864
3978
|
return this.error("unauthenticated", "invalid or insufficient LiveKit token", 401);
|
|
3865
|
-
return service === "RoomService" ? this.roomService(method, input) : this.asyncService(service, method, input);
|
|
3979
|
+
return service === "RoomService" ? this.roomService(method, input) : service === "AgentDispatchService" ? this.dispatchService(method, input) : this.asyncService(service, method, input);
|
|
3866
3980
|
}
|
|
3867
3981
|
};
|
|
3868
3982
|
|
|
@@ -3878,4 +3992,4 @@ export {
|
|
|
3878
3992
|
LIVEKIT_NAMESPACE,
|
|
3879
3993
|
LiveKitAPI
|
|
3880
3994
|
};
|
|
3881
|
-
//# sourceMappingURL=chunk-
|
|
3995
|
+
//# sourceMappingURL=chunk-FPXRYSAN.js.map
|