@xema/omni-protocol 0.1.99 → 0.1.101
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +60 -47
- package/dist/index.js +4 -3
- package/dist/testing.d.ts +12 -12
- package/dist/testing.js +110 -107
- package/dist/validation.d.ts +1 -1
- package/dist/validation.js +108 -72
- package/guide.md +250 -210
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -106,7 +106,7 @@ export type DialOutcome = "answered" | "busy" | "no-answer" | "unreachable" | "r
|
|
|
106
106
|
export declare const DIAL_OUTCOMES: readonly ["answered", "busy", "no-answer", "unreachable", "rejected", "cancelled", "unexplained"];
|
|
107
107
|
/**
|
|
108
108
|
* How the agent hears the call: on a `softphone`, where the host owns the audio and opens it
|
|
109
|
-
* through `
|
|
109
|
+
* through `openAudio`, or on a `deskPhone`, a handset the platform rings, where the host opens
|
|
110
110
|
* nothing and only shows the call. A voice manifest lists the phones its platform supports, and
|
|
111
111
|
* the host picks one for the login at authentication.
|
|
112
112
|
*/
|
|
@@ -433,7 +433,7 @@ export interface RecordingActions {
|
|
|
433
433
|
export interface TaskRecordingPolicy {
|
|
434
434
|
provider?: RecordingActions;
|
|
435
435
|
host?: RecordingActions & {
|
|
436
|
-
|
|
436
|
+
storageId: string;
|
|
437
437
|
};
|
|
438
438
|
}
|
|
439
439
|
/** Current evidence only. Expiry/disconnect means unknown, never a historical stop. */
|
|
@@ -478,7 +478,7 @@ export interface HostRecording {
|
|
|
478
478
|
announcesToCaller?: true;
|
|
479
479
|
actions: RecordingAction[];
|
|
480
480
|
/** Explicitly provisioned destinations. A task chooses one; no upload/storage fallback. */
|
|
481
|
-
|
|
481
|
+
storageIds: string[];
|
|
482
482
|
execute(request: HostRecordingRequest): Promise<RecordingCommandResult>;
|
|
483
483
|
}
|
|
484
484
|
/** Recording applies or fails; it never dials. Rejection without result means unknown. */
|
|
@@ -729,9 +729,9 @@ export type TaskPhase =
|
|
|
729
729
|
/** What the system does when a preview's deadline passes with no Call pressed. */
|
|
730
730
|
export type PreviewDeadline =
|
|
731
731
|
/** Provider initiates dialing when preparation ends; never a host timer command. */
|
|
732
|
-
"
|
|
732
|
+
"provider-dials"
|
|
733
733
|
/** Host initiates the ordinary call command when preparation ends. */
|
|
734
|
-
| "host-
|
|
734
|
+
| "host-dials"
|
|
735
735
|
/** Preparation target has elapsed; remain in preview until the agent presses Call. */
|
|
736
736
|
| "waits";
|
|
737
737
|
/** Who ends the task: the agent issuing `complete`, or the provider deciding it is over. */
|
|
@@ -866,7 +866,7 @@ export type TaskLeadAssist = {
|
|
|
866
866
|
* On a task that reached this agent by a lead's take-over: which member the call was taken from,
|
|
867
867
|
* and when. The provider moves the call from one agent to another, and the lead is the new agent,
|
|
868
868
|
* so the task is an ordinary assignment with the call's history -- offered whatever break the lead
|
|
869
|
-
* is on, counted against
|
|
869
|
+
* is on, counted against their capacity like any other call, provided they are under it and their voice channel is free.
|
|
870
870
|
*/
|
|
871
871
|
export interface TaskTakenOver {
|
|
872
872
|
memberId: UserId;
|
|
@@ -917,12 +917,12 @@ export interface Locked {
|
|
|
917
917
|
*/
|
|
918
918
|
export type Lockable<T> = T | Locked;
|
|
919
919
|
/**
|
|
920
|
-
* Who chose a task's capabilities. `
|
|
920
|
+
* Who chose a task's capabilities. `not-yet-read` is a fault the provider states on the task rather
|
|
921
921
|
* than hides: the platform's terms could not be read, and the set published is what the provider
|
|
922
922
|
* will honour, not what the platform permits.
|
|
923
923
|
*/
|
|
924
|
-
export type CapabilitySource = "queue" | "
|
|
925
|
-
export declare const CAPABILITY_SOURCES: readonly ["queue", "
|
|
924
|
+
export type CapabilitySource = "queue" | "nobody" | "not-yet-read";
|
|
925
|
+
export declare const CAPABILITY_SOURCES: readonly ["queue", "nobody", "not-yet-read"];
|
|
926
926
|
export type Task<C extends Channel = Channel> = {
|
|
927
927
|
/** The assignment this task is the record of, and its one identity. See `AssignmentId`. */
|
|
928
928
|
assignmentId: AssignmentId;
|
|
@@ -933,8 +933,8 @@ export type Task<C extends Channel = Channel> = {
|
|
|
933
933
|
capabilities: TaskCapabilities<C>;
|
|
934
934
|
/**
|
|
935
935
|
* Where the capabilities came from before the provider put them on the task, so a host can tell
|
|
936
|
-
* a fact from a fault: `queue` when somebody chose these terms, `
|
|
937
|
-
* the work over, `
|
|
936
|
+
* a fact from a fault: `queue` when somebody chose these terms, `nobody` when nothing handed
|
|
937
|
+
* the work over, `not-yet-read` when a queue was named and its terms could not be read -- the
|
|
938
938
|
* provider then publishes what it will honour and says so here, where the controls are drawn.
|
|
939
939
|
*/
|
|
940
940
|
capabilitySource: CapabilitySource;
|
|
@@ -953,7 +953,7 @@ export type Task<C extends Channel = Channel> = {
|
|
|
953
953
|
acceptance?: AcceptanceMode;
|
|
954
954
|
/**
|
|
955
955
|
* In `preview` only, and together: the preparation target and behavior when it elapses,
|
|
956
|
-
* and who acts then -- `
|
|
956
|
+
* and who acts then -- `provider-dials` makes the provider initiate dialing, `host-dials` makes the
|
|
957
957
|
* host issue Call, and `waits` keeps waiting for the agent without dialing or ending the task.
|
|
958
958
|
* Absent, the agent has as long as they need, without a preparation countdown.
|
|
959
959
|
*/
|
|
@@ -970,13 +970,13 @@ export type Task<C extends Channel = Channel> = {
|
|
|
970
970
|
onCall?: OnCall[];
|
|
971
971
|
leadAssist?: TaskLeadAssist;
|
|
972
972
|
takenOver?: TaskTakenOver;
|
|
973
|
-
|
|
973
|
+
audio?: TaskAudioState;
|
|
974
974
|
} : {
|
|
975
975
|
recording?: never;
|
|
976
976
|
onCall?: never;
|
|
977
977
|
leadAssist?: never;
|
|
978
978
|
takenOver?: never;
|
|
979
|
-
|
|
979
|
+
audio?: never;
|
|
980
980
|
});
|
|
981
981
|
/**
|
|
982
982
|
* What the provider wants of Omni's acceptance policy for one offer. On routed work, present only
|
|
@@ -1014,7 +1014,7 @@ export type TaskOutcome = {
|
|
|
1014
1014
|
failure: ProtocolFailure;
|
|
1015
1015
|
};
|
|
1016
1016
|
export declare const TASK_COMMAND_NAMES: {
|
|
1017
|
-
readonly voice: readonly ["answer", "decline", "
|
|
1017
|
+
readonly voice: readonly ["answer", "decline", "dial", "hold", "resume", "end-call", "terminate-call", "connect-back", "transfer", "lead-assist", "conference", "recording", "complete"];
|
|
1018
1018
|
readonly chat: readonly ["accept", "decline", "pause", "resume", "complete"];
|
|
1019
1019
|
readonly email: readonly ["accept", "decline", "complete"];
|
|
1020
1020
|
};
|
|
@@ -1030,7 +1030,7 @@ export type VoiceTaskCommand = {
|
|
|
1030
1030
|
}
|
|
1031
1031
|
/** In `preview`: place the call to the party whose record the agent has read. A dial, gated by the phase alone. */
|
|
1032
1032
|
| {
|
|
1033
|
-
type: "
|
|
1033
|
+
type: "dial";
|
|
1034
1034
|
dialId: DialId;
|
|
1035
1035
|
} | {
|
|
1036
1036
|
type: "hold";
|
|
@@ -1041,7 +1041,7 @@ export type VoiceTaskCommand = {
|
|
|
1041
1041
|
| {
|
|
1042
1042
|
type: "end-call";
|
|
1043
1043
|
}
|
|
1044
|
-
/** End the caller
|
|
1044
|
+
/** End the whole call at the provider: every channel on it, the agent's, the caller's and anyone else's. Gated by `terminateCall`. */
|
|
1045
1045
|
| {
|
|
1046
1046
|
type: "terminate-call";
|
|
1047
1047
|
}
|
|
@@ -1256,8 +1256,8 @@ export type BreakEndResult = {
|
|
|
1256
1256
|
status: "failed";
|
|
1257
1257
|
failure: ProtocolFailure;
|
|
1258
1258
|
};
|
|
1259
|
-
/** `
|
|
1260
|
-
export type TeamMemberAvailability = "ready" | "on-task" | "on-break" | "
|
|
1259
|
+
/** `elsewhere`: signed in here, and the host holds this agent's capacity for another provider (`count: 0`, host-stopped); not receiving this provider's work. */
|
|
1260
|
+
export type TeamMemberAvailability = "ready" | "on-task" | "on-break" | "elsewhere" | "signed-out";
|
|
1261
1261
|
export interface TeamMember {
|
|
1262
1262
|
id: UserId;
|
|
1263
1263
|
availability: TeamMemberAvailability;
|
|
@@ -1269,6 +1269,8 @@ export interface TeamMember {
|
|
|
1269
1269
|
tasks?: MemberTask[];
|
|
1270
1270
|
/** Present while this lead is on the member's call, listening, coaching or joined; absent otherwise. */
|
|
1271
1271
|
listening?: MemberListening;
|
|
1272
|
+
/** The member's own history for the day: sign-in, sign-out, breaks and productivity. Omitted where the provider cannot say. */
|
|
1273
|
+
shift?: MemberShift;
|
|
1272
1274
|
}
|
|
1273
1275
|
/** A member asking this lead to join their call, named by the member and the assignment. */
|
|
1274
1276
|
export interface LeadRequest {
|
|
@@ -1302,18 +1304,43 @@ export type MemberTask<C extends Channel = Channel> = {
|
|
|
1302
1304
|
onCall?: OnCall[];
|
|
1303
1305
|
leadAssist?: TaskLeadAssist;
|
|
1304
1306
|
takenOver?: TaskTakenOver;
|
|
1305
|
-
|
|
1307
|
+
audio?: TaskAudioState;
|
|
1306
1308
|
} : {
|
|
1307
1309
|
onCall?: never;
|
|
1308
1310
|
leadAssist?: never;
|
|
1309
1311
|
takenOver?: never;
|
|
1310
|
-
|
|
1312
|
+
audio?: never;
|
|
1311
1313
|
});
|
|
1312
|
-
/**
|
|
1314
|
+
/**
|
|
1315
|
+
* The lead on this member's call: which of the member's calls, in the mode they are heard, since
|
|
1316
|
+
* when. Its appearance on the team member list is the provider's word that the lead's audio is up,
|
|
1317
|
+
* and the application opens `openAudio` on the assignment named; its disappearance closes it.
|
|
1318
|
+
*/
|
|
1313
1319
|
export interface MemberListening {
|
|
1320
|
+
assignmentId: AssignmentId;
|
|
1314
1321
|
mode: ListeningMode;
|
|
1315
1322
|
since: IsoTimestamp;
|
|
1316
1323
|
}
|
|
1324
|
+
export type ShiftEventKind = "signed-in" | "signed-out" | "break-started" | "break-ended";
|
|
1325
|
+
export declare const SHIFT_EVENT_KINDS: readonly ["signed-in", "signed-out", "break-started", "break-ended"];
|
|
1326
|
+
export interface ShiftEvent {
|
|
1327
|
+
at: IsoTimestamp;
|
|
1328
|
+
kind: ShiftEventKind;
|
|
1329
|
+
}
|
|
1330
|
+
/**
|
|
1331
|
+
* The member's own history for the day, about the person rather than any one call: when they
|
|
1332
|
+
* signed in and out, today's totals as the provider counts them, each present only when the
|
|
1333
|
+
* provider knows it, and the day's sign-in, sign-out and break events, oldest first.
|
|
1334
|
+
*/
|
|
1335
|
+
export interface MemberShift {
|
|
1336
|
+
signedInAt: IsoTimestamp;
|
|
1337
|
+
signedOutAt?: IsoTimestamp;
|
|
1338
|
+
talkSeconds?: DurationSeconds;
|
|
1339
|
+
holdSeconds?: DurationSeconds;
|
|
1340
|
+
breakSeconds?: DurationSeconds;
|
|
1341
|
+
tasksHandled?: number;
|
|
1342
|
+
events?: ShiftEvent[];
|
|
1343
|
+
}
|
|
1317
1344
|
/**
|
|
1318
1345
|
* The lead's view of their team: published to a login that declares `capabilities.lead` while the
|
|
1319
1346
|
* lead has the team feature on, on every snapshot, and to nobody else. The provider keeps it
|
|
@@ -1425,20 +1452,20 @@ export type TeamCommandResult = {
|
|
|
1425
1452
|
* `ended` once primary interaction's audio ended, and the field omitted while none should be. The
|
|
1426
1453
|
* provider's word -- a desk attaches and renders audio from it, never from its own senses.
|
|
1427
1454
|
*/
|
|
1428
|
-
export type
|
|
1429
|
-
export interface
|
|
1455
|
+
export type TaskAudioState = "started" | "ended";
|
|
1456
|
+
export interface CallAudio {
|
|
1430
1457
|
remoteAudio: MediaStream;
|
|
1431
1458
|
setMuted(muted: boolean): void;
|
|
1432
1459
|
close(): void;
|
|
1433
1460
|
}
|
|
1434
|
-
export interface
|
|
1461
|
+
export interface OpenAudioRequest {
|
|
1435
1462
|
assignmentId: AssignmentId;
|
|
1436
1463
|
/** The agent's microphone as Omni captured it, `HostReport.audio.input.localAudio`; absent while that input is `unavailable`. */
|
|
1437
1464
|
localAudio?: MediaStream;
|
|
1438
1465
|
}
|
|
1439
|
-
export type
|
|
1466
|
+
export type OpenAudioResult = {
|
|
1440
1467
|
status: "opened";
|
|
1441
|
-
|
|
1468
|
+
audio: CallAudio;
|
|
1442
1469
|
} | {
|
|
1443
1470
|
status: "unavailable";
|
|
1444
1471
|
failure: ProtocolFailure;
|
|
@@ -1530,7 +1557,7 @@ export interface Snapshot<C extends Channel = Channel> {
|
|
|
1530
1557
|
/** The provider's own count of those tasks, stated rather than inferred: it must equal `tasks.length`, so a blank or unanswered state can never pass as a confirmed empty. */
|
|
1531
1558
|
taskCount: number;
|
|
1532
1559
|
contacts?: Contact[];
|
|
1533
|
-
|
|
1560
|
+
calendar?: ScheduledActivity[];
|
|
1534
1561
|
team?: TeamMembers;
|
|
1535
1562
|
}
|
|
1536
1563
|
/**
|
|
@@ -1540,7 +1567,7 @@ export interface Snapshot<C extends Channel = Channel> {
|
|
|
1540
1567
|
* tasks against it and needs no new signal when one ends. The agent is one person on several
|
|
1541
1568
|
* providers, and the host divides their capacity among them: `0` is host-stopped -- the agent's
|
|
1542
1569
|
* capacity is elsewhere for now, this provider assigns nothing and shows the member as
|
|
1543
|
-
* `
|
|
1570
|
+
* `elsewhere` -- and is not a break, which is the agent not working at all. The host restates a
|
|
1544
1571
|
* count of one or more when this provider has the agent's capacity again.
|
|
1545
1572
|
*/
|
|
1546
1573
|
export interface AgentCapacity {
|
|
@@ -1583,24 +1610,10 @@ export type ProviderEvent<C extends Channel = Channel> = {
|
|
|
1583
1610
|
type: "task-updated";
|
|
1584
1611
|
task: Task<C>;
|
|
1585
1612
|
} | {
|
|
1586
|
-
type: "task-
|
|
1613
|
+
type: "task-audio-started";
|
|
1587
1614
|
assignmentId: AssignmentId;
|
|
1588
1615
|
} | {
|
|
1589
|
-
type: "task-
|
|
1590
|
-
assignmentId: AssignmentId;
|
|
1591
|
-
}
|
|
1592
|
-
/**
|
|
1593
|
-
* The lead's channel is in a member's call -- listening, coaching or joined -- and its audio should
|
|
1594
|
-
* attach: on a softphone the application opens media on the member's assignment as it does for a
|
|
1595
|
-
* task. Voice, to a login that declares `lead`, never to the member.
|
|
1596
|
-
*/
|
|
1597
|
-
| {
|
|
1598
|
-
type: "team-media-started";
|
|
1599
|
-
memberId: UserId;
|
|
1600
|
-
assignmentId: AssignmentId;
|
|
1601
|
-
} | {
|
|
1602
|
-
type: "team-media-ended";
|
|
1603
|
-
memberId: UserId;
|
|
1616
|
+
type: "task-audio-ended";
|
|
1604
1617
|
assignmentId: AssignmentId;
|
|
1605
1618
|
} | {
|
|
1606
1619
|
type: "task-ended";
|
|
@@ -1643,7 +1656,7 @@ export type ProviderEvent<C extends Channel = Channel> = {
|
|
|
1643
1656
|
contacts: Contact[];
|
|
1644
1657
|
} | {
|
|
1645
1658
|
type: "calendar-updated";
|
|
1646
|
-
|
|
1659
|
+
calendar: ScheduledActivity[];
|
|
1647
1660
|
};
|
|
1648
1661
|
/**
|
|
1649
1662
|
* The `Provider` prefix survives here for a mechanical reason rather than a naming one: `Event`
|
|
@@ -1718,7 +1731,7 @@ export interface Connection<C extends Channel = Channel> {
|
|
|
1718
1731
|
/** Required when the login declares `capabilities.lead`: every lead act, on the team surface and nowhere else. */
|
|
1719
1732
|
executeTeam?(request: TeamCommandRequest): Promise<TeamCommandResult>;
|
|
1720
1733
|
/** Required of a voice adapter whose manifest lists `softphone`: on one, the call's audio lands in Omni. */
|
|
1721
|
-
|
|
1734
|
+
openAudio?(request: OpenAudioRequest): Promise<OpenAudioResult>;
|
|
1722
1735
|
/** Required when the login declares `capabilities.preferences`: the person's own choice, kept by the provider and republished as `authenticated`. */
|
|
1723
1736
|
setPreference?(request: SetPreferenceRequest): Promise<PreferenceResult>;
|
|
1724
1737
|
/** Records an interaction leg the host performed. Required of a softphone login's connection: the host mutes its microphone on any call, and the record is the provider's. */
|
package/dist/index.js
CHANGED
|
@@ -71,19 +71,19 @@ export const DEFAULT_LEVELS = [
|
|
|
71
71
|
export function effectiveLevels(declared) {
|
|
72
72
|
return [...(declared ?? DEFAULT_LEVELS)];
|
|
73
73
|
}
|
|
74
|
-
export const CAPABILITY_SOURCES = ["queue", "
|
|
74
|
+
export const CAPABILITY_SOURCES = ["queue", "nobody", "not-yet-read"];
|
|
75
75
|
// ---------------------------------------------------------------------------
|
|
76
76
|
// Task commands.
|
|
77
77
|
// ---------------------------------------------------------------------------
|
|
78
78
|
export const TASK_COMMAND_NAMES = {
|
|
79
|
-
voice: ["answer", "decline", "
|
|
79
|
+
voice: ["answer", "decline", "dial", "hold", "resume", "end-call", "terminate-call",
|
|
80
80
|
"connect-back", "transfer", "lead-assist", "conference", "recording", "complete"],
|
|
81
81
|
chat: ["accept", "decline", "pause", "resume", "complete"],
|
|
82
82
|
email: ["accept", "decline", "complete"],
|
|
83
83
|
};
|
|
84
84
|
/** The dial a command places, by the host's identity for it; `undefined` for a command that dials nothing. */
|
|
85
85
|
export function commandDialId(command) {
|
|
86
|
-
if (command.type === "connect-back" || command.type === "
|
|
86
|
+
if (command.type === "connect-back" || command.type === "dial")
|
|
87
87
|
return command.dialId;
|
|
88
88
|
if (command.type === "transfer" && (command.action === "cold" || command.action === "warm"))
|
|
89
89
|
return command.dialId;
|
|
@@ -95,6 +95,7 @@ export const BREAK_KINDS = [
|
|
|
95
95
|
"short-break", "meal", "rest", "training", "coaching",
|
|
96
96
|
"meeting", "administrative", "technical", "personal", "other",
|
|
97
97
|
];
|
|
98
|
+
export const SHIFT_EVENT_KINDS = ["signed-in", "signed-out", "break-started", "break-ended"];
|
|
98
99
|
export const OMNI_FAILURE_CODES = [
|
|
99
100
|
"omni.not-authenticated",
|
|
100
101
|
"omni.capability-not-enabled",
|
package/dist/testing.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export { ProtocolConformanceError, assertNoViolations, type ProtocolViolation }
|
|
|
7
7
|
* rules -- each optional part of a task, each optional part of the break state and team member list, each
|
|
8
8
|
* declared contribution, and each event type.
|
|
9
9
|
*/
|
|
10
|
-
declare const STATE_SUBJECTS: readonly ["tasks", "task.browsers", "task.attributes", "task.history", "task.onCall", "task.leadAssist", "task.takenOver", "task.
|
|
10
|
+
declare const STATE_SUBJECTS: readonly ["tasks", "task.browsers", "task.attributes", "task.history", "task.onCall", "task.leadAssist", "task.takenOver", "task.audio", "task.acceptance", "task.outcomes", "task.destinations", "task.custom", "task.locked", "break.reasons", "break.forced", "team.members", "team.requests", "team.tasks", "team.listening", "team.shift", "contacts", "calendar", "team.policies"];
|
|
11
11
|
export type ContractSubject = (typeof STATE_SUBJECTS)[number] | `event.${ProviderEvent["type"]}`;
|
|
12
12
|
export interface AdapterContractResult {
|
|
13
13
|
events: ProviderEventEnvelope[];
|
|
@@ -41,7 +41,7 @@ export interface ExerciseAdapterOptions {
|
|
|
41
41
|
collectOnly?: boolean;
|
|
42
42
|
/**
|
|
43
43
|
* Drive one ordinary lifecycle on the first task the provider offers -- accept it, open its
|
|
44
|
-
*
|
|
44
|
+
* audio on a softphone, hold and resume where offered, end the call where offered, complete it
|
|
45
45
|
* where the agent completes -- so the rules about a live call are reached rather than listed
|
|
46
46
|
* under `notExercised`. Off by default, since it issues commands against whatever platform the
|
|
47
47
|
* adapter is connected to: turn it on against a test backend.
|
|
@@ -177,9 +177,9 @@ export declare class TaskStream {
|
|
|
177
177
|
* Takes a resync snapshot -- a `snapshot` event, or the read a reloaded client makes -- as the
|
|
178
178
|
* state now, and first holds it to what the stream knew. A snapshot replaces state; it does not
|
|
179
179
|
* get to forget it. A task it carries that the stream already held may not go backwards, lose an
|
|
180
|
-
* entry of its record, return to
|
|
181
|
-
* held up:
|
|
182
|
-
* paused without its
|
|
180
|
+
* entry of its record, return to not-yet-read terms, or be at work without the audio the stream
|
|
181
|
+
* held up: audio ends on task-audio-ended and the call moves on, so a task still in-progress or
|
|
182
|
+
* paused without its audio is a snapshot that lost state, not a call that ended.
|
|
183
183
|
*/
|
|
184
184
|
resync(snapshot: unknown, at: string): ProtocolViolation[];
|
|
185
185
|
/** Replaces what is known with a snapshot's tasks, as a snapshot replaces Omni's state. */
|
|
@@ -205,12 +205,12 @@ export declare class BreakStream {
|
|
|
205
205
|
*/
|
|
206
206
|
export declare function assertBreakFollowsItsRequests(envelopes: readonly ProviderEventEnvelope[], snapshot?: Snapshot): void;
|
|
207
207
|
/**
|
|
208
|
-
* The
|
|
209
|
-
* with the snapshot it began from -- every task is introduced once, `task-
|
|
210
|
-
* `task-
|
|
211
|
-
* follows the
|
|
208
|
+
* The audio follows the task and never decides it. Given a provider's stream -- optionally seeded
|
|
209
|
+
* with the snapshot it began from -- every task is introduced once, `task-audio-started` and
|
|
210
|
+
* `task-audio-ended` alternate on work that has begun, audio ends only where it arrived, and what
|
|
211
|
+
* follows the audio ending is `completing` or `task-ended`.
|
|
212
212
|
*/
|
|
213
|
-
export declare function
|
|
213
|
+
export declare function assertAudioFollowsTheTask(envelopes: readonly ProviderEventEnvelope[], snapshot?: Snapshot): void;
|
|
214
214
|
/** A login store that lives in memory for the test: what most adapter tests hand `exerciseAdapter` as `context.store`. */
|
|
215
215
|
export declare function memoryStore(): LoginStore;
|
|
216
216
|
/**
|
|
@@ -252,14 +252,14 @@ export interface BreakOnTaskStep {
|
|
|
252
252
|
*/
|
|
253
253
|
export declare function assertBreakBeginsAfterTask(steps: readonly BreakOnTaskStep[]): void;
|
|
254
254
|
/**
|
|
255
|
-
* Validates the deadline derived from
|
|
255
|
+
* Validates the deadline derived from audio end and the task's fixed wrap allowance.
|
|
256
256
|
*
|
|
257
257
|
* A task with no allowance has no deadline, so `observedDeadline` must then be `undefined`: a
|
|
258
258
|
* host counting down what the provider left open is the violation, and so is a host counting
|
|
259
259
|
* nothing down when the provider set a clock. `toleranceMs` absorbs scheduler jitter in a real
|
|
260
260
|
* implementation; pass 0 to demand an exact match.
|
|
261
261
|
*/
|
|
262
|
-
export declare function assertWrapTimeout(task: Pick<TaskCompletion, "completionMode" | "wrapAllowance">,
|
|
262
|
+
export declare function assertWrapTimeout(task: Pick<TaskCompletion, "completionMode" | "wrapAllowance">, audioEndedAt: string, observedDeadline: string | undefined, toleranceMs?: number): void;
|
|
263
263
|
/** One browser in one task of one provider. `providerId` is `Manifest.id`, never `displayName`. */
|
|
264
264
|
export type BrowserIsolationScenario = BrowserSessionKeyInput;
|
|
265
265
|
/** Validates whether two task-browser definitions should share one browser session. */
|