@vinaverse/client 0.1.0-alpha.6 → 0.1.0-alpha.8
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 +69 -7
- package/dist/agent/index.cjs +526 -75
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +3 -3
- package/dist/agent/index.d.ts +3 -3
- package/dist/agent/index.js +2 -2
- package/dist/backend/index.cjs +268 -0
- package/dist/backend/index.cjs.map +1 -0
- package/dist/backend/index.d.cts +72 -0
- package/dist/backend/index.d.ts +72 -0
- package/dist/backend/index.js +250 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/{chunk-ZWG2TMUL.js → chunk-46D3FSLU.js} +24 -2
- package/dist/chunk-46D3FSLU.js.map +1 -0
- package/dist/chunk-DI4DPUNA.js +843 -0
- package/dist/chunk-DI4DPUNA.js.map +1 -0
- package/dist/chunk-YNUHXJD6.js +9 -0
- package/dist/{chunk-VSJDVLCP.js.map → chunk-YNUHXJD6.js.map} +1 -1
- package/dist/contract-DmQs8amJ.d.cts +6 -0
- package/dist/contract-DmQs8amJ.d.ts +6 -0
- package/dist/conversation/index.cjs +24 -2
- package/dist/conversation/index.cjs.map +1 -1
- package/dist/conversation/index.d.cts +5 -5
- package/dist/conversation/index.d.ts +5 -5
- package/dist/conversation/index.js +3 -3
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/{runtime-DLJbJkSr.d.ts → runtime-A4ovUdrc.d.cts} +147 -21
- package/dist/{runtime-CErMdYxJ.d.cts → runtime-B6_l8--U.d.ts} +147 -21
- package/dist/{session-8W3fRNeb.d.cts → session-CPz4pcPu.d.cts} +246 -7
- package/dist/{session-8W3fRNeb.d.ts → session-CPz4pcPu.d.ts} +246 -7
- package/dist/{store-C7FtS5AY.d.cts → store-BxiicOKG.d.cts} +32 -2
- package/dist/{store-DFk0ayh8.d.ts → store-DZka9T2-.d.ts} +32 -2
- package/dist/testing/index.cjs +38 -1
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +15 -4
- package/dist/testing/index.d.ts +15 -4
- package/dist/testing/index.js +40 -3
- package/dist/testing/index.js.map +1 -1
- package/package.json +41 -2
- package/dist/chunk-VSJDVLCP.js +0 -9
- package/dist/chunk-XPES5PZ3.js +0 -416
- package/dist/chunk-XPES5PZ3.js.map +0 -1
- package/dist/chunk-ZWG2TMUL.js.map +0 -1
- package/dist/contract-_NMdPjgN.d.cts +0 -6
- package/dist/contract-_NMdPjgN.d.ts +0 -6
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { C as CONTRACT } from './contract-
|
|
2
|
-
export { A as AnswerInput, h as AuthMode, a as Card, d as CardKind, e as ClientErrorCode, j as ClientEvent, k as ClientSecret, l as Connection, m as ConversationEngine, n as ConversationState, F as FetchLike, o as Frame, H as HeldCard, f as HeldQuestion, M as Message, P as Proposal, g as ProposalOutcome, Q as Question, R as Reconnect, S as Schemas, p as ServerEvent, q as ServerEventOf, r as ServerEventType, s as SessionEvents, t as SessionInfo, u as SessionOptions, v as SessionStatus, w as SseTarget, T as ToolLine, x as TranscriptItem, y as TurnInput, V as VinaverseClientError, z as VinaverseSession, B as WebSocketFactory, D as WebSocketLike, E as cardActionSse, G as components, i as isKnownCard, I as operations, J as paths, K as sseFrames, L as turnSse } from './session-
|
|
1
|
+
export { C as CONTRACT } from './contract-DmQs8amJ.cjs';
|
|
2
|
+
export { A as AnswerInput, h as AuthMode, a as Card, d as CardKind, e as ClientErrorCode, j as ClientEvent, k as ClientSecret, l as Connection, m as ConversationEngine, n as ConversationState, F as FetchLike, o as Frame, H as HeldCard, f as HeldQuestion, M as Message, P as Proposal, g as ProposalOutcome, Q as Question, R as Reconnect, S as Schemas, p as ServerEvent, q as ServerEventOf, r as ServerEventType, s as SessionEvents, t as SessionInfo, u as SessionOptions, v as SessionStatus, w as SseTarget, T as ToolLine, x as TranscriptItem, y as TurnInput, V as VinaverseClientError, z as VinaverseSession, B as WebSocketFactory, D as WebSocketLike, E as cardActionSse, G as components, i as isKnownCard, I as operations, J as paths, K as sseFrames, L as turnSse } from './session-CPz4pcPu.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* The client secret, checked: an app holds only the session's `vv_cs_` secret, which the tenant's backend got from
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { C as CONTRACT } from './contract-
|
|
2
|
-
export { A as AnswerInput, h as AuthMode, a as Card, d as CardKind, e as ClientErrorCode, j as ClientEvent, k as ClientSecret, l as Connection, m as ConversationEngine, n as ConversationState, F as FetchLike, o as Frame, H as HeldCard, f as HeldQuestion, M as Message, P as Proposal, g as ProposalOutcome, Q as Question, R as Reconnect, S as Schemas, p as ServerEvent, q as ServerEventOf, r as ServerEventType, s as SessionEvents, t as SessionInfo, u as SessionOptions, v as SessionStatus, w as SseTarget, T as ToolLine, x as TranscriptItem, y as TurnInput, V as VinaverseClientError, z as VinaverseSession, B as WebSocketFactory, D as WebSocketLike, E as cardActionSse, G as components, i as isKnownCard, I as operations, J as paths, K as sseFrames, L as turnSse } from './session-
|
|
1
|
+
export { C as CONTRACT } from './contract-DmQs8amJ.js';
|
|
2
|
+
export { A as AnswerInput, h as AuthMode, a as Card, d as CardKind, e as ClientErrorCode, j as ClientEvent, k as ClientSecret, l as Connection, m as ConversationEngine, n as ConversationState, F as FetchLike, o as Frame, H as HeldCard, f as HeldQuestion, M as Message, P as Proposal, g as ProposalOutcome, Q as Question, R as Reconnect, S as Schemas, p as ServerEvent, q as ServerEventOf, r as ServerEventType, s as SessionEvents, t as SessionInfo, u as SessionOptions, v as SessionStatus, w as SseTarget, T as ToolLine, x as TranscriptItem, y as TurnInput, V as VinaverseClientError, z as VinaverseSession, B as WebSocketFactory, D as WebSocketLike, E as cardActionSse, G as components, i as isKnownCard, I as operations, J as paths, K as sseFrames, L as turnSse } from './session-CPz4pcPu.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* The client secret, checked: an app holds only the session's `vv_cs_` secret, which the tenant's backend got from
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { CONTRACT } from './chunk-
|
|
1
|
+
export { CONTRACT } from './chunk-YNUHXJD6.js';
|
|
2
2
|
export { ConversationEngine, VinaverseClientError, VinaverseSession, cardActionSse, clientSecret, isKnownCard, sseFrames, turnSse } from './chunk-GWLLUOFY.js';
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as SessionRequest, b as ConversationSession, C as ConversationStore, a as ConversationOptions } from './store-
|
|
2
|
-
import { S as Schemas } from './session-
|
|
1
|
+
import { S as SessionRequest, b as ConversationSession, C as ConversationStore, f as ConversationPersistence, a as ConversationOptions } from './store-BxiicOKG.cjs';
|
|
2
|
+
import { S as Schemas, k as ClientSecret } from './session-CPz4pcPu.cjs';
|
|
3
3
|
|
|
4
4
|
/** Whose conversation: a person (null for a guest), the app's side, the business acted for, and the thread. */
|
|
5
5
|
interface AgentKey {
|
|
@@ -22,17 +22,47 @@ interface AgentPlace {
|
|
|
22
22
|
} | null;
|
|
23
23
|
readonly filters?: ScreenContext['filters'];
|
|
24
24
|
}
|
|
25
|
+
/** How the person came in: the kit's parts say `launcher` and `ask`; an app adds `deep_link` or its own words. */
|
|
26
|
+
type AgentEntryPoint = 'launcher' | 'ask' | 'deep_link' | (string & Record<never, never>);
|
|
25
27
|
/** What the runtime asks the tenant's backend for: a session, for this key, told this place. */
|
|
26
28
|
interface AgentSessionRequest extends SessionRequest {
|
|
27
29
|
readonly key: AgentKey;
|
|
30
|
+
/**
|
|
31
|
+
* This session creation's id: the same through its retries, so the backend uses it as the gateway's idempotency key
|
|
32
|
+
* and never opens twice; a new one for every creation (a first open, a resume, continue-here, a rollover). A creation
|
|
33
|
+
* that could not reach the backend keeps it, and its whole request, for the next try, the person's "try again" too,
|
|
34
|
+
* for 24 hours. An `unknown_open` answer is final: not retried under it.
|
|
35
|
+
*/
|
|
36
|
+
readonly openId: string;
|
|
37
|
+
/** The runtime's `agent`, for a backend that serves more than one. */
|
|
38
|
+
readonly agent: string | null;
|
|
28
39
|
readonly place: AgentPlace | null;
|
|
29
|
-
/**
|
|
30
|
-
|
|
40
|
+
/**
|
|
41
|
+
* The place's revision (`ScreenContext.revision`): higher than any the session was told before, and lower than any
|
|
42
|
+
* `updateContext` after it, so the API keeps the newest place across a session's rollover.
|
|
43
|
+
*/
|
|
44
|
+
readonly placeRevision: number;
|
|
45
|
+
/** How the person came in (`launcher`, `ask`, `deep_link`, the app's own words), passed through. */
|
|
46
|
+
readonly entryPoint: AgentEntryPoint | null;
|
|
31
47
|
}
|
|
32
48
|
/** Why there is no session, typed, so an app never needs sentinel errors of its own. */
|
|
33
49
|
type AgentFailureReason =
|
|
34
|
-
/** The conversation
|
|
50
|
+
/** The conversation is over (its session's own end, or a refusal with no finer reason). */
|
|
35
51
|
'ended'
|
|
52
|
+
/** The conversation asked for does not exist for this person (deleted, or never theirs). */
|
|
53
|
+
| 'not_found'
|
|
54
|
+
/** Past the time the conversation is kept. */
|
|
55
|
+
| 'expired'
|
|
56
|
+
/** The conversation belongs to another business, mode or agent than the key's. */
|
|
57
|
+
| 'mismatch'
|
|
58
|
+
/** The conversation's flow is completed; a new one starts when the person asks. */
|
|
59
|
+
| 'completed'
|
|
60
|
+
/** The person may not act for this business or conversation. */
|
|
61
|
+
| 'forbidden'
|
|
62
|
+
/** The server holds a newer screen context than the one told (an update, never a session). */
|
|
63
|
+
| 'conflict'
|
|
64
|
+
/** The backend could not tell whether the session opened: unavailable, never retried, its `openId` kept for support. */
|
|
65
|
+
| 'unknown_open'
|
|
36
66
|
/** The person's sign-in was refused by the tenant's API. */
|
|
37
67
|
| 'auth'
|
|
38
68
|
/** The agent is switched off for this tenant, mode or person. */
|
|
@@ -83,11 +113,17 @@ interface AgentStatusRead {
|
|
|
83
113
|
interface AgentBackend {
|
|
84
114
|
/** A session from the tenant's API (it creates it at Vinaverse with its service key), or an `AgentRefusal`. */
|
|
85
115
|
openSession(request: AgentSessionRequest): Promise<ConversationSession>;
|
|
86
|
-
/**
|
|
87
|
-
|
|
116
|
+
/**
|
|
117
|
+
* A fresh client secret for the same session (before its end): a `ClientSecret` `{ value, expires_at }`, or its
|
|
118
|
+
* value. A refusal (`session_closed`: the session is over) goes on with the conversation in a new session.
|
|
119
|
+
*/
|
|
120
|
+
refreshSecret?(sessionId: string): Promise<ClientSecret | string>;
|
|
88
121
|
/**
|
|
89
122
|
* The person's place changed while the chat is open: the tenant's backend tells Vinaverse
|
|
90
|
-
* (`PUT /v1/sessions/{id}/context`).
|
|
123
|
+
* (`PUT /v1/sessions/{id}/context`). A place cleared (`tell({ place: null })`) comes as `{ screen: 'other' }`.
|
|
124
|
+
* `revision` only grows for a conversation, across its sessions. A conflict (`decodeBackendFailure`'s
|
|
125
|
+
* `context_conflict`, or a refusal with reason `conflict`, with the server's `currentRevision`) is sent once more
|
|
126
|
+
* above it, then said as `moved`. Absent, or refused otherwise, the kit offers a question about the new place.
|
|
91
127
|
*/
|
|
92
128
|
updateContext?(sessionId: string, place: AgentPlace, revision: number): Promise<void>;
|
|
93
129
|
/** Whether the agent is offered, and what it can do. Absent: available, nothing extra. */
|
|
@@ -100,13 +136,16 @@ interface AgentBackend {
|
|
|
100
136
|
}): Promise<void>;
|
|
101
137
|
/** Sign-out: end the person's open sessions at the tenant's API. */
|
|
102
138
|
endSessions?(): Promise<void>;
|
|
139
|
+
/** History's delete: the tenant's API deletes the person's conversation (authenticated, theirs only). */
|
|
140
|
+
deleteConversation?(conversationId: string): Promise<void>;
|
|
103
141
|
}
|
|
104
142
|
type AgentRating = 'up' | 'down';
|
|
105
143
|
type AgentFailure = 'ended' | 'unreachable' | 'unavailable';
|
|
106
|
-
type AgentEventType = 'session_opened' | 'session_resumed' | 'session_retried' | 'session_failed' | 'conversation_ended' | 'context_updated' | 'rated' | 'chip_tapped' | 'card_action' | 'target_opened' | 'link_opened' | 'launcher_shown' | 'launcher_opened' | 'launcher_greeted' | 'greeting_closed';
|
|
144
|
+
type AgentEventType = 'session_opened' | 'session_resumed' | 'session_retried' | 'session_failed' | 'conversation_ended' | 'context_updated' | 'rated' | 'chip_tapped' | 'card_action' | 'target_opened' | 'link_opened' | 'launcher_shown' | 'launcher_opened' | 'launcher_greeted' | 'greeting_closed' | 'message_sent' | 'reply_completed' | 'card_shown';
|
|
107
145
|
/** For the app's analytics: what happened, for which conversation, with nothing the person said. */
|
|
108
146
|
interface AgentEvent {
|
|
109
147
|
readonly type: AgentEventType;
|
|
148
|
+
/** The conversation, as a hash of its key (`hashKey`): stable, and never the person's id. */
|
|
110
149
|
readonly key?: string;
|
|
111
150
|
readonly sessionId?: string;
|
|
112
151
|
readonly failure?: AgentFailure;
|
|
@@ -116,8 +155,8 @@ interface AgentEvent {
|
|
|
116
155
|
readonly rating?: AgentRating;
|
|
117
156
|
readonly cardId?: string;
|
|
118
157
|
readonly kind?: string;
|
|
119
|
-
/** Where the person opened from (`
|
|
120
|
-
readonly from?:
|
|
158
|
+
/** Where the person opened from (`launcher`, `ask`, `deep_link`, the app's own words). */
|
|
159
|
+
readonly from?: AgentEntryPoint;
|
|
121
160
|
}
|
|
122
161
|
/** What a UI draws around the store: why there is no session, whether the person moved, the thumbs given. */
|
|
123
162
|
interface AgentConversationState {
|
|
@@ -129,6 +168,13 @@ interface AgentConversationState {
|
|
|
129
168
|
readonly moved: boolean;
|
|
130
169
|
readonly ratings: ReadonlyMap<string, AgentRating>;
|
|
131
170
|
readonly sessionId: string | null;
|
|
171
|
+
/**
|
|
172
|
+
* The conversation the key holds: the one it continues before a session opens, then its session's. Null for a new
|
|
173
|
+
* one not yet opened. History's delete compares against it (`deleteConversation` does).
|
|
174
|
+
*/
|
|
175
|
+
readonly conversationId: string | null;
|
|
176
|
+
/** The open the backend could not settle (`unknown_open`), for support; null otherwise. */
|
|
177
|
+
readonly openId: string | null;
|
|
132
178
|
}
|
|
133
179
|
interface AgentConversation {
|
|
134
180
|
/** The key as a string, for the app's own maps and the events. */
|
|
@@ -142,18 +188,26 @@ interface AgentConversation {
|
|
|
142
188
|
*/
|
|
143
189
|
show(open?: {
|
|
144
190
|
readonly place?: AgentPlace | null;
|
|
145
|
-
readonly entryPoint?:
|
|
191
|
+
readonly entryPoint?: AgentEntryPoint | null;
|
|
146
192
|
}): () => void;
|
|
147
|
-
/**
|
|
193
|
+
/**
|
|
194
|
+
* The place and the way in changed while a view is attached: told live where the backend can, else on the next
|
|
195
|
+
* session. `undefined` keeps what was told; `null` clears it.
|
|
196
|
+
*/
|
|
148
197
|
tell(open: {
|
|
149
198
|
readonly place?: AgentPlace | null;
|
|
150
|
-
readonly entryPoint?:
|
|
199
|
+
readonly entryPoint?: AgentEntryPoint | null;
|
|
151
200
|
}): void;
|
|
152
201
|
getState(): AgentConversationState;
|
|
153
202
|
subscribe(listener: () => void): () => void;
|
|
154
203
|
/** Asks for a session again, after the backend could not be reached. */
|
|
155
204
|
retry(): void;
|
|
156
|
-
/**
|
|
205
|
+
/**
|
|
206
|
+
* Whether a reply can be rated: one this runtime saw given live. A reply restored from the device or a resumed
|
|
207
|
+
* transcript cannot be, until the API rates a turn by its conversation; the kits draw no thumbs for it.
|
|
208
|
+
*/
|
|
209
|
+
canRate(turnId: string): boolean;
|
|
210
|
+
/** A thumbs on a whole reply, against the session it was given in; a change of mind only is sent again. */
|
|
157
211
|
rate(turnId: string, rating: AgentRating): void;
|
|
158
212
|
/**
|
|
159
213
|
* Sends the person's `text` once in this conversation's life (a chip tapped twice, a retried tap). It is shown as
|
|
@@ -172,6 +226,11 @@ interface AgentClock {
|
|
|
172
226
|
}
|
|
173
227
|
interface AgentRuntimeOptions {
|
|
174
228
|
readonly backend: AgentBackend;
|
|
229
|
+
/**
|
|
230
|
+
* The agent this runtime talks to (its id at Vinaverse). It is part of every key, so two agents sharing the device's
|
|
231
|
+
* storage (`conversation.persistence`) never share a conversation. Default: none (one agent per storage namespace).
|
|
232
|
+
*/
|
|
233
|
+
readonly agent?: string;
|
|
175
234
|
/** The store's own options (locale, time zone, deep-link prefixes, transport, persistence, closeInBackground…). */
|
|
176
235
|
readonly conversation?: Omit<ConversationOptions, 'getSession' | 'refreshSecret' | 'clock'>;
|
|
177
236
|
/** Default: 500, 1500, 3500 ms, for errors with `retryable: true`; applied to `openSession` and `refreshSecret`. */
|
|
@@ -189,8 +248,28 @@ interface AgentRuntimeOptions {
|
|
|
189
248
|
*/
|
|
190
249
|
readonly insecureAddresses?: AgentInsecureAddresses;
|
|
191
250
|
readonly onEvent?: (event: AgentEvent) => void;
|
|
251
|
+
/**
|
|
252
|
+
* Where the launcher remembers it greeted a person (the app's preferences store). Given here, the launcher reads and
|
|
253
|
+
* writes it through the runtime (`greetings`), a sign-out fences it, and `erase()` removes it.
|
|
254
|
+
*/
|
|
255
|
+
readonly greetingStorage?: ConversationPersistence;
|
|
256
|
+
/**
|
|
257
|
+
* Keys an earlier version of the app or the kit wrote that no index lists, for a storage with neither `keys` nor
|
|
258
|
+
* `removePrefix`: removed by every sign-out from `conversation.persistence`, and by `erase()` from `greetingStorage`
|
|
259
|
+
* too. The migration that makes their removal certain on such a storage.
|
|
260
|
+
*/
|
|
261
|
+
readonly legacyKeys?: readonly string[];
|
|
192
262
|
/** Where the runtime's warnings go (the app's logger, crash reporter); default `console.warn`. */
|
|
193
|
-
readonly onWarning?: (message: string) => void;
|
|
263
|
+
readonly onWarning?: (message: string, warning: AgentWarning) => void;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* What a warning is about, for an app's logger to count without reading the message: `insecure_addresses` (a leg let
|
|
267
|
+
* off the wss:// and https:// check outside development), `callback_threw` (the app's `onEvent` or `onActivity` threw;
|
|
268
|
+
* `callback` names it), `events_dropped` (the oldest analytics events, while the salt is read).
|
|
269
|
+
*/
|
|
270
|
+
interface AgentWarning {
|
|
271
|
+
readonly code: 'insecure_addresses' | 'callback_threw' | 'events_dropped';
|
|
272
|
+
readonly callback?: 'onEvent' | 'onActivity';
|
|
194
273
|
}
|
|
195
274
|
/** The legs whose session address may be plaintext: `realtime` (the WebSocket), `turns` (HTTP). */
|
|
196
275
|
interface AgentInsecureAddresses {
|
|
@@ -207,15 +286,43 @@ interface AgentRuntime {
|
|
|
207
286
|
peek(key: AgentKey): AgentConversation;
|
|
208
287
|
/** A new conversation for the key from the person's next opening; the old one is let go and forgotten. */
|
|
209
288
|
startNew(key: AgentKey): void;
|
|
210
|
-
/**
|
|
289
|
+
/**
|
|
290
|
+
* Closes the key's conversation now; the next opening continues it in a new session. What the device kept of it and
|
|
291
|
+
* the conversation it continues stay: `forget` removes them.
|
|
292
|
+
*/
|
|
211
293
|
dispose(key: AgentKey): void;
|
|
294
|
+
/**
|
|
295
|
+
* Closes the key's conversation and forgets it on this device: the conversation it continued and the transcript kept
|
|
296
|
+
* by `persistence`. History's "delete" calls it after the tenant's backend deleted the conversation.
|
|
297
|
+
*/
|
|
298
|
+
forget(key: AgentKey): void;
|
|
299
|
+
/** Ends every conversation no view shows that is past its session's end. The kits call it when the app comes back. */
|
|
300
|
+
sweep(): void;
|
|
301
|
+
/**
|
|
302
|
+
* History's delete: the backend deletes the conversation, then the device forgets it, only where the key still
|
|
303
|
+
* continues that conversation (an older history entry never forgets the key's newer one).
|
|
304
|
+
*/
|
|
305
|
+
deleteConversation(key: AgentKey, conversationId: string): Promise<void>;
|
|
306
|
+
/**
|
|
307
|
+
* The person's erasure on this device: a sign-out, plus the launcher's greeting records (`greetingStorage`) and the
|
|
308
|
+
* analytics salt, every key this version and alpha.5 or alpha.6 wrote. Keys no index lists (an earlier version's, a
|
|
309
|
+
* write lost with its process) are found only when the storage has `keys` or `removePrefix`.
|
|
310
|
+
*/
|
|
311
|
+
erase(): Promise<void>;
|
|
312
|
+
/** The launcher's greeting storage, under the sign-out fence; null without `greetingStorage`. */
|
|
313
|
+
readonly greetings: ConversationPersistence | null;
|
|
212
314
|
/**
|
|
213
315
|
* The key goes on with this conversation (history's "Continue"): pinned for the key and opened through the backend's
|
|
214
316
|
* resume. One that is gone (404, 410: the backend's `AgentRefusal('ended')`) is said as `ended`, never replaced by a
|
|
215
317
|
* new one silently.
|
|
216
318
|
*/
|
|
217
319
|
continue(key: AgentKey, conversationId: string): AgentConversation;
|
|
218
|
-
/**
|
|
320
|
+
/**
|
|
321
|
+
* Every conversation closed and forgotten, and everything this runtime kept on the device (every transcript it ever
|
|
322
|
+
* wrote under `conversation.persistenceKey`, even of conversations already closed), the status and the name; then
|
|
323
|
+
* the backend is told to end the sessions at the same time. A late answer from before (a session, a status, a write)
|
|
324
|
+
* changes nothing. Kept on purpose: the launcher's greeting records and the analytics salt (`erase` takes them).
|
|
325
|
+
*/
|
|
219
326
|
signOut(): Promise<void>;
|
|
220
327
|
/** The agent's status, read from the backend at most every `statusStaleMs`. */
|
|
221
328
|
status(): Promise<AgentStatus>;
|
|
@@ -227,8 +334,27 @@ interface AgentRuntime {
|
|
|
227
334
|
/** An event from a kit or the app, passed to `onEvent`. */
|
|
228
335
|
emit(event: AgentEvent): void;
|
|
229
336
|
}
|
|
230
|
-
/**
|
|
231
|
-
|
|
337
|
+
/**
|
|
338
|
+
* Where the launcher remembers that it greeted a person in a mode, the key its storage sees. Encoded so a guest
|
|
339
|
+
* (`null`) is never a person whose id is "guest".
|
|
340
|
+
*/
|
|
341
|
+
declare function greetedKey(subject: string | null, mode: string): string;
|
|
342
|
+
/**
|
|
343
|
+
* A conversation's key as analytics sees it: SHA-256 of the install's salt and the key, 128 bits in hex. Stable per
|
|
344
|
+
* install (the runtime keeps the salt in the app's storage until `erase()`), never the person's id, and not
|
|
345
|
+
* recomputable from a guessed id without the salt.
|
|
346
|
+
*/
|
|
347
|
+
declare function hashKey(key: string, salt: string): string;
|
|
348
|
+
/**
|
|
349
|
+
* The key as a string: one conversation per agent, person, mode, business and thread. Encoded as a JSON array, so no
|
|
350
|
+
* value can pass for another (a guest is `null`, never a subject named "guest"; a `|` in an id is just a character).
|
|
351
|
+
*/
|
|
352
|
+
declare function agentKey(key: AgentKey, agent?: string | null): string;
|
|
232
353
|
declare function createAgentRuntime(options: AgentRuntimeOptions): AgentRuntime;
|
|
354
|
+
/**
|
|
355
|
+
* An `AgentRefusal`, also one made by another copy of this package (the mock in `@vinaverse/client/testing`, the
|
|
356
|
+
* backend helpers in `@vinaverse/client/backend`, a second install): recognised by its name and kind, not its class.
|
|
357
|
+
*/
|
|
358
|
+
declare function isRefusal(error: unknown): error is AgentRefusal;
|
|
233
359
|
|
|
234
|
-
export { type AgentBackend as A, type AgentClock as a, type AgentConversation as b, type AgentConversationState as c, type
|
|
360
|
+
export { type AgentBackend as A, type AgentClock as a, type AgentConversation as b, type AgentConversationState as c, type AgentEntryPoint as d, type AgentEvent as e, type AgentEventType as f, type AgentFailure as g, type AgentFailureReason as h, type AgentInsecureAddresses as i, type AgentKey as j, type AgentPlace as k, type AgentRating as l, AgentRefusal as m, type AgentRetryPolicy as n, type AgentRuntime as o, type AgentRuntimeOptions as p, type AgentSessionRequest as q, type AgentStatus as r, type AgentStatusRead as s, type AgentWarning as t, agentKey as u, createAgentRuntime as v, greetedKey as w, hashKey as x, isRefusal as y };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as SessionRequest, b as ConversationSession, C as ConversationStore, a as ConversationOptions } from './store-
|
|
2
|
-
import { S as Schemas } from './session-
|
|
1
|
+
import { S as SessionRequest, b as ConversationSession, C as ConversationStore, f as ConversationPersistence, a as ConversationOptions } from './store-DZka9T2-.js';
|
|
2
|
+
import { S as Schemas, k as ClientSecret } from './session-CPz4pcPu.js';
|
|
3
3
|
|
|
4
4
|
/** Whose conversation: a person (null for a guest), the app's side, the business acted for, and the thread. */
|
|
5
5
|
interface AgentKey {
|
|
@@ -22,17 +22,47 @@ interface AgentPlace {
|
|
|
22
22
|
} | null;
|
|
23
23
|
readonly filters?: ScreenContext['filters'];
|
|
24
24
|
}
|
|
25
|
+
/** How the person came in: the kit's parts say `launcher` and `ask`; an app adds `deep_link` or its own words. */
|
|
26
|
+
type AgentEntryPoint = 'launcher' | 'ask' | 'deep_link' | (string & Record<never, never>);
|
|
25
27
|
/** What the runtime asks the tenant's backend for: a session, for this key, told this place. */
|
|
26
28
|
interface AgentSessionRequest extends SessionRequest {
|
|
27
29
|
readonly key: AgentKey;
|
|
30
|
+
/**
|
|
31
|
+
* This session creation's id: the same through its retries, so the backend uses it as the gateway's idempotency key
|
|
32
|
+
* and never opens twice; a new one for every creation (a first open, a resume, continue-here, a rollover). A creation
|
|
33
|
+
* that could not reach the backend keeps it, and its whole request, for the next try, the person's "try again" too,
|
|
34
|
+
* for 24 hours. An `unknown_open` answer is final: not retried under it.
|
|
35
|
+
*/
|
|
36
|
+
readonly openId: string;
|
|
37
|
+
/** The runtime's `agent`, for a backend that serves more than one. */
|
|
38
|
+
readonly agent: string | null;
|
|
28
39
|
readonly place: AgentPlace | null;
|
|
29
|
-
/**
|
|
30
|
-
|
|
40
|
+
/**
|
|
41
|
+
* The place's revision (`ScreenContext.revision`): higher than any the session was told before, and lower than any
|
|
42
|
+
* `updateContext` after it, so the API keeps the newest place across a session's rollover.
|
|
43
|
+
*/
|
|
44
|
+
readonly placeRevision: number;
|
|
45
|
+
/** How the person came in (`launcher`, `ask`, `deep_link`, the app's own words), passed through. */
|
|
46
|
+
readonly entryPoint: AgentEntryPoint | null;
|
|
31
47
|
}
|
|
32
48
|
/** Why there is no session, typed, so an app never needs sentinel errors of its own. */
|
|
33
49
|
type AgentFailureReason =
|
|
34
|
-
/** The conversation
|
|
50
|
+
/** The conversation is over (its session's own end, or a refusal with no finer reason). */
|
|
35
51
|
'ended'
|
|
52
|
+
/** The conversation asked for does not exist for this person (deleted, or never theirs). */
|
|
53
|
+
| 'not_found'
|
|
54
|
+
/** Past the time the conversation is kept. */
|
|
55
|
+
| 'expired'
|
|
56
|
+
/** The conversation belongs to another business, mode or agent than the key's. */
|
|
57
|
+
| 'mismatch'
|
|
58
|
+
/** The conversation's flow is completed; a new one starts when the person asks. */
|
|
59
|
+
| 'completed'
|
|
60
|
+
/** The person may not act for this business or conversation. */
|
|
61
|
+
| 'forbidden'
|
|
62
|
+
/** The server holds a newer screen context than the one told (an update, never a session). */
|
|
63
|
+
| 'conflict'
|
|
64
|
+
/** The backend could not tell whether the session opened: unavailable, never retried, its `openId` kept for support. */
|
|
65
|
+
| 'unknown_open'
|
|
36
66
|
/** The person's sign-in was refused by the tenant's API. */
|
|
37
67
|
| 'auth'
|
|
38
68
|
/** The agent is switched off for this tenant, mode or person. */
|
|
@@ -83,11 +113,17 @@ interface AgentStatusRead {
|
|
|
83
113
|
interface AgentBackend {
|
|
84
114
|
/** A session from the tenant's API (it creates it at Vinaverse with its service key), or an `AgentRefusal`. */
|
|
85
115
|
openSession(request: AgentSessionRequest): Promise<ConversationSession>;
|
|
86
|
-
/**
|
|
87
|
-
|
|
116
|
+
/**
|
|
117
|
+
* A fresh client secret for the same session (before its end): a `ClientSecret` `{ value, expires_at }`, or its
|
|
118
|
+
* value. A refusal (`session_closed`: the session is over) goes on with the conversation in a new session.
|
|
119
|
+
*/
|
|
120
|
+
refreshSecret?(sessionId: string): Promise<ClientSecret | string>;
|
|
88
121
|
/**
|
|
89
122
|
* The person's place changed while the chat is open: the tenant's backend tells Vinaverse
|
|
90
|
-
* (`PUT /v1/sessions/{id}/context`).
|
|
123
|
+
* (`PUT /v1/sessions/{id}/context`). A place cleared (`tell({ place: null })`) comes as `{ screen: 'other' }`.
|
|
124
|
+
* `revision` only grows for a conversation, across its sessions. A conflict (`decodeBackendFailure`'s
|
|
125
|
+
* `context_conflict`, or a refusal with reason `conflict`, with the server's `currentRevision`) is sent once more
|
|
126
|
+
* above it, then said as `moved`. Absent, or refused otherwise, the kit offers a question about the new place.
|
|
91
127
|
*/
|
|
92
128
|
updateContext?(sessionId: string, place: AgentPlace, revision: number): Promise<void>;
|
|
93
129
|
/** Whether the agent is offered, and what it can do. Absent: available, nothing extra. */
|
|
@@ -100,13 +136,16 @@ interface AgentBackend {
|
|
|
100
136
|
}): Promise<void>;
|
|
101
137
|
/** Sign-out: end the person's open sessions at the tenant's API. */
|
|
102
138
|
endSessions?(): Promise<void>;
|
|
139
|
+
/** History's delete: the tenant's API deletes the person's conversation (authenticated, theirs only). */
|
|
140
|
+
deleteConversation?(conversationId: string): Promise<void>;
|
|
103
141
|
}
|
|
104
142
|
type AgentRating = 'up' | 'down';
|
|
105
143
|
type AgentFailure = 'ended' | 'unreachable' | 'unavailable';
|
|
106
|
-
type AgentEventType = 'session_opened' | 'session_resumed' | 'session_retried' | 'session_failed' | 'conversation_ended' | 'context_updated' | 'rated' | 'chip_tapped' | 'card_action' | 'target_opened' | 'link_opened' | 'launcher_shown' | 'launcher_opened' | 'launcher_greeted' | 'greeting_closed';
|
|
144
|
+
type AgentEventType = 'session_opened' | 'session_resumed' | 'session_retried' | 'session_failed' | 'conversation_ended' | 'context_updated' | 'rated' | 'chip_tapped' | 'card_action' | 'target_opened' | 'link_opened' | 'launcher_shown' | 'launcher_opened' | 'launcher_greeted' | 'greeting_closed' | 'message_sent' | 'reply_completed' | 'card_shown';
|
|
107
145
|
/** For the app's analytics: what happened, for which conversation, with nothing the person said. */
|
|
108
146
|
interface AgentEvent {
|
|
109
147
|
readonly type: AgentEventType;
|
|
148
|
+
/** The conversation, as a hash of its key (`hashKey`): stable, and never the person's id. */
|
|
110
149
|
readonly key?: string;
|
|
111
150
|
readonly sessionId?: string;
|
|
112
151
|
readonly failure?: AgentFailure;
|
|
@@ -116,8 +155,8 @@ interface AgentEvent {
|
|
|
116
155
|
readonly rating?: AgentRating;
|
|
117
156
|
readonly cardId?: string;
|
|
118
157
|
readonly kind?: string;
|
|
119
|
-
/** Where the person opened from (`
|
|
120
|
-
readonly from?:
|
|
158
|
+
/** Where the person opened from (`launcher`, `ask`, `deep_link`, the app's own words). */
|
|
159
|
+
readonly from?: AgentEntryPoint;
|
|
121
160
|
}
|
|
122
161
|
/** What a UI draws around the store: why there is no session, whether the person moved, the thumbs given. */
|
|
123
162
|
interface AgentConversationState {
|
|
@@ -129,6 +168,13 @@ interface AgentConversationState {
|
|
|
129
168
|
readonly moved: boolean;
|
|
130
169
|
readonly ratings: ReadonlyMap<string, AgentRating>;
|
|
131
170
|
readonly sessionId: string | null;
|
|
171
|
+
/**
|
|
172
|
+
* The conversation the key holds: the one it continues before a session opens, then its session's. Null for a new
|
|
173
|
+
* one not yet opened. History's delete compares against it (`deleteConversation` does).
|
|
174
|
+
*/
|
|
175
|
+
readonly conversationId: string | null;
|
|
176
|
+
/** The open the backend could not settle (`unknown_open`), for support; null otherwise. */
|
|
177
|
+
readonly openId: string | null;
|
|
132
178
|
}
|
|
133
179
|
interface AgentConversation {
|
|
134
180
|
/** The key as a string, for the app's own maps and the events. */
|
|
@@ -142,18 +188,26 @@ interface AgentConversation {
|
|
|
142
188
|
*/
|
|
143
189
|
show(open?: {
|
|
144
190
|
readonly place?: AgentPlace | null;
|
|
145
|
-
readonly entryPoint?:
|
|
191
|
+
readonly entryPoint?: AgentEntryPoint | null;
|
|
146
192
|
}): () => void;
|
|
147
|
-
/**
|
|
193
|
+
/**
|
|
194
|
+
* The place and the way in changed while a view is attached: told live where the backend can, else on the next
|
|
195
|
+
* session. `undefined` keeps what was told; `null` clears it.
|
|
196
|
+
*/
|
|
148
197
|
tell(open: {
|
|
149
198
|
readonly place?: AgentPlace | null;
|
|
150
|
-
readonly entryPoint?:
|
|
199
|
+
readonly entryPoint?: AgentEntryPoint | null;
|
|
151
200
|
}): void;
|
|
152
201
|
getState(): AgentConversationState;
|
|
153
202
|
subscribe(listener: () => void): () => void;
|
|
154
203
|
/** Asks for a session again, after the backend could not be reached. */
|
|
155
204
|
retry(): void;
|
|
156
|
-
/**
|
|
205
|
+
/**
|
|
206
|
+
* Whether a reply can be rated: one this runtime saw given live. A reply restored from the device or a resumed
|
|
207
|
+
* transcript cannot be, until the API rates a turn by its conversation; the kits draw no thumbs for it.
|
|
208
|
+
*/
|
|
209
|
+
canRate(turnId: string): boolean;
|
|
210
|
+
/** A thumbs on a whole reply, against the session it was given in; a change of mind only is sent again. */
|
|
157
211
|
rate(turnId: string, rating: AgentRating): void;
|
|
158
212
|
/**
|
|
159
213
|
* Sends the person's `text` once in this conversation's life (a chip tapped twice, a retried tap). It is shown as
|
|
@@ -172,6 +226,11 @@ interface AgentClock {
|
|
|
172
226
|
}
|
|
173
227
|
interface AgentRuntimeOptions {
|
|
174
228
|
readonly backend: AgentBackend;
|
|
229
|
+
/**
|
|
230
|
+
* The agent this runtime talks to (its id at Vinaverse). It is part of every key, so two agents sharing the device's
|
|
231
|
+
* storage (`conversation.persistence`) never share a conversation. Default: none (one agent per storage namespace).
|
|
232
|
+
*/
|
|
233
|
+
readonly agent?: string;
|
|
175
234
|
/** The store's own options (locale, time zone, deep-link prefixes, transport, persistence, closeInBackground…). */
|
|
176
235
|
readonly conversation?: Omit<ConversationOptions, 'getSession' | 'refreshSecret' | 'clock'>;
|
|
177
236
|
/** Default: 500, 1500, 3500 ms, for errors with `retryable: true`; applied to `openSession` and `refreshSecret`. */
|
|
@@ -189,8 +248,28 @@ interface AgentRuntimeOptions {
|
|
|
189
248
|
*/
|
|
190
249
|
readonly insecureAddresses?: AgentInsecureAddresses;
|
|
191
250
|
readonly onEvent?: (event: AgentEvent) => void;
|
|
251
|
+
/**
|
|
252
|
+
* Where the launcher remembers it greeted a person (the app's preferences store). Given here, the launcher reads and
|
|
253
|
+
* writes it through the runtime (`greetings`), a sign-out fences it, and `erase()` removes it.
|
|
254
|
+
*/
|
|
255
|
+
readonly greetingStorage?: ConversationPersistence;
|
|
256
|
+
/**
|
|
257
|
+
* Keys an earlier version of the app or the kit wrote that no index lists, for a storage with neither `keys` nor
|
|
258
|
+
* `removePrefix`: removed by every sign-out from `conversation.persistence`, and by `erase()` from `greetingStorage`
|
|
259
|
+
* too. The migration that makes their removal certain on such a storage.
|
|
260
|
+
*/
|
|
261
|
+
readonly legacyKeys?: readonly string[];
|
|
192
262
|
/** Where the runtime's warnings go (the app's logger, crash reporter); default `console.warn`. */
|
|
193
|
-
readonly onWarning?: (message: string) => void;
|
|
263
|
+
readonly onWarning?: (message: string, warning: AgentWarning) => void;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* What a warning is about, for an app's logger to count without reading the message: `insecure_addresses` (a leg let
|
|
267
|
+
* off the wss:// and https:// check outside development), `callback_threw` (the app's `onEvent` or `onActivity` threw;
|
|
268
|
+
* `callback` names it), `events_dropped` (the oldest analytics events, while the salt is read).
|
|
269
|
+
*/
|
|
270
|
+
interface AgentWarning {
|
|
271
|
+
readonly code: 'insecure_addresses' | 'callback_threw' | 'events_dropped';
|
|
272
|
+
readonly callback?: 'onEvent' | 'onActivity';
|
|
194
273
|
}
|
|
195
274
|
/** The legs whose session address may be plaintext: `realtime` (the WebSocket), `turns` (HTTP). */
|
|
196
275
|
interface AgentInsecureAddresses {
|
|
@@ -207,15 +286,43 @@ interface AgentRuntime {
|
|
|
207
286
|
peek(key: AgentKey): AgentConversation;
|
|
208
287
|
/** A new conversation for the key from the person's next opening; the old one is let go and forgotten. */
|
|
209
288
|
startNew(key: AgentKey): void;
|
|
210
|
-
/**
|
|
289
|
+
/**
|
|
290
|
+
* Closes the key's conversation now; the next opening continues it in a new session. What the device kept of it and
|
|
291
|
+
* the conversation it continues stay: `forget` removes them.
|
|
292
|
+
*/
|
|
211
293
|
dispose(key: AgentKey): void;
|
|
294
|
+
/**
|
|
295
|
+
* Closes the key's conversation and forgets it on this device: the conversation it continued and the transcript kept
|
|
296
|
+
* by `persistence`. History's "delete" calls it after the tenant's backend deleted the conversation.
|
|
297
|
+
*/
|
|
298
|
+
forget(key: AgentKey): void;
|
|
299
|
+
/** Ends every conversation no view shows that is past its session's end. The kits call it when the app comes back. */
|
|
300
|
+
sweep(): void;
|
|
301
|
+
/**
|
|
302
|
+
* History's delete: the backend deletes the conversation, then the device forgets it, only where the key still
|
|
303
|
+
* continues that conversation (an older history entry never forgets the key's newer one).
|
|
304
|
+
*/
|
|
305
|
+
deleteConversation(key: AgentKey, conversationId: string): Promise<void>;
|
|
306
|
+
/**
|
|
307
|
+
* The person's erasure on this device: a sign-out, plus the launcher's greeting records (`greetingStorage`) and the
|
|
308
|
+
* analytics salt, every key this version and alpha.5 or alpha.6 wrote. Keys no index lists (an earlier version's, a
|
|
309
|
+
* write lost with its process) are found only when the storage has `keys` or `removePrefix`.
|
|
310
|
+
*/
|
|
311
|
+
erase(): Promise<void>;
|
|
312
|
+
/** The launcher's greeting storage, under the sign-out fence; null without `greetingStorage`. */
|
|
313
|
+
readonly greetings: ConversationPersistence | null;
|
|
212
314
|
/**
|
|
213
315
|
* The key goes on with this conversation (history's "Continue"): pinned for the key and opened through the backend's
|
|
214
316
|
* resume. One that is gone (404, 410: the backend's `AgentRefusal('ended')`) is said as `ended`, never replaced by a
|
|
215
317
|
* new one silently.
|
|
216
318
|
*/
|
|
217
319
|
continue(key: AgentKey, conversationId: string): AgentConversation;
|
|
218
|
-
/**
|
|
320
|
+
/**
|
|
321
|
+
* Every conversation closed and forgotten, and everything this runtime kept on the device (every transcript it ever
|
|
322
|
+
* wrote under `conversation.persistenceKey`, even of conversations already closed), the status and the name; then
|
|
323
|
+
* the backend is told to end the sessions at the same time. A late answer from before (a session, a status, a write)
|
|
324
|
+
* changes nothing. Kept on purpose: the launcher's greeting records and the analytics salt (`erase` takes them).
|
|
325
|
+
*/
|
|
219
326
|
signOut(): Promise<void>;
|
|
220
327
|
/** The agent's status, read from the backend at most every `statusStaleMs`. */
|
|
221
328
|
status(): Promise<AgentStatus>;
|
|
@@ -227,8 +334,27 @@ interface AgentRuntime {
|
|
|
227
334
|
/** An event from a kit or the app, passed to `onEvent`. */
|
|
228
335
|
emit(event: AgentEvent): void;
|
|
229
336
|
}
|
|
230
|
-
/**
|
|
231
|
-
|
|
337
|
+
/**
|
|
338
|
+
* Where the launcher remembers that it greeted a person in a mode, the key its storage sees. Encoded so a guest
|
|
339
|
+
* (`null`) is never a person whose id is "guest".
|
|
340
|
+
*/
|
|
341
|
+
declare function greetedKey(subject: string | null, mode: string): string;
|
|
342
|
+
/**
|
|
343
|
+
* A conversation's key as analytics sees it: SHA-256 of the install's salt and the key, 128 bits in hex. Stable per
|
|
344
|
+
* install (the runtime keeps the salt in the app's storage until `erase()`), never the person's id, and not
|
|
345
|
+
* recomputable from a guessed id without the salt.
|
|
346
|
+
*/
|
|
347
|
+
declare function hashKey(key: string, salt: string): string;
|
|
348
|
+
/**
|
|
349
|
+
* The key as a string: one conversation per agent, person, mode, business and thread. Encoded as a JSON array, so no
|
|
350
|
+
* value can pass for another (a guest is `null`, never a subject named "guest"; a `|` in an id is just a character).
|
|
351
|
+
*/
|
|
352
|
+
declare function agentKey(key: AgentKey, agent?: string | null): string;
|
|
232
353
|
declare function createAgentRuntime(options: AgentRuntimeOptions): AgentRuntime;
|
|
354
|
+
/**
|
|
355
|
+
* An `AgentRefusal`, also one made by another copy of this package (the mock in `@vinaverse/client/testing`, the
|
|
356
|
+
* backend helpers in `@vinaverse/client/backend`, a second install): recognised by its name and kind, not its class.
|
|
357
|
+
*/
|
|
358
|
+
declare function isRefusal(error: unknown): error is AgentRefusal;
|
|
233
359
|
|
|
234
|
-
export { type AgentBackend as A, type AgentClock as a, type AgentConversation as b, type AgentConversationState as c, type
|
|
360
|
+
export { type AgentBackend as A, type AgentClock as a, type AgentConversation as b, type AgentConversationState as c, type AgentEntryPoint as d, type AgentEvent as e, type AgentEventType as f, type AgentFailure as g, type AgentFailureReason as h, type AgentInsecureAddresses as i, type AgentKey as j, type AgentPlace as k, type AgentRating as l, AgentRefusal as m, type AgentRetryPolicy as n, type AgentRuntime as o, type AgentRuntimeOptions as p, type AgentSessionRequest as q, type AgentStatus as r, type AgentStatusRead as s, type AgentWarning as t, agentKey as u, createAgentRuntime as v, greetedKey as w, hashKey as x, isRefusal as y };
|