@xema/omni-protocol 0.1.55 → 0.1.57

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 CHANGED
@@ -744,6 +744,13 @@ export interface Locked {
744
744
  * is the discriminant: a value that carries it is the lock, so no `T` may carry that key.
745
745
  */
746
746
  export type Lockable<T> = T | Locked;
747
+ /**
748
+ * Who chose a task's capabilities. `undetermined` is a fault the provider states on the task rather
749
+ * than hides: the platform's terms could not be read, and the set published is what the provider
750
+ * will honour, not what the platform permits.
751
+ */
752
+ export type CapabilitySource = "queue" | "ungoverned" | "undetermined";
753
+ export declare const CAPABILITY_SOURCES: readonly ["queue", "ungoverned", "undetermined"];
747
754
  export type Task<C extends Channel = Channel> = {
748
755
  id: TaskId;
749
756
  title: string;
@@ -751,6 +758,13 @@ export type Task<C extends Channel = Channel> = {
751
758
  /** The provider's own name for a category of work. Finer-grained than a channel. */
752
759
  taskType: string;
753
760
  capabilities: TaskCapabilities<C>;
761
+ /**
762
+ * Where the capabilities came from before the provider put them on the task, so a host can tell
763
+ * a fact from a fault: `queue` when somebody chose these terms, `ungoverned` when nothing handed
764
+ * the work over, `undetermined` when a queue was named and its terms could not be read -- the
765
+ * provider then publishes what it will honour and says so here, where the controls are drawn.
766
+ */
767
+ capabilitySource: CapabilitySource;
754
768
  browsers: TaskBrowser[];
755
769
  /** The person or entity on the other end of this task. Who the task is with; `contacts` on the snapshot is the directory. */
756
770
  party?: Contact;
package/dist/index.js CHANGED
@@ -68,6 +68,7 @@ export const DEFAULT_LEVELS = [
68
68
  export function effectiveLevels(declared) {
69
69
  return [...(declared ?? DEFAULT_LEVELS)];
70
70
  }
71
+ export const CAPABILITY_SOURCES = ["queue", "ungoverned", "undetermined"];
71
72
  // ---------------------------------------------------------------------------
72
73
  // Task commands.
73
74
  // ---------------------------------------------------------------------------
package/dist/testing.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type Adapter, type AuthenticationState, type ProviderEventEnvelope, type Snapshot, type TaskCompletion, type BreakApproval, type BrowserSessionKeyInput, type Channel, type ConnectContext, type Host, type HostGuarantees, type HostReport, type Manifest, type ProviderEvent } from "./index.js";
1
+ import { type Adapter, type AuthenticationState, type ProviderEventEnvelope, type Snapshot, type Task, type TaskCompletion, type BreakApproval, type BrowserSessionKeyInput, type Channel, type ConnectContext, type Host, type HostGuarantees, type HostReport, type Manifest, type ProviderEvent } from "./index.js";
2
2
  import { type ProtocolViolation } from "./validation.js";
3
3
  export { ProtocolConformanceError, assertNoViolations, type ProtocolViolation } from "./validation.js";
4
4
  /**
@@ -84,6 +84,20 @@ export declare function assertCommandRefusedAfterWithdrawal(result: {
84
84
  code: string;
85
85
  };
86
86
  }): void;
87
+ /**
88
+ * A task's capabilities are current, not fixed. A provider whose platform withdraws a permission
89
+ * mid-task republishes the task with the set as it now stands, and a command under the withdrawn
90
+ * capability is refused from then on. `tasks` is what the provider published for one task, first
91
+ * to last -- the offer, then each republish -- every one validated against the manifest, all the
92
+ * same id, with at least one capability offered by the first absent from the last. A locked
93
+ * control is present without permission, not withdrawn: it is still drawn, so it does not count.
94
+ * `command` is the command a host issues under a withdrawn capability: it must be clean against
95
+ * the first task and refused against the last for want of that capability and for nothing else.
96
+ * That pairing is what proves the refusal comes from the withdrawal rather than from a command
97
+ * that was never issuable. Pair it with `assertCommandRefusedAfterWithdrawal` on the provider's
98
+ * answer to the same command.
99
+ */
100
+ export declare function assertTaskCapabilityWithdrawal(tasks: readonly Task[], manifest: Manifest, command: Record<string, unknown>): void;
87
101
  /**
88
102
  * Throws unless the run reached every subject named: the paired assertion beside a clean result,
89
103
  * so a fixture that never produced a roster cannot pass a test that meant to check one.
package/dist/testing.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { browserSessionKey, effectiveLevels, sameCapabilities, } from "./index.js";
2
- import { assertNoViolations, validateAuthenticationState, validateEventEnvelope, validateHostGuarantees, validateHostReport, validateManifest, validateResult, validateSnapshot, validateTimeZone, validatePhone, validateTaskCommand, isTimeZone, sameTimeZone, } from "./validation.js";
2
+ import { assertNoViolations, validateAuthenticationState, validateEventEnvelope, validateHostGuarantees, validateHostReport, validateManifest, validateResult, validateSnapshot, validateTask, validateTimeZone, validatePhone, validateTaskCommand, isTimeZone, sameTimeZone, } from "./validation.js";
3
3
  export { ProtocolConformanceError, assertNoViolations } from "./validation.js";
4
4
  /**
5
5
  * A part of the contract a run may never reach: state nothing obliges an adapter to publish, so
@@ -301,6 +301,7 @@ export async function exerciseAdapter(adapter, context, options = {}) {
301
301
  violations.push({ rule: "diagnostic.raised", path: "event.diagnostic",
302
302
  message: `the provider reported a diagnostic: expected ${String(envelope.event.expected)}; observed ${String(envelope.event.observed)}` });
303
303
  }
304
+ violations.push(...undeterminedTasks(eventTasks(envelope), "event"));
304
305
  if (eventNamesUsers(envelope))
305
306
  requireMethod(live, "describeUsers", "an event publishes a UserId");
306
307
  if (eventDeclaresMute(envelope))
@@ -320,6 +321,7 @@ export async function exerciseAdapter(adapter, context, options = {}) {
320
321
  const snapshot = await connection.snapshot();
321
322
  observeSnapshot(snapshot, seen);
322
323
  violations.push(...validateSnapshot(snapshot, adapter.manifest, "snapshot", reader()));
324
+ violations.push(...undeterminedTasks(Array.isArray(snapshot?.tasks) ? snapshot.tasks : [], "snapshot.tasks"));
323
325
  stream.seed(snapshot);
324
326
  breaks.seed(snapshot);
325
327
  seeded = true;
@@ -526,6 +528,28 @@ export function assertAuthenticationRestoreAndExpiry(states) {
526
528
  throw new Error("Refreshing state must occur before expiry");
527
529
  }
528
530
  }
531
+ /** The tasks an envelope carries: the one a task event names, or a snapshot event's list. */
532
+ function eventTasks(envelope) {
533
+ if (!isRecord(envelope) || !isRecord(envelope.event))
534
+ return [];
535
+ const event = envelope.event;
536
+ if (event.type === "task-offered" || event.type === "task-updated")
537
+ return [event.task];
538
+ if (event.type === "snapshot" && isRecord(event.snapshot) && Array.isArray(event.snapshot.tasks))
539
+ return event.snapshot.tasks;
540
+ return [];
541
+ }
542
+ /**
543
+ * A task published under `undetermined` terms is a fact to a host and a failure to a conformance
544
+ * run, as a diagnostic is: the platform under test could not say what it permits, and a green
545
+ * result must not paper over it.
546
+ */
547
+ function undeterminedTasks(tasks, path) {
548
+ return tasks.flatMap((task, index) => isRecord(task) && task.capabilitySource === "undetermined"
549
+ ? [{ rule: "capabilitySource.undetermined", path: `${path}[${index}].capabilitySource`,
550
+ message: `task ${String(task.id)} was published under terms the provider could not determine` }]
551
+ : []);
552
+ }
529
553
  /**
530
554
  * Capabilities are current, not fixed. A provider that withdraws one republishes `authenticated`
531
555
  * with the new set, and the next snapshot agrees with it. `states` is what the authentication
@@ -575,6 +599,54 @@ export function assertCommandRefusedAfterWithdrawal(result) {
575
599
  throw new Error(`A command after its capability was withdrawn fails with omni.capability-not-enabled, not ${result.failure?.code}`);
576
600
  }
577
601
  }
602
+ /**
603
+ * A task's capabilities are current, not fixed. A provider whose platform withdraws a permission
604
+ * mid-task republishes the task with the set as it now stands, and a command under the withdrawn
605
+ * capability is refused from then on. `tasks` is what the provider published for one task, first
606
+ * to last -- the offer, then each republish -- every one validated against the manifest, all the
607
+ * same id, with at least one capability offered by the first absent from the last. A locked
608
+ * control is present without permission, not withdrawn: it is still drawn, so it does not count.
609
+ * `command` is the command a host issues under a withdrawn capability: it must be clean against
610
+ * the first task and refused against the last for want of that capability and for nothing else.
611
+ * That pairing is what proves the refusal comes from the withdrawal rather than from a command
612
+ * that was never issuable. Pair it with `assertCommandRefusedAfterWithdrawal` on the provider's
613
+ * answer to the same command.
614
+ */
615
+ export function assertTaskCapabilityWithdrawal(tasks, manifest, command) {
616
+ const first = tasks[0];
617
+ const last = tasks.at(-1);
618
+ if (tasks.length < 2 || first === undefined || last === undefined) {
619
+ throw new Error("Task capability withdrawal needs the task as offered and at least one republish of it");
620
+ }
621
+ const context = {
622
+ channel: manifest.channel,
623
+ levels: effectiveLevels(manifest.orgLevels).map(level => level.id),
624
+ dialOutcomesDeclared: manifest.dialOutcomes !== undefined,
625
+ };
626
+ tasks.forEach((task, index) => {
627
+ assertNoViolations(validateTask(task, context, `tasks[${index}]`), `Task capability withdrawal: tasks[${index}] must be a task the wire could carry`);
628
+ if (task.id !== first.id) {
629
+ throw new Error(`Task capability withdrawal must keep the task: tasks[${index}] is ${task.id}, and the offer was ${first.id}`);
630
+ }
631
+ });
632
+ const withdrawn = Object.keys(first.capabilities).filter(name => last.capabilities[name] === undefined);
633
+ if (withdrawn.length === 0) {
634
+ throw new Error("Task capability withdrawal must end with at least one capability the offer declared withdrawn; a locked control is present without permission, not withdrawn");
635
+ }
636
+ const before = validateTaskCommand(command, first, "command");
637
+ if (before.length > 0) {
638
+ throw new Error(`Task capability withdrawal: the command must be issuable against the task as offered, or its later refusal proves nothing (${before.map(v => v.rule).join(", ")})`);
639
+ }
640
+ const after = validateTaskCommand(command, last, "command");
641
+ const forWant = after.filter(v => withdrawn.some(name => v.rule === `command.capability.${name}`));
642
+ if (forWant.length === 0) {
643
+ throw new Error(`Task capability withdrawal: the command must be refused against the republished task for want of ${withdrawn.join(" or ")}; it was ${after.length === 0 ? "accepted" : `refused for ${after.map(v => v.rule).join(", ")}`}`);
644
+ }
645
+ const other = after.filter(v => !forWant.includes(v));
646
+ if (other.length > 0) {
647
+ throw new Error(`Task capability withdrawal: the republished task refuses the command for more than the withdrawal (${other.map(v => v.rule).join(", ")}); change one thing at a time`);
648
+ }
649
+ }
578
650
  /**
579
651
  * Throws unless the run reached every subject named: the paired assertion beside a clean result,
580
652
  * so a fixture that never produced a roster cannot pass a test that meant to check one.
@@ -687,7 +759,7 @@ export class TaskStream {
687
759
  stages.set(entry.dialId, entry.stage);
688
760
  }
689
761
  }
690
- return { phase: String(isRecord(task) ? task.phase : undefined), media, stages };
762
+ return { phase: String(isRecord(task) ? task.phase : undefined), media, source: String(isRecord(task) ? task.capabilitySource : undefined), stages };
691
763
  }
692
764
  /** Replaces what is known with a snapshot's tasks, as a snapshot replaces Omni's state. */
693
765
  seed(snapshot) {
@@ -729,6 +801,12 @@ export class TaskStream {
729
801
  refuse("stream.taskUpdated.unknown", `${at}.task.id`, `${id} was never offered or carried on a snapshot`);
730
802
  break;
731
803
  }
804
+ // Terms once read stay read. A re-read that fails is not a new fact about the task, so the
805
+ // last statement stands and the failure is a diagnostic; undetermined is a place a task
806
+ // starts from, never one it returns to.
807
+ if ((known.source === "queue" || known.source === "ungoverned") && isRecord(event.task) && event.task.capabilitySource === "undetermined") {
808
+ refuse("stream.taskUpdated.capabilitySource", `${at}.task.capabilitySource`, `${id} was published under ${known.source} terms and now says undetermined: terms once read stay read, and a re-read that fails is a diagnostic, not a republish`);
809
+ }
732
810
  if (known.media === "ended") {
733
811
  const phase = isRecord(event.task) ? String(event.task.phase) : "";
734
812
  if (phase !== "completing") {
@@ -41,6 +41,7 @@ const TASK_PHASES = membersOf({
41
41
  pending: true, confirmed: true, preview: true, "in-progress": true, paused: true, completing: true,
42
42
  });
43
43
  const COMPLETION_MODES = membersOf({ "agent-command": true, "provider-automatic": true });
44
+ const CAPABILITY_SOURCES = membersOf({ queue: true, ungoverned: true, undetermined: true });
44
45
  const ACCEPTANCE_MODES = membersOf({
45
46
  "no-preference": true, "consent": true, "automatic": true,
46
47
  });
@@ -970,6 +971,9 @@ function validateTaskInto(task, context, path, into) {
970
971
  if (task.assisting !== undefined && task.monitoring !== undefined) {
971
972
  into.add("task.monitoring.assisting", `${path}.monitoring`, "a task is a joined call or a monitored one, never both");
972
973
  }
974
+ // Where the terms came from is stated with them: a host cannot tell "the platform permits
975
+ // nothing" from "the terms could not be read" from the set alone, and the provider knows which.
976
+ into.oneOf(task.capabilitySource, CAPABILITY_SOURCES, "task.capabilitySource", `${path}.capabilitySource`);
973
977
  const capabilities = task.capabilities;
974
978
  if (!isPlainObject(capabilities)) {
975
979
  into.add("task.capabilities.shape", `${path}.capabilities`, "a task needs a capabilities object");
package/guide.md CHANGED
@@ -644,12 +644,15 @@ type Lockable<T> = T | Locked;
644
644
 
645
645
  type TaskMediaState = "started" | "ended";
646
646
 
647
+ type CapabilitySource = "queue" | "ungoverned" | "undetermined";
648
+
647
649
  type Task<C extends Channel = Channel> = {
648
650
  id: TaskId;
649
651
  title: string;
650
652
  channel: C;
651
653
  taskType: string;
652
654
  capabilities: TaskCapabilities<C>;
655
+ capabilitySource: CapabilitySource;
653
656
  browsers: TaskBrowser[];
654
657
  party?: Contact;
655
658
  phase: TaskPhase;
@@ -2194,6 +2197,7 @@ time. Runtime conformance checks also require the task channel to match its prov
2194
2197
  | `channel` | Channel handling this task. It must equal the source provider's manifest channel. |
2195
2198
  | `taskType` | Required provider-defined source or category of work, such as a voice `Queue Name`, `Mailbox Folder`, `Chat Source`, `Support`, `Billing`, or `Returns`. |
2196
2199
  | `capabilities` | Controls and workspace features available for this specific task. |
2200
+ | `capabilitySource` | Required. Who chose the capabilities: `queue` when somebody configured these terms, `ungoverned` when nothing handed the work over -- an agent's own outbound -- and `undetermined` when a queue was named and its terms could not be read, in which case `capabilities` is what the provider will honour, not what the platform permits. A host shows `undetermined` where the agent works. See **Task capabilities**. |
2197
2201
  | `browsers` | Named browser definitions for the task workspace: at least one when the task declares the `browsers` capability, empty when it does not. |
2198
2202
  | `party` | The person or entity on the other end of this task, as a `Contact`: often a name and one address; a withheld caller ID may leave nothing to send at all. Optional. The party is who the task is *with*; `contacts` is the directory. |
2199
2203
  | `phase` | Current canonical task phase: `pending`, `confirmed`, `preview`, `in-progress`, `paused`, or `completing`. `preview` is voice only. |
@@ -2664,6 +2668,80 @@ browser that used it.
2664
2668
  Task capabilities belong to each `Task`. If `hold` is omitted on one task, Omni
2665
2669
  must not show or issue hold for that task even if another task from the same provider supports it.
2666
2670
 
2671
+ **A capability is a property of the task, and of nothing the task names.** A provider derives it
2672
+ from no other source -- not the queue the task came from, not the login, not its own configuration
2673
+ -- because each of those answers a question about this task from somewhere that does not know
2674
+ about this task, and a client with two sources and a rule for choosing between them is the shape
2675
+ that produces two consumers disagreeing about one fact. The task is the one source, and the
2676
+ provider puts on the task what the platform permits for it -- and says, in `capabilitySource`, who
2677
+ chose those terms. `queue` says somebody configured them. `ungoverned` says nothing handed the work
2678
+ over: an agent's own outbound call has no queue behind it, and the provider states what it permits
2679
+ for such a call. Neither changes where a host reads the capabilities from, which is the task; the
2680
+ source is one more published fact about them, and the one that lets a host tell a fact from a fault
2681
+ (see below).
2682
+
2683
+ **Completing the task is not a capability, and no capability set withholds it.** `complete` is
2684
+ governed by `completionMode` alone: under `agent-command` it is always available, whatever the set
2685
+ says, and the `dispositions` capability decides only whether a code travels with it. Likewise
2686
+ Answer on a pending task and Call on a preview are the phase's controls, not the set's. The
2687
+ capability set governs what the agent may do *with* the task; disposing of it is never on the
2688
+ list.
2689
+
2690
+ **A permission that changes while the task is open is republished on the task at the moment it
2691
+ changes.** An agent on a billing dispute may refund up to their own limit and no further. The
2692
+ customer wants more, the agent asks for a lead, and the moment the lead joins the call the task is
2693
+ republished with the Refund control the agent could not have a minute ago; when the lead leaves, it
2694
+ is republished without it. Nothing about the agent changed -- who is on the call did -- and the
2695
+ task said so both times, at the moment it became true. A call moves queues the same way: a caller
2696
+ identified as a priority customer is transferred to the priority queue, and the task arrives under
2697
+ that queue's terms -- a longer wrap allowance, a discount control the general queue never offered --
2698
+ restated on the task at the hand-over, not inferred from the queue it left. A capability stated
2699
+ once at offer or answer and never corrected is a fact with a shelf life and no expiry, and a host
2700
+ draws a control the provider will now refuse -- or withholds one the agent now has. So the provider republishes
2701
+ the task, with its capabilities as they now stand, and a host treats the last statement as current
2702
+ rather than re-deriving anything. This is the same shape as a room left full after the call ends
2703
+ -- a field describing the present, carried past the moment it stopped being true -- carried past
2704
+ this time not by a spread but by nobody sending the correction. A provider whose platform can
2705
+ change a permission mid-task and does not republish is in breach, however conformant its offer was.
2706
+ A capability set can shrink as well as grow, and a host that has only ever seen it grow meets a
2707
+ control that was there a moment ago and is gone; a command that arrives after its capability was
2708
+ withdrawn is refused with a reason, never acted on. The asymmetry decides which direction a
2709
+ provider gets right first: a control gained late is a nicety, a control withdrawn and not
2710
+ republished is a button that fails when pressed. `assertTaskCapabilityWithdrawal` is the test for that
2711
+ direction: the task as offered and as republished, and one command that was issuable under the
2712
+ first and is refused under the last for want of the capability withdrawn -- and nothing else.
2713
+
2714
+ **An empty capability set is a statement, not a shrug.** `capabilities: {}` under `queue` or
2715
+ `ungoverned` says the platform permits nothing capability-gated on this task, and a host draws
2716
+ nothing beyond what the phase and `completionMode` require. A provider that has not yet learned
2717
+ what the platform permits -- a queue's configuration that has not reached it -- knows nothing of
2718
+ the kind, and must not publish the task as if it did, neither as `{}` nor as every control it has.
2719
+ It publishes the task under `capabilitySource: "undetermined"`, with the capabilities it will
2720
+ honour until it knows, and a host shows that where the agent works, beside the controls it draws
2721
+ from them: "no queue governs this call" is a fact, "the configuration has not arrived" is a fault,
2722
+ and the set alone cannot tell them apart, so the provider says which. What a provider honours
2723
+ under undetermined terms is its own call -- a floor that would rather an agent briefly hold a
2724
+ control the platform might not have granted than lose hold or hang-up mid-call over a slow
2725
+ configuration read publishes those -- and the protocol chooses no default set for it. The fault is
2726
+ also reported as a `diagnostic` naming the task, one per occurrence, so an operator counts it. When
2727
+ the terms arrive, the task is republished under `queue` with the set as it now stands: the same
2728
+ republish as any other permission that changed while the task was open. The move goes one way.
2729
+ Terms once read stay read: a re-read that fails mid-task is not a new fact about the task, so the
2730
+ last statement stands and the failure is a `diagnostic`, and a task that was published under
2731
+ `queue` or `ungoverned` never returns to `undetermined` (`stream.taskUpdated.capabilitySource`).
2732
+
2733
+ What the agent is told differs by source, and only one source tells them anything. Under `queue`
2734
+ and `ungoverned` the agent sees controls and nothing about where they came from: both are facts,
2735
+ and an agent working a call has no use for the name of the rule behind its buttons. Under
2736
+ `undetermined` the agent is told, beside the controls, that these are what the provider will honour
2737
+ until the queue's terms arrive, and that the controls may change when they do -- a statement about
2738
+ the buttons in front of them now, not about the provider, because that is what changes when the
2739
+ republish lands. The two words are close in English and far apart on the desk: `ungoverned` is
2740
+ silence, `undetermined` is a notice. `exerciseAdapter` treats a
2741
+ task published under `undetermined` as a violation (`capabilitySource.undetermined`), as it treats
2742
+ a diagnostic: a conformance run against a platform that cannot say what it permits fails loudly
2743
+ rather than passing with a note.
2744
+
2667
2745
  ```ts
2668
2746
  const taskCapabilities = {
2669
2747
  channel: "voice",
@@ -4209,7 +4287,9 @@ agent works and keeps a count an operator can read, because a healthy workspace
4209
4287
  console is the silence problem one layer up. One event per occurrence; the host counts, the
4210
4288
  provider does not batch. `exerciseAdapter` treats a diagnostic delivered during a run as a
4211
4289
  violation (`diagnostic.raised`): a conformance run against a platform that is breaking its rules
4212
- fails loudly rather than passing with a note.
4290
+ fails loudly rather than passing with a note. A task published under `capabilitySource:
4291
+ "undetermined"` is the same kind of fact, stated on the task instead, and fails a run the same way
4292
+ (`capabilitySource.undetermined`); see **Task capabilities**.
4213
4293
 
4214
4294
  | Field | Contract |
4215
4295
  | --- | --- |
@@ -4401,6 +4481,7 @@ cannot be established from TypeScript structure alone.
4401
4481
  | Helper | Contract checked |
4402
4482
  | --- | --- |
4403
4483
  | `assertCapabilityWithdrawal(states, snapshot, manifest)` | A capability withdrawn by a later `authenticated` state is gone from the next snapshot: no roster for a login that no longer leads, no requests for one that may no longer join. Every state is validated on the way, `refreshing` must carry the login over, and the sequence passes only through usable states. |
4484
+ | `assertTaskCapabilityWithdrawal(tasks, manifest, command)` | A capability withdrawn by a republish of the task is gone from the task: every task in the sequence is validated, all carry the offer's id, at least one capability the offer declared is absent at the end (a locked control is present, not withdrawn), and `command` is clean against the first task and refused against the last for want of a withdrawn capability and nothing else. Pair it with `assertCommandRefusedAfterWithdrawal` on the provider's answer. |
4404
4485
  | `assertCommandRefusedAfterWithdrawal(result)` | A command that arrives after its capability was withdrawn fails with `omni.capability-not-enabled`, named by the provider. The same assertion serves a command the provider never supported under a capability it declares. |
4405
4486
  | `assertReached(result, subjects)` | The exercise met every subject named; throws listing those it did not. Pair it with a clean `exerciseAdapter` result. |
4406
4487
  | `assertAuthenticationRestoreAndExpiry(states)` | A restored authenticated session can refresh and ends in expiry. Every state is validated. |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xema/omni-protocol",
3
- "version": "0.1.55",
3
+ "version": "0.1.57",
4
4
  "description": "The Omni protocol: the contract every provider adapter implements",
5
5
  "type": "module",
6
6
  "license": "MIT",