@xema/omni-protocol 0.1.112 → 0.1.114
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/README.md +6 -6
- package/dist/index.d.ts +5 -2
- package/dist/testing.d.ts +13 -13
- package/dist/testing.js +198 -176
- package/dist/validation.d.ts +2 -2
- package/dist/validation.js +11 -9
- package/guide/agent.md +12 -9
- package/guide/breaks.md +1 -1
- package/guide/phone.md +1 -1
- package/guide/voice.md +8 -1
- package/guide.md +52 -50
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ system.
|
|
|
15
15
|
| `guide/` | One file per role and channel: `agent.md`, `lead.md`, `queue.md`, `breaks.md`, `phone.md`, `voice.md`, `chat.md`, `email.md`. Each points back into `guide.md` for what it relies on. |
|
|
16
16
|
| `src/index.ts` | The TypeScript declarations. |
|
|
17
17
|
| `src/validation.ts` | Runtime validators Omni applies to adapter output. |
|
|
18
|
-
| `src/testing.ts` |
|
|
18
|
+
| `src/testing.ts` | Testing an adapter an adapter runs against its own test state. |
|
|
19
19
|
| `tests/` | One test file per source module, plus the guards over the guide and the repository's own text. |
|
|
20
20
|
|
|
21
21
|
## Entry points
|
|
@@ -23,7 +23,7 @@ system.
|
|
|
23
23
|
```ts
|
|
24
24
|
import { defineAdapter } from "@xema/omni-protocol";
|
|
25
25
|
import { validateSnapshot, assertNoViolations } from "@xema/omni-protocol/validation";
|
|
26
|
-
import {
|
|
26
|
+
import { testAdapter } from "@xema/omni-protocol/testing";
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
## Validation is not only for tests
|
|
@@ -49,7 +49,7 @@ is reading, or what their login declares, from the snapshot alone. `validateTeam
|
|
|
49
49
|
`validateSnapshot`, and `validateEventEnvelope` each take an optional final `{ self, capabilities }`
|
|
50
50
|
from the `authenticated` state; given them, they report `team.member.self`, `team.request.self`,
|
|
51
51
|
`team.required`, `team.unentitled`, `team.requests.capability`, and `team.requests.required`.
|
|
52
|
-
Without them those rules are not checked. `
|
|
52
|
+
Without them those rules are not checked. `testAdapter` always passes both.
|
|
53
53
|
|
|
54
54
|
```ts
|
|
55
55
|
const { identity, capabilities } = authenticated;
|
|
@@ -58,17 +58,17 @@ validateSnapshot(snapshot, manifest, "snapshot", { self: identity.id, capabiliti
|
|
|
58
58
|
|
|
59
59
|
## Conformance
|
|
60
60
|
|
|
61
|
-
`
|
|
61
|
+
`testAdapter` validates the manifest, opens an authenticated session, connects, checks
|
|
62
62
|
required capability methods, subscribes, validates the snapshot, every delivered event, and every
|
|
63
63
|
authentication state published during the run — against the latest login — states a capacity,
|
|
64
|
-
then unsubscribes and disconnects. `result.
|
|
64
|
+
then unsubscribes and disconnects. `result.notTested` names what the run never reached — each
|
|
65
65
|
optional part of a task, of the break state and team member list, each contribution, each event type — so a
|
|
66
66
|
clean result is read for what it covers and not for the whole contract; `assertReached(result,
|
|
67
67
|
subjects)` is the paired assertion.
|
|
68
68
|
|
|
69
69
|
```ts
|
|
70
70
|
const context = { protocolVersion: OMNI_PROTOCOL_VERSION, loginId: "session-1", host: stillHost(report) };
|
|
71
|
-
const result = await
|
|
71
|
+
const result = await testAdapter(adapter, context, { collectOnly: true });
|
|
72
72
|
expect(result.violations).toEqual([]);
|
|
73
73
|
expect(result.disconnectWasClean).toBe(true);
|
|
74
74
|
```
|
package/dist/index.d.ts
CHANGED
|
@@ -1106,7 +1106,10 @@ export type VoiceTaskCommand = {
|
|
|
1106
1106
|
} | {
|
|
1107
1107
|
type: "resume";
|
|
1108
1108
|
}
|
|
1109
|
-
/**
|
|
1109
|
+
/**
|
|
1110
|
+
* End the agent's channel and every channel the agent added; the caller continues on the provider's
|
|
1111
|
+
* path. Gated by `endCall`, and never from hold: a `paused` task is resumed first (`command.endCall.held`).
|
|
1112
|
+
*/
|
|
1110
1113
|
| {
|
|
1111
1114
|
type: "end-call";
|
|
1112
1115
|
}
|
|
@@ -1666,7 +1669,7 @@ export type HistoryReport = {
|
|
|
1666
1669
|
* `at` is the provider's instant for the leg, on its own clock, assigned when the provider writes
|
|
1667
1670
|
* the leg into its record and never an echo of the host's: the host keeps the answer as the leg's
|
|
1668
1671
|
* identity from then on, and names it on the closing report. A provider that echoes the host's
|
|
1669
|
-
* instant has assigned nothing, and the
|
|
1672
|
+
* instant has assigned nothing, and the test names it (`test.recordStep.identity`).
|
|
1670
1673
|
*/
|
|
1671
1674
|
export type HistoryReportResult = {
|
|
1672
1675
|
status: "recorded";
|
package/dist/testing.d.ts
CHANGED
|
@@ -26,32 +26,32 @@ export interface AdapterContractResult {
|
|
|
26
26
|
* tasks exercises no task rule, and an adapter's own test asserts that the subjects it meant to
|
|
27
27
|
* reach are absent from this list.
|
|
28
28
|
*/
|
|
29
|
-
|
|
29
|
+
notTested: readonly ContractSubject[];
|
|
30
30
|
/** Every violation observed. Non-empty only when `collectOnly` suppressed the throw. */
|
|
31
31
|
violations: readonly ProtocolViolation[];
|
|
32
32
|
/**
|
|
33
33
|
* Every rule the run evaluated, pass or fail: the validators' as each was applied, the stream's
|
|
34
|
-
* and the
|
|
34
|
+
* and the test's as each case was considered. A rule absent here was never looked at, which a
|
|
35
35
|
* clean `violations` says nothing about; a test that needs a rule to have run asserts it here.
|
|
36
36
|
*/
|
|
37
|
-
|
|
37
|
+
rulesTested: ReadonlySet<string>;
|
|
38
38
|
}
|
|
39
|
-
export interface
|
|
39
|
+
export interface TestAdapterOptions {
|
|
40
40
|
/** Return violations in the result instead of throwing. Defaults to `false`. */
|
|
41
41
|
collectOnly?: boolean;
|
|
42
42
|
/**
|
|
43
|
-
*
|
|
43
|
+
* Test 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
|
-
* under `
|
|
46
|
+
* under `notTested`. Off by default, since it issues commands against whatever platform the
|
|
47
47
|
* adapter is connected to: turn it on against a test backend.
|
|
48
48
|
*/
|
|
49
|
-
|
|
50
|
-
/** How long the
|
|
51
|
-
|
|
49
|
+
withCall?: boolean;
|
|
50
|
+
/** How long the test waits for each thing the provider owes it. Defaults to 5000. */
|
|
51
|
+
timeoutMs?: number;
|
|
52
52
|
/**
|
|
53
53
|
* Builds the adapter again, as a host reload does: a new object with no memory, for the same
|
|
54
|
-
* login. Given it, the
|
|
54
|
+
* login. Given it, the test -- once the host's muted leg is recorded -- connects a second adapter
|
|
55
55
|
* with the same context and the same store and expects its snapshot to carry the task with that
|
|
56
56
|
* leg. A platform that holds the record hands it back; an adapter that composed the record in
|
|
57
57
|
* memory has nothing, and is named. Without it the store is required and never read.
|
|
@@ -77,7 +77,7 @@ export interface ExerciseAdapterOptions {
|
|
|
77
77
|
* for a synchronous emitter, and is swallowed as an unhandled rejection for an
|
|
78
78
|
* asynchronous one — which would let a non-conforming async adapter pass.
|
|
79
79
|
*/
|
|
80
|
-
export declare function
|
|
80
|
+
export declare function testAdapter<C extends Channel>(adapter: Adapter<C>, context: ConnectContext, options?: TestAdapterOptions): Promise<AdapterContractResult>;
|
|
81
81
|
/**
|
|
82
82
|
* Validates restored authentication followed by a refresh failure or expiry. Every state is
|
|
83
83
|
* validated, and a `refreshing` state must carry over the login it refreshes.
|
|
@@ -237,10 +237,10 @@ export declare function assertBreakFollowsItsRequests(envelopes: readonly Provid
|
|
|
237
237
|
* follows the audio ending is `completing` or `task-ended`.
|
|
238
238
|
*/
|
|
239
239
|
export declare function assertAudioFollowsTheTask(envelopes: readonly ProviderEventEnvelope[], snapshot?: Snapshot): void;
|
|
240
|
-
/** A login store that lives in memory for the test: what most adapter tests hand `
|
|
240
|
+
/** A login store that lives in memory for the test: what most adapter tests hand `testAdapter` as `context.store`. */
|
|
241
241
|
export declare function memoryStore(): LoginStore;
|
|
242
242
|
/**
|
|
243
|
-
* A host that reports one thing and never changes: what most adapter tests hand `
|
|
243
|
+
* A host that reports one thing and never changes: what most adapter tests hand `testAdapter`.
|
|
244
244
|
* A softphone host states what its Mute does; a desk-phone or conversation host has no microphone and states nothing.
|
|
245
245
|
*/
|
|
246
246
|
export declare function stillHost(report: HostReport, guarantees: HostGuarantees, mute: HostMute): Host & {
|