@xema/omni-protocol 0.1.96 → 0.1.98
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 +51 -64
- package/dist/index.js +13 -13
- package/dist/testing.d.ts +6 -7
- package/dist/testing.js +97 -122
- package/dist/validation.d.ts +2 -2
- package/dist/validation.js +76 -88
- package/guide.md +201 -197
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -24,16 +24,15 @@ export type IsoTimestamp = string;
|
|
|
24
24
|
* provider id through `userKey()` before storing or comparing.
|
|
25
25
|
*/
|
|
26
26
|
export type UserId = string;
|
|
27
|
-
/** A non-empty, opaque task identifier unique within one provider. Scope it with `taskKey()`. */
|
|
28
|
-
export type TaskId = string;
|
|
29
27
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
28
|
+
* The provider's name for one assignment: the call routed to this agent, from the offer until the
|
|
29
|
+
* task ends. Non-empty, opaque, unique within the provider and never reused while the provider is
|
|
30
|
+
* still speaking about it -- a lead names a member's assignment from another login, so the scope is
|
|
31
|
+
* the provider, not the login. What the platform calls its own record, and whether it reuses that
|
|
32
|
+
* name, is the adapter's business: a platform that reoffers a closed call under the same handle
|
|
33
|
+
* seconds later is why the adapter, not the desk, is held to this. Scope it with `assignmentKey()`.
|
|
35
34
|
*/
|
|
36
|
-
export type
|
|
35
|
+
export type AssignmentId = string;
|
|
37
36
|
/**
|
|
38
37
|
* The host's identity for one dial, minted before the command leaves and unique across the
|
|
39
38
|
* installation. A dial is the one command whose outcome arrives later and apart, so the provider
|
|
@@ -483,8 +482,7 @@ export type RecordingCommand = {
|
|
|
483
482
|
recordingId: string;
|
|
484
483
|
});
|
|
485
484
|
export interface HostRecordingReport {
|
|
486
|
-
|
|
487
|
-
allocationId: AllocationId;
|
|
485
|
+
assignmentId: AssignmentId;
|
|
488
486
|
state: RecordingState;
|
|
489
487
|
}
|
|
490
488
|
/** Host declaration in ConnectContext, not the provider-owned Manifest. */
|
|
@@ -501,8 +499,7 @@ export type RecordingCommandResult = Exclude<TaskCommandResult, {
|
|
|
501
499
|
status: "dialling";
|
|
502
500
|
}>;
|
|
503
501
|
export interface HostRecordingRequest {
|
|
504
|
-
|
|
505
|
-
allocationId: AllocationId;
|
|
502
|
+
assignmentId: AssignmentId;
|
|
506
503
|
command: RecordingCommand & {
|
|
507
504
|
source: "host";
|
|
508
505
|
};
|
|
@@ -693,7 +690,7 @@ export type TaskCapabilities<C extends Channel = Channel> = C extends "voice" ?
|
|
|
693
690
|
* mistype and unreadable as an argument.
|
|
694
691
|
*/
|
|
695
692
|
export declare const BROWSER_ISOLATION_SCHEMES: {
|
|
696
|
-
readonly
|
|
693
|
+
readonly PROVIDER_NAME__ASSIGNMENT_ID__TAB_NAME: "ProviderName.AssignmentId.TabName";
|
|
697
694
|
readonly TAB_NAME: "TabName";
|
|
698
695
|
readonly PROVIDER_NAME__TASK_TYPE_NAME__TAB_NAME: "ProviderName.TaskTypeName.TabName";
|
|
699
696
|
readonly PROVIDER_NAME__TAB_NAME: "ProviderName.TabName";
|
|
@@ -730,7 +727,7 @@ export type PersonalBrowser = Browser;
|
|
|
730
727
|
export declare const ALLOWED_BROWSER_URL_SCHEMES: readonly ["http:", "https:"];
|
|
731
728
|
export declare function isAllowedBrowserUrl(url: string): boolean;
|
|
732
729
|
export type TaskPhase =
|
|
733
|
-
/**
|
|
730
|
+
/** Assigned to this agent and not yet accepted. */
|
|
734
731
|
"pending"
|
|
735
732
|
/** Accepted, and not yet started. */
|
|
736
733
|
| "confirmed"
|
|
@@ -765,7 +762,7 @@ export type TaskAttribute = TaskAttributeBase & ({
|
|
|
765
762
|
type: "timestamp";
|
|
766
763
|
at: IsoTimestamp;
|
|
767
764
|
});
|
|
768
|
-
export type
|
|
765
|
+
export type HistoryStep = "queued" | "offered" | "answered" | "held" | "muted" | "transferred" | "conferenced" | "unanswered";
|
|
769
766
|
/**
|
|
770
767
|
* The call record: the steps that brought the task here, one entry per occurrence and oldest
|
|
771
768
|
* first, and what they add up to before this agent -- stated by the provider from its own record,
|
|
@@ -773,8 +770,8 @@ export type InteractionStep = "queued" | "offered" | "answered" | "held" | "mute
|
|
|
773
770
|
* absent when it does not; a plausible nought is the fallback the no-fallbacks rule forbids. The
|
|
774
771
|
* record rides on the task and is replaced with it, so a late entry corrects the sums.
|
|
775
772
|
*/
|
|
776
|
-
export interface
|
|
777
|
-
steps:
|
|
773
|
+
export interface TaskHistory {
|
|
774
|
+
steps: TaskHistoryStep[];
|
|
778
775
|
/** Seconds others spent working on it before this agent. */
|
|
779
776
|
interactionSeconds?: DurationSeconds;
|
|
780
777
|
/** Seconds the caller spent on hold at others' hands. */
|
|
@@ -784,8 +781,8 @@ export interface TaskInteractionHistory {
|
|
|
784
781
|
/** How many times the task changed hands. */
|
|
785
782
|
transfers?: number;
|
|
786
783
|
}
|
|
787
|
-
export interface
|
|
788
|
-
step:
|
|
784
|
+
export interface TaskHistoryStep {
|
|
785
|
+
step: HistoryStep;
|
|
789
786
|
at: IsoTimestamp;
|
|
790
787
|
/**
|
|
791
788
|
* On a step that dialled -- `transferred`, `conferenced`, `unanswered` -- the host's identity for
|
|
@@ -883,6 +880,8 @@ export type TaskLeadAssist = {
|
|
|
883
880
|
*/
|
|
884
881
|
export interface TaskAssisting {
|
|
885
882
|
memberId: UserId;
|
|
883
|
+
/** The member's assignment the lead joined: the lead's task has an assignment of its own. */
|
|
884
|
+
assignmentId: AssignmentId;
|
|
886
885
|
note?: string;
|
|
887
886
|
since: IsoTimestamp;
|
|
888
887
|
}
|
|
@@ -895,8 +894,7 @@ export interface TaskAssisting {
|
|
|
895
894
|
*/
|
|
896
895
|
export interface TaskListening {
|
|
897
896
|
memberId: UserId;
|
|
898
|
-
|
|
899
|
-
allocationId: AllocationId;
|
|
897
|
+
assignmentId: AssignmentId;
|
|
900
898
|
mode: ListeningMode;
|
|
901
899
|
since: IsoTimestamp;
|
|
902
900
|
}
|
|
@@ -952,9 +950,8 @@ export type Lockable<T> = T | Locked;
|
|
|
952
950
|
export type CapabilitySource = "queue" | "ungoverned" | "undetermined";
|
|
953
951
|
export declare const CAPABILITY_SOURCES: readonly ["queue", "ungoverned", "undetermined"];
|
|
954
952
|
export type Task<C extends Channel = Channel> = {
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
allocationId: AllocationId;
|
|
953
|
+
/** The assignment this task is the record of, and its one identity. See `AssignmentId`. */
|
|
954
|
+
assignmentId: AssignmentId;
|
|
958
955
|
title: string;
|
|
959
956
|
channel: C;
|
|
960
957
|
/** The provider's own name for a category of work. Finer-grained than a channel. */
|
|
@@ -991,7 +988,7 @@ export type Task<C extends Channel = Channel> = {
|
|
|
991
988
|
/** The identifier an agent reads back to a customer, where the provider has one. */
|
|
992
989
|
reference?: string;
|
|
993
990
|
attributes?: TaskAttribute[];
|
|
994
|
-
|
|
991
|
+
history?: TaskHistory;
|
|
995
992
|
} & TaskCompletion & (C extends "voice" ? {
|
|
996
993
|
recording?: {
|
|
997
994
|
provider?: RecordingState;
|
|
@@ -1036,7 +1033,7 @@ export type TaskOutcome = {
|
|
|
1036
1033
|
by: "agent" | "provider" | "party";
|
|
1037
1034
|
reason?: string;
|
|
1038
1035
|
}
|
|
1039
|
-
/** Only the phases in which somebody is still being waited on can expire; an offer that lapses at `
|
|
1036
|
+
/** Only the phases in which somebody is still being waited on can expire; an offer that lapses at `assignmentExpiresAt` names `pending`. */
|
|
1040
1037
|
| {
|
|
1041
1038
|
type: "expired";
|
|
1042
1039
|
phase: "pending" | "confirmed" | "preview";
|
|
@@ -1179,8 +1176,7 @@ export interface CustomTaskCommand {
|
|
|
1179
1176
|
}
|
|
1180
1177
|
export type TaskCommand<C extends Channel = Channel> = (C extends "voice" ? VoiceTaskCommand : C extends "chat" ? ChatTaskCommand : EmailTaskCommand) | CustomTaskCommand;
|
|
1181
1178
|
export interface TaskCommandRequest<C extends Channel = Channel> {
|
|
1182
|
-
|
|
1183
|
-
allocationId: AllocationId;
|
|
1179
|
+
assignmentId: AssignmentId;
|
|
1184
1180
|
command: TaskCommand<C>;
|
|
1185
1181
|
}
|
|
1186
1182
|
/**
|
|
@@ -1274,7 +1270,7 @@ export interface BreakState {
|
|
|
1274
1270
|
activeReasonId?: string;
|
|
1275
1271
|
forced?: ForcedBreak;
|
|
1276
1272
|
}
|
|
1277
|
-
/** Capacity is a statement, not a request: it is taken, never refused. A provider that cannot carry the count
|
|
1273
|
+
/** Capacity is a statement, not a request: it is taken, never refused. A provider that cannot carry the count assigns within what it can and says so on a `diagnostic`. */
|
|
1278
1274
|
export type CapacityResult = {
|
|
1279
1275
|
status: "applied";
|
|
1280
1276
|
};
|
|
@@ -1318,8 +1314,7 @@ export interface TeamMember {
|
|
|
1318
1314
|
export interface LeadRequest {
|
|
1319
1315
|
id: string;
|
|
1320
1316
|
memberId: UserId;
|
|
1321
|
-
|
|
1322
|
-
allocationId: AllocationId;
|
|
1317
|
+
assignmentId: AssignmentId;
|
|
1323
1318
|
note?: string;
|
|
1324
1319
|
since: IsoTimestamp;
|
|
1325
1320
|
}
|
|
@@ -1423,8 +1418,7 @@ export interface VoiceMediaSession {
|
|
|
1423
1418
|
close(): void;
|
|
1424
1419
|
}
|
|
1425
1420
|
export interface OpenMediaRequest {
|
|
1426
|
-
|
|
1427
|
-
allocationId: AllocationId;
|
|
1421
|
+
assignmentId: AssignmentId;
|
|
1428
1422
|
/** The agent's microphone as Omni captured it, `HostReport.audio.input.localAudio`; absent while that input is `unavailable`. */
|
|
1429
1423
|
localAudio?: MediaStream;
|
|
1430
1424
|
}
|
|
@@ -1482,9 +1476,8 @@ export type SetPreferenceRequest = {
|
|
|
1482
1476
|
* legs it performs, so `seconds` may say how long so far at any time; the end is stated, never
|
|
1483
1477
|
* inferred from a number's presence. What the adapter forwards upstream, and how often, is its own.
|
|
1484
1478
|
*/
|
|
1485
|
-
export type
|
|
1486
|
-
|
|
1487
|
-
allocationId: AllocationId;
|
|
1479
|
+
export type HistoryReport = {
|
|
1480
|
+
assignmentId: AssignmentId;
|
|
1488
1481
|
at: IsoTimestamp;
|
|
1489
1482
|
} & (
|
|
1490
1483
|
/** A muted leg says whose the silence was: the host's own Mute, or the station's slider or system. */
|
|
@@ -1492,7 +1485,7 @@ export type InteractionReport = {
|
|
|
1492
1485
|
step: "muted";
|
|
1493
1486
|
mutedBy: MutedBy;
|
|
1494
1487
|
} | {
|
|
1495
|
-
step: Exclude<
|
|
1488
|
+
step: Exclude<HistoryStep, "muted">;
|
|
1496
1489
|
mutedBy?: never;
|
|
1497
1490
|
}) & ({
|
|
1498
1491
|
ended: true;
|
|
@@ -1501,7 +1494,7 @@ export type InteractionReport = {
|
|
|
1501
1494
|
ended?: never;
|
|
1502
1495
|
seconds?: DurationSeconds;
|
|
1503
1496
|
});
|
|
1504
|
-
export type
|
|
1497
|
+
export type HistoryReportResult = {
|
|
1505
1498
|
status: "recorded";
|
|
1506
1499
|
at: IsoTimestamp;
|
|
1507
1500
|
} | {
|
|
@@ -1527,12 +1520,12 @@ export interface Snapshot<C extends Channel = Channel> {
|
|
|
1527
1520
|
team?: TeamMembers;
|
|
1528
1521
|
}
|
|
1529
1522
|
/**
|
|
1530
|
-
* How many tasks this provider may have
|
|
1523
|
+
* How many tasks this provider may have assigned to the agent at once.
|
|
1531
1524
|
*
|
|
1532
1525
|
* An absolute ceiling standing until Omni restates it. The provider counts its own outstanding
|
|
1533
1526
|
* tasks against it and needs no new signal when one ends. The agent is one person on several
|
|
1534
1527
|
* providers, and the host divides their capacity among them: `0` is host-stopped -- the agent's
|
|
1535
|
-
* capacity is elsewhere for now, this provider
|
|
1528
|
+
* capacity is elsewhere for now, this provider assigns nothing and shows the member as
|
|
1536
1529
|
* `reserved` -- and is not a break, which is the agent not working at all. The host restates a
|
|
1537
1530
|
* count of one or more when this provider has the agent's capacity again.
|
|
1538
1531
|
*/
|
|
@@ -1571,28 +1564,25 @@ export type ProviderEvent<C extends Channel = Channel> = {
|
|
|
1571
1564
|
} | {
|
|
1572
1565
|
type: "task-offered";
|
|
1573
1566
|
task: Task<C>;
|
|
1574
|
-
|
|
1567
|
+
assignmentExpiresAt?: IsoTimestamp;
|
|
1575
1568
|
} | {
|
|
1576
1569
|
type: "task-updated";
|
|
1577
1570
|
task: Task<C>;
|
|
1578
1571
|
} | {
|
|
1579
1572
|
type: "task-media-started";
|
|
1580
|
-
|
|
1581
|
-
allocationId: AllocationId;
|
|
1573
|
+
assignmentId: AssignmentId;
|
|
1582
1574
|
} | {
|
|
1583
1575
|
type: "task-media-ended";
|
|
1584
|
-
|
|
1585
|
-
allocationId: AllocationId;
|
|
1576
|
+
assignmentId: AssignmentId;
|
|
1586
1577
|
} | {
|
|
1587
1578
|
type: "task-ended";
|
|
1588
|
-
|
|
1589
|
-
allocationId: AllocationId;
|
|
1579
|
+
assignmentId: AssignmentId;
|
|
1590
1580
|
outcome: TaskOutcome;
|
|
1591
1581
|
}
|
|
1592
1582
|
/**
|
|
1593
1583
|
* How a dial the host placed ended, once, either way -- `answered` is stated, never read off
|
|
1594
1584
|
* somebody appearing on the call, and says what happened to the dial; who is on the call is
|
|
1595
|
-
* `Task.onCall`. `
|
|
1585
|
+
* `Task.onCall`. `assignmentId` is the task the dial was placed on, resolved from the dial and never
|
|
1596
1586
|
* from what the agent is looking at, and that task may already have ended: a dial placed late
|
|
1597
1587
|
* routinely outlives its call. `reason` is the switch's own words, shown to the agent as such.
|
|
1598
1588
|
*/
|
|
@@ -1600,8 +1590,7 @@ export type ProviderEvent<C extends Channel = Channel> = {
|
|
|
1600
1590
|
type: "dial-outcome";
|
|
1601
1591
|
dialId: DialId;
|
|
1602
1592
|
outcome: DialOutcome;
|
|
1603
|
-
|
|
1604
|
-
allocationId?: AllocationId;
|
|
1593
|
+
assignmentId?: AssignmentId;
|
|
1605
1594
|
destinationId?: string;
|
|
1606
1595
|
reason?: string;
|
|
1607
1596
|
} | {
|
|
@@ -1617,8 +1606,7 @@ export type ProviderEvent<C extends Channel = Channel> = {
|
|
|
1617
1606
|
type: "diagnostic";
|
|
1618
1607
|
expected: string;
|
|
1619
1608
|
observed: string;
|
|
1620
|
-
|
|
1621
|
-
allocationId?: AllocationId;
|
|
1609
|
+
assignmentId?: AssignmentId;
|
|
1622
1610
|
} | {
|
|
1623
1611
|
type: "team-updated";
|
|
1624
1612
|
team: TeamMembers;
|
|
@@ -1641,7 +1629,7 @@ export interface ProviderEventEnvelope<C extends Channel = Channel> {
|
|
|
1641
1629
|
occurredAt: IsoTimestamp;
|
|
1642
1630
|
event: ProviderEvent<C>;
|
|
1643
1631
|
}
|
|
1644
|
-
export declare const OMNI_FAILURE_CODES: readonly ["omni.not-authenticated", "omni.capability-not-enabled", "omni.
|
|
1632
|
+
export declare const OMNI_FAILURE_CODES: readonly ["omni.not-authenticated", "omni.capability-not-enabled", "omni.assignment-not-found", "omni.destination-not-permitted", "omni.phone-not-permitted", "omni.rate-limited", "omni.unavailable", "omni.break-already-committed"];
|
|
1645
1633
|
export type OmniFailureCode = (typeof OMNI_FAILURE_CODES)[number];
|
|
1646
1634
|
/**
|
|
1647
1635
|
* What the host refused, told to the adapter that published it: a snapshot the host would not
|
|
@@ -1682,7 +1670,7 @@ export interface Connection<C extends Channel = Channel> {
|
|
|
1682
1670
|
subscribe(listener: (envelope: ProviderEventEnvelope<C>) => void): Unsubscribe;
|
|
1683
1671
|
/** Told what the host refused, snapshot or event, with every rule broken. Always; a refusal is visible on both sides. */
|
|
1684
1672
|
refused(report: Refusal): void;
|
|
1685
|
-
/** Nothing may be
|
|
1673
|
+
/** Nothing may be assigned until a capacity is stated, so every connection receives it. */
|
|
1686
1674
|
setCapacity(capacity: AgentCapacity): Promise<CapacityResult>;
|
|
1687
1675
|
execute(request: TaskCommandRequest<C>): Promise<TaskCommandResult>;
|
|
1688
1676
|
disconnect(): Promise<void>;
|
|
@@ -1712,7 +1700,7 @@ export interface Connection<C extends Channel = Channel> {
|
|
|
1712
1700
|
/** Required when the login declares `capabilities.preferences`: the person's own choice, kept by the provider and republished as `authenticated`. */
|
|
1713
1701
|
setPreference?(request: SetPreferenceRequest): Promise<PreferenceResult>;
|
|
1714
1702
|
/** 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. */
|
|
1715
|
-
recordStep?(report:
|
|
1703
|
+
recordStep?(report: HistoryReport): Promise<HistoryReportResult>;
|
|
1716
1704
|
}
|
|
1717
1705
|
export interface Adapter<C extends Channel = Channel> {
|
|
1718
1706
|
manifest: Manifest<C>;
|
|
@@ -1774,7 +1762,7 @@ export declare const DEFAULT_TASK_TYPE_PRESENTATION: {
|
|
|
1774
1762
|
* string. Encoding before joining is what stops a provider id containing a separator from
|
|
1775
1763
|
* forging another provider's key.
|
|
1776
1764
|
*/
|
|
1777
|
-
export declare const
|
|
1765
|
+
export declare const assignmentKey: (providerId: string, assignmentId: AssignmentId) => string;
|
|
1778
1766
|
/**
|
|
1779
1767
|
* The same treatment for a `UserId`, and needed for the same reason.
|
|
1780
1768
|
*
|
|
@@ -1783,19 +1771,18 @@ export declare const taskKey: (providerId: string, taskId: TaskId) => string;
|
|
|
1783
1771
|
* same provider; anything wider goes through this.
|
|
1784
1772
|
*/
|
|
1785
1773
|
export declare const userKey: (providerId: string, userId: UserId) => string;
|
|
1786
|
-
/** Every
|
|
1787
|
-
export declare const
|
|
1774
|
+
/** Every history step somebody takes part in. `queued` is the one nobody does. */
|
|
1775
|
+
export declare const HISTORY_STEPS_WITH_A_PERSON: readonly ["offered", "answered", "held", "muted", "transferred", "conferenced", "unanswered"];
|
|
1788
1776
|
/** The steps a dial writes, and so the only ones that carry a `dialId` and a `destinationId`. */
|
|
1789
|
-
export declare const
|
|
1790
|
-
export declare const
|
|
1777
|
+
export declare const HISTORY_STEPS_THAT_DIAL: readonly ["transferred", "conferenced", "unanswered"];
|
|
1778
|
+
export declare const historyStepDials: (step: HistoryStep) => boolean;
|
|
1791
1779
|
/** Whether an absent `by` means "could not attribute" rather than "nobody was involved". */
|
|
1792
|
-
export declare function
|
|
1780
|
+
export declare function historyStepExpectsAPerson(step: HistoryStep): boolean;
|
|
1793
1781
|
export interface BrowserSessionKeyInput {
|
|
1794
1782
|
/** `Manifest.id`, never `displayName`: only the id is unique across an installation and stable. */
|
|
1795
1783
|
providerId: string;
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
allocationId: AllocationId;
|
|
1784
|
+
/** The task's assignment: a task-scoped session lives one assignment, never the next customer's. */
|
|
1785
|
+
assignmentId: AssignmentId;
|
|
1799
1786
|
/** `Task.taskType`. */
|
|
1800
1787
|
taskType: string;
|
|
1801
1788
|
browser: TaskBrowser;
|
package/dist/index.js
CHANGED
|
@@ -40,7 +40,7 @@ export const RECORDING_ACTIONS = ["start", "pause", "resume", "stop", "cancel"];
|
|
|
40
40
|
* mistype and unreadable as an argument.
|
|
41
41
|
*/
|
|
42
42
|
export const BROWSER_ISOLATION_SCHEMES = {
|
|
43
|
-
|
|
43
|
+
PROVIDER_NAME__ASSIGNMENT_ID__TAB_NAME: "ProviderName.AssignmentId.TabName",
|
|
44
44
|
TAB_NAME: "TabName",
|
|
45
45
|
PROVIDER_NAME__TASK_TYPE_NAME__TAB_NAME: "ProviderName.TaskTypeName.TabName",
|
|
46
46
|
PROVIDER_NAME__TAB_NAME: "ProviderName.TabName",
|
|
@@ -104,7 +104,7 @@ export const breakKindAllowsListening = (kind) => kind !== undefined && LISTENIN
|
|
|
104
104
|
export const OMNI_FAILURE_CODES = [
|
|
105
105
|
"omni.not-authenticated",
|
|
106
106
|
"omni.capability-not-enabled",
|
|
107
|
-
"omni.
|
|
107
|
+
"omni.assignment-not-found",
|
|
108
108
|
"omni.destination-not-permitted",
|
|
109
109
|
"omni.phone-not-permitted",
|
|
110
110
|
"omni.rate-limited",
|
|
@@ -150,7 +150,7 @@ export const DEFAULT_TASK_TYPE_PRESENTATION = {
|
|
|
150
150
|
* string. Encoding before joining is what stops a provider id containing a separator from
|
|
151
151
|
* forging another provider's key.
|
|
152
152
|
*/
|
|
153
|
-
export const
|
|
153
|
+
export const assignmentKey = (providerId, assignmentId) => `${encodeURIComponent(providerId)}:${encodeURIComponent(assignmentId)}`;
|
|
154
154
|
/**
|
|
155
155
|
* The same treatment for a `UserId`, and needed for the same reason.
|
|
156
156
|
*
|
|
@@ -159,19 +159,19 @@ export const taskKey = (providerId, taskId) => `${encodeURIComponent(providerId)
|
|
|
159
159
|
* same provider; anything wider goes through this.
|
|
160
160
|
*/
|
|
161
161
|
export const userKey = (providerId, userId) => `${encodeURIComponent(providerId)}:${encodeURIComponent(userId)}`;
|
|
162
|
-
/** Every
|
|
163
|
-
export const
|
|
162
|
+
/** Every history step somebody takes part in. `queued` is the one nobody does. */
|
|
163
|
+
export const HISTORY_STEPS_WITH_A_PERSON = [
|
|
164
164
|
"offered", "answered", "held", "muted", "transferred", "conferenced", "unanswered",
|
|
165
165
|
];
|
|
166
166
|
/** The steps a dial writes, and so the only ones that carry a `dialId` and a `destinationId`. */
|
|
167
|
-
export const
|
|
168
|
-
export const
|
|
169
|
-
// Pinned both ways: a step added to `
|
|
167
|
+
export const HISTORY_STEPS_THAT_DIAL = ["transferred", "conferenced", "unanswered"];
|
|
168
|
+
export const historyStepDials = (step) => HISTORY_STEPS_THAT_DIAL.includes(step);
|
|
169
|
+
// Pinned both ways: a step added to `HistoryStep` has to be placed here, and a step listed here
|
|
170
170
|
// has to exist there. `satisfies` on the list covers the second; this statement covers the first.
|
|
171
171
|
true;
|
|
172
172
|
/** Whether an absent `by` means "could not attribute" rather than "nobody was involved". */
|
|
173
|
-
export function
|
|
174
|
-
return
|
|
173
|
+
export function historyStepExpectsAPerson(step) {
|
|
174
|
+
return HISTORY_STEPS_WITH_A_PERSON.includes(step);
|
|
175
175
|
}
|
|
176
176
|
/**
|
|
177
177
|
* Whether two logins declare the same capabilities, field by field. The comparison an adapter
|
|
@@ -202,15 +202,15 @@ export function sameCapabilities(a, b) {
|
|
|
202
202
|
* cannot collide with a provider called `a` and a tab called `b`.
|
|
203
203
|
*/
|
|
204
204
|
export function browserSessionKey(input) {
|
|
205
|
-
const { providerId,
|
|
205
|
+
const { providerId, assignmentId, taskType, browser } = input;
|
|
206
206
|
if (browser.sharedSession !== true)
|
|
207
207
|
return undefined;
|
|
208
208
|
// `encodeURIComponent` leaves `.` untouched, and `.` is the separator: a raw join would let
|
|
209
209
|
// provider `Acme.Voice` with type `Support` forge the key of `Acme` with `Voice.Support`.
|
|
210
210
|
const part = (value) => encodeURIComponent(value).replaceAll(".", "%2E");
|
|
211
211
|
switch (browser.isolationScheme) {
|
|
212
|
-
case BROWSER_ISOLATION_SCHEMES.
|
|
213
|
-
return `${part(providerId)}.${part(
|
|
212
|
+
case BROWSER_ISOLATION_SCHEMES.PROVIDER_NAME__ASSIGNMENT_ID__TAB_NAME:
|
|
213
|
+
return `${part(providerId)}.${part(assignmentId)}.${part(browser.name)}`;
|
|
214
214
|
case BROWSER_ISOLATION_SCHEMES.TAB_NAME:
|
|
215
215
|
return part(browser.name);
|
|
216
216
|
case BROWSER_ISOLATION_SCHEMES.PROVIDER_NAME__TASK_TYPE_NAME__TAB_NAME:
|
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.
|
|
10
|
+
declare const STATE_SUBJECTS: readonly ["tasks", "task.browsers", "task.attributes", "task.history", "task.onCall", "task.leadAssist", "task.assisting", "task.listening", "task.media", "task.acceptance", "task.outcomes", "task.destinations", "task.custom", "task.locked", "break.reasons", "break.forced", "team.members", "team.requests", "contacts", "scheduledActivities", "team.policies"];
|
|
11
11
|
export type ContractSubject = (typeof STATE_SUBJECTS)[number] | `event.${ProviderEvent["type"]}`;
|
|
12
12
|
export interface AdapterContractResult {
|
|
13
13
|
events: ProviderEventEnvelope[];
|
|
@@ -147,18 +147,17 @@ export declare function assertDeniedAndRetriedBreak(approvals: readonly BreakSta
|
|
|
147
147
|
export declare const SUPERSEDED_BY_A_SNAPSHOT: ReadonlySet<string>;
|
|
148
148
|
export declare class TaskStream {
|
|
149
149
|
private readonly tasks;
|
|
150
|
-
private readonly
|
|
151
|
-
private readonly
|
|
150
|
+
private readonly assignments;
|
|
151
|
+
private readonly endedAssignments;
|
|
152
152
|
private readonly dials;
|
|
153
153
|
/** The host placed a dial: its outcome, whenever it arrives, is one the stream expects. */
|
|
154
154
|
dialled(dialId: string): void;
|
|
155
155
|
private noteDials;
|
|
156
156
|
/**
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
* a different fault. Either way it is not applied to the open task.
|
|
157
|
+
* Why an event names no open task: the assignment ended, so this is the late event that must not
|
|
158
|
+
* land on anything, or nobody has seen it. Either way it is not applied.
|
|
160
159
|
*/
|
|
161
|
-
private
|
|
160
|
+
private notOpen;
|
|
162
161
|
/** How many tasks the stream currently holds open. */
|
|
163
162
|
openCount(): number;
|
|
164
163
|
/** Whether an offered task is a dial arriving -- the host's own call, a connect-back -- which counts against no capacity: an entry on its call carrying a dial. */
|