@onereach/step-voice 4.0.13 → 4.0.16

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.
@@ -25,7 +25,7 @@ interface EVENT extends VoiceEvent {
25
25
  tags?: string[];
26
26
  out?: string;
27
27
  }
28
- export default class GlobalCommand extends VoiceStep<INPUT, OUTPUT, EVENT> {
28
+ export default class GlobalCommand extends VoiceStep<Partial<INPUT>, OUTPUT, EVENT> {
29
29
  get isGlobal(): boolean;
30
30
  get autoCancel(): boolean | undefined;
31
31
  runStep(): Promise<void>;
@@ -1,4 +1,5 @@
1
1
  "use strict";
2
+ /* eslint-disable @typescript-eslint/strict-boolean-expressions, @typescript-eslint/explicit-function-return-type */
2
3
  Object.defineProperty(exports, "__esModule", { value: true });
3
4
  const tslib_1 = require("tslib");
4
5
  const lodash_1 = tslib_1.__importDefault(require("lodash"));
@@ -1,8 +1,27 @@
1
- export default class InitiateCall extends VoiceStep<any, any, import("./voice").VoiceEvent> {
2
- constructor(thread: import("@onereach/flow-sdk/dst/types").IThread, stepData: import("@onereach/flow-sdk/dst/types").IStepData<any>);
3
- get conversation(): string;
1
+ import VoiceStep, { CallStartEvent, TODO } from './voice';
2
+ interface INPUT {
3
+ channelId?: string;
4
+ sessionTimeout?: number;
5
+ asr: TODO;
6
+ tts: TODO;
7
+ from: string;
8
+ endUserNumber: string;
9
+ sipHost?: string;
10
+ sipUser?: string;
11
+ sipPassword?: string;
12
+ timeout?: number;
13
+ headers?: Array<{
14
+ name: string;
15
+ value: string;
16
+ }>;
17
+ enableSpoofCallerId?: boolean;
18
+ spoofCallerId?: string;
19
+ isAMD?: boolean;
20
+ }
21
+ export default class InitiateCall extends VoiceStep<INPUT, TODO, CallStartEvent> {
22
+ get conversation(): string | import("@onereach/flow-sdk/dst/types").IMergeField;
4
23
  get autoCancel(): undefined;
5
24
  runStep(): Promise<void>;
6
25
  waitForCall(): Promise<void>;
7
26
  }
8
- import VoiceStep from "./voice";
27
+ export {};
@@ -1,22 +1,25 @@
1
1
  "use strict";
2
+ /* eslint-disable @typescript-eslint/strict-boolean-expressions, @typescript-eslint/explicit-function-return-type */
2
3
  Object.defineProperty(exports, "__esModule", { value: true });
3
4
  const tslib_1 = require("tslib");
4
5
  const voice_1 = tslib_1.__importDefault(require("./voice"));
5
- const _ = require('lodash');
6
- const timestring = require('timestring');
7
- const uuid = require('uuid');
8
- const defaultSessionTimeout = 5 * 60 * 1000;
6
+ const lodash_1 = tslib_1.__importDefault(require("lodash"));
7
+ const timestring_1 = tslib_1.__importDefault(require("timestring"));
8
+ const uuid_1 = tslib_1.__importDefault(require("uuid"));
9
+ const defaultSessionTimeoutMin = 5;
9
10
  class InitiateCall extends voice_1.default {
10
11
  get conversation() {
11
- return this.step.dataOut?.name ?? 'conversation';
12
+ if (this.step.dataOut == null)
13
+ throw new Error('missing conversation');
14
+ return this.step.dataOut;
12
15
  }
13
16
  get autoCancel() {
14
17
  return undefined;
15
18
  }
16
19
  async runStep() {
17
- const { channelId = uuid.v4() } = this.data;
20
+ const { channelId = uuid_1.default.v4() } = this.data;
18
21
  if (!this.session.key) {
19
- const sessionTimeoutMs = timestring(`${this.data.sessionTimeout} min`, 'ms') || defaultSessionTimeout;
22
+ const sessionTimeoutMs = (0, timestring_1.default)(`${this.data.sessionTimeout ?? defaultSessionTimeoutMin} min`, 'ms');
20
23
  await this.session.start({
21
24
  key: channelId,
22
25
  timeout: sessionTimeoutMs,
@@ -27,7 +30,8 @@ class InitiateCall extends voice_1.default {
27
30
  }
28
31
  });
29
32
  }
30
- await this.startConversation({ id: channelId, type: 'voicer' }, { events: [] });
33
+ const convData = { id: channelId, type: 'voicer' };
34
+ await this.startConversation(convData, { events: {} });
31
35
  this.gotoState('waitForCall');
32
36
  }
33
37
  async waitForCall() {
@@ -44,18 +48,18 @@ class InitiateCall extends voice_1.default {
44
48
  }
45
49
  };
46
50
  });
47
- await this.startConversation(event.params.channel, { events: [] });
51
+ await this.startConversation(event.params.channel, { events: {} });
48
52
  this.log.warn({ channel: event.params.channel, conv: this.conversation, data: this.get(this.conversation) }, 'Confirming that the OB call can be started');
49
53
  return this.exitFlow();
50
54
  }
51
55
  case 'call': {
52
56
  const channel = {
53
- botNumber: event.params.channel.to,
54
- endUserNumber,
55
57
  headers: event.params.headers,
58
+ ...event.params.channel,
56
59
  asr: asr.getSettings(),
57
60
  tts: tts.getVoice(),
58
- ...event.params.channel
61
+ botNumber: event.params.channel.to ?? 'unknown',
62
+ endUserNumber
59
63
  };
60
64
  delete channel.from;
61
65
  delete channel.to;
@@ -88,7 +92,7 @@ class InitiateCall extends voice_1.default {
88
92
  return this.exitStep('success');
89
93
  }
90
94
  case 'error': {
91
- const error = _.get(event, 'params.error.originateStatus');
95
+ const error = lodash_1.default.get(event, 'params.error.originateStatus');
92
96
  const errorChannel = {
93
97
  botNumber,
94
98
  endUserNumber
@@ -108,9 +112,10 @@ class InitiateCall extends voice_1.default {
108
112
  return this.exitStep('no answer', errorChannel);
109
113
  }
110
114
  await this.transcript(errorChannel, { action: 'Call Error' });
115
+ const errorParams = event.params.error;
111
116
  return this.throwError({
112
- name: event.params.error.name,
113
- message: `${event.params.error.date}: ${event.params.error.originateStatus}`
117
+ name: event.params.error?.name ?? 'VoiceError',
118
+ message: `${errorParams.date}: ${errorParams.originateStatus}`
114
119
  });
115
120
  }
116
121
  default:
@@ -119,8 +124,8 @@ class InitiateCall extends voice_1.default {
119
124
  });
120
125
  this.triggers.otherwise(async () => {
121
126
  await this.triggers.flush();
122
- const originateTimeout = timestring(`${timeout || 30} sec`, 'ms'); // timeout or 30 seconds
123
- const customHeaders = _.reduce(headers, (memo, header) => {
127
+ const originateTimeout = (0, timestring_1.default)(`${timeout ?? 30} sec`, 'ms'); // timeout or 30 seconds
128
+ const customHeaders = lodash_1.default.reduce(headers, (memo, header) => {
124
129
  memo[header.name] = `${header.value}`;
125
130
  return memo;
126
131
  }, {});
@@ -12,7 +12,7 @@ interface INPUT {
12
12
  };
13
13
  interSpeechTimeout: number;
14
14
  }
15
- export default class SayMessage extends VoiceStep<INPUT> {
15
+ export default class SayMessage extends VoiceStep<Partial<INPUT>> {
16
16
  runStep(): Promise<void>;
17
17
  }
18
18
  export {};
@@ -1,11 +1,12 @@
1
1
  "use strict";
2
+ /* eslint-disable @typescript-eslint/strict-boolean-expressions, @typescript-eslint/explicit-function-return-type */
2
3
  Object.defineProperty(exports, "__esModule", { value: true });
3
4
  const tslib_1 = require("tslib");
4
5
  const lodash_1 = tslib_1.__importDefault(require("lodash"));
5
6
  const voice_1 = tslib_1.__importDefault(require("./voice"));
6
7
  class SayMessage extends voice_1.default {
7
8
  async runStep() {
8
- const { audio, textType, tts, sensitiveData, interSpeechTimeout } = this.data;
9
+ const { audio, textType, tts, sensitiveData, interSpeechTimeout = 0 } = this.data;
9
10
  const channel = await this.fetchData();
10
11
  this.triggers.once(`in/voice/${channel.id}/event`, async (event) => {
11
12
  if (channel.recordCall && sensitiveData?.muteStep) {
@@ -1,8 +1,8 @@
1
- export default class WaitForCall extends VoiceStep<any, any, import("./voice").VoiceEvent> {
2
- constructor(thread: import("@onereach/flow-sdk/dst/types").IThread, stepData: import("@onereach/flow-sdk/dst/types").IStepData<any>);
3
- get conversation(): string | undefined;
1
+ import VoiceStep, { CallStartEvent, TODO } from './voice';
2
+ import { ITypedEvent } from '@onereach/flow-sdk/dst/types';
3
+ export default class WaitForCall extends VoiceStep<TODO, TODO, TODO> {
4
+ get conversation(): string | import("@onereach/flow-sdk/dst/types").IMergeField;
4
5
  get autoCancel(): boolean;
5
6
  runStep(): Promise<void>;
6
- onCall(event: any): Promise<unknown>;
7
+ onCall(event: ITypedEvent<CallStartEvent>): Promise<unknown>;
7
8
  }
8
- import VoiceStep from "./voice";
@@ -1,32 +1,35 @@
1
1
  "use strict";
2
+ /* eslint-disable @typescript-eslint/strict-boolean-expressions, @typescript-eslint/explicit-function-return-type */
2
3
  Object.defineProperty(exports, "__esModule", { value: true });
3
4
  const tslib_1 = require("tslib");
4
5
  const voice_1 = tslib_1.__importDefault(require("./voice"));
5
- const _ = require('lodash');
6
+ const lodash_1 = tslib_1.__importDefault(require("lodash"));
6
7
  const defaultSessionTimeout = 5 * 60 * 1000;
7
8
  class WaitForCall extends voice_1.default {
8
9
  get conversation() {
9
- return this.step.dataOut.name;
10
+ if (this.step.dataOut == null)
11
+ throw new Error('missing conversation');
12
+ return this.step.dataOut;
10
13
  }
11
14
  get autoCancel() {
12
15
  return false;
13
16
  }
14
17
  async runStep() {
15
18
  const selectedNumbers = this.data.selectedNumbers;
16
- _.forEach(selectedNumbers, number => {
17
- this.triggers.on(`in/voice/${number.value}/call`, event => this.onCall(event));
19
+ lodash_1.default.forEach(selectedNumbers, number => {
20
+ this.triggers.on(`in/voice/${number.value}/call`, async (event) => await this.onCall(event));
18
21
  });
19
22
  }
20
23
  async onCall(event) {
21
24
  const { autoHangup, asr, tts, endOfInputTimeout } = this.data;
22
25
  const channel = {
23
- autoHangup,
24
- botNumber: event.params.channel.to,
25
- endUserNumber: event.params.channel.from,
26
26
  headers: event.params.headers,
27
+ ...event.params.channel,
28
+ autoHangup,
27
29
  asr: asr.getSettings(),
28
30
  tts: tts.getVoice(),
29
- ...event.params.channel
31
+ botNumber: event.params.channel.to ?? 'unknown',
32
+ endUserNumber: event.params.channel?.from ?? 'unknown'
30
33
  };
31
34
  delete channel.from;
32
35
  delete channel.to;
package/dst/step.d.ts ADDED
@@ -0,0 +1,49 @@
1
+ import Step from '@onereach/flow-sdk/dst/step';
2
+ import { IThreadId, IEvent, IStepResult, IMergeField, IMergeFieldKey } from '@onereach/flow-sdk/dst/types';
3
+ import { IConversationData, IConversation, IConversationStep } from '@onereach/step-conversation/dst/types';
4
+ export interface ConvStepDataIn {
5
+ conversation?: IMergeFieldKey | IMergeField;
6
+ conversationThread?: string;
7
+ }
8
+ export default class ConvStep<TData = unknown, TIn = unknown, TOut = unknown, TParams = any> extends Step<TIn & ConvStepDataIn, TOut, TParams> {
9
+ convDataCache?: TData & IConversationData;
10
+ get conversation(): IMergeFieldKey | IMergeField;
11
+ /** id of the thread where conversation data is stored */
12
+ get dataThreadId(): IThreadId;
13
+ get autoCancel(): boolean | undefined;
14
+ get isGlobal(): boolean;
15
+ get useQueue(): boolean;
16
+ fetchData(): Promise<TData & IConversationData>;
17
+ updateData(): Promise<void>;
18
+ hasConversation(): Promise<boolean>;
19
+ runBefore(): Promise<void>;
20
+ runAfter(): Promise<void>;
21
+ hasActiveGlobal(): Promise<boolean>;
22
+ setTriggerType(): Promise<void>;
23
+ waitForConversation(): Promise<void>;
24
+ onSkipEvent(): Promise<void>;
25
+ cancel(): Promise<void>;
26
+ onCancel(): Promise<void>;
27
+ waitCancelEnd(): Promise<void>;
28
+ pause(): Promise<void>;
29
+ resume(): Promise<void>;
30
+ sendEventToStep({ toGlobal, toStep, action, event }: {
31
+ action?: string;
32
+ event?: IEvent;
33
+ toStep?: IConversationStep;
34
+ toGlobal?: boolean;
35
+ }): Promise<IStepResult | undefined>;
36
+ activeStep(isGlobal?: boolean): Promise<IConversationStep | undefined>;
37
+ /** @returns true if current conv is active */
38
+ pushConvStep(): Promise<boolean>;
39
+ /** @returns true if current conv was active */
40
+ popConvStep(): Promise<boolean>;
41
+ startConversation(data: TData, { autoCancel, events }: {
42
+ autoCancel?: boolean;
43
+ events: Record<string, {}>;
44
+ thread?: IThreadId;
45
+ }): Promise<void>;
46
+ _fetchData(): Promise<(TData & IConversationData) | undefined>;
47
+ _getConversation(): Promise<IConversation>;
48
+ _clearCache(): void;
49
+ }
package/dst/step.js ADDED
@@ -0,0 +1,264 @@
1
+ "use strict";
2
+ /* eslint-disable @typescript-eslint/strict-boolean-expressions */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const tslib_1 = require("tslib");
5
+ const step_1 = tslib_1.__importDefault(require("@onereach/flow-sdk/dst/step"));
6
+ class ConvStep extends step_1.default {
7
+ get conversation() {
8
+ if (this.data.conversation == null)
9
+ throw new Error('missing conversation');
10
+ return this.data.conversation;
11
+ }
12
+ /** id of the thread where conversation data is stored */
13
+ get dataThreadId() {
14
+ const dataThreadId = this.state.thread ?? this.data.conversationThread;
15
+ return dataThreadId || this.thread.id;
16
+ }
17
+ get autoCancel() {
18
+ return undefined;
19
+ }
20
+ get isGlobal() {
21
+ return false;
22
+ }
23
+ get useQueue() {
24
+ return true;
25
+ }
26
+ async fetchData() {
27
+ const data = await this._fetchData();
28
+ if (data?._conv == null)
29
+ throw new Error(`missing conversation data in state ${this.state.name}`);
30
+ return data;
31
+ }
32
+ async updateData() {
33
+ if (this.convDataCache == null)
34
+ throw new Error(`missing conversation cache in state ${this.state.name}`);
35
+ // console.log('UPDATE', this.conversation, this.thread.id, this.step.label, this.convDataCache?._conv.que)
36
+ const convDataThread = this.process.getSafeThread(this.dataThreadId);
37
+ await convDataThread.set(this.conversation, this.convDataCache);
38
+ }
39
+ async hasConversation() {
40
+ return (await this._fetchData())?._conv != null;
41
+ }
42
+ async runBefore() {
43
+ this.log.debug('conv.runBefore', { state: this.state, conv: this.conversation });
44
+ await super.runBefore();
45
+ // ensure cache is reset between step runs, just in case
46
+ this._clearCache();
47
+ this.triggers.local('_conv');
48
+ if (!await this.hasConversation())
49
+ return;
50
+ if (this.state.direct)
51
+ return;
52
+ if (this.event.action === 'cancel') {
53
+ this.state.name = 'onCancel';
54
+ return;
55
+ }
56
+ if (this.useQueue && !await this.pushConvStep()) {
57
+ return await this.waitForConversation();
58
+ }
59
+ if (this.event.action == null && this.event.processed !== true && this.convDataCache?._conv?.trg?.[this.event.name] != null) {
60
+ if (this.isGlobal)
61
+ return;
62
+ const hasGlobal = await this.sendEventToStep({ event: { ...this.event, action: 'global' }, toGlobal: true }); // redirect to global (1)
63
+ this.log.debug('conv.sendEventToStep toGlobal', { hasGlobal });
64
+ if (hasGlobal != null) {
65
+ this.state.prevSkipName = this.state.name;
66
+ this.state.name = 'onSkipEvent';
67
+ return;
68
+ }
69
+ }
70
+ if (this.isGlobal && this.event.action === 'global') {
71
+ return; // it was redirected from (1)
72
+ }
73
+ if (!this.isGlobal && (this.convDataCache?._conv?.glb?.length ?? 0) > 0) {
74
+ this.triggers.config({ params: { type: 'local' } });
75
+ }
76
+ }
77
+ async runAfter() {
78
+ if (!await this.hasConversation())
79
+ return await super.runAfter();
80
+ if (this.thread.hasControlAction()) {
81
+ if (await this.popConvStep()) {
82
+ await this.sendEventToStep({ toGlobal: this.isGlobal, action: 'activate' });
83
+ }
84
+ }
85
+ if (this.isGlobal && this.event.processed !== true) {
86
+ await this.sendEventToStep({ toGlobal: false, event: { ...this.event, processed: undefined, action: 'local' } });
87
+ }
88
+ await super.runAfter();
89
+ }
90
+ async hasActiveGlobal() {
91
+ const globalLength = (await this._getConversation())?.glb?.length ?? 0;
92
+ return globalLength > 0;
93
+ }
94
+ async setTriggerType() {
95
+ if (!this.isGlobal && !await this.hasActiveGlobal()) {
96
+ this.triggers.config({ params: { type: 'local' } });
97
+ }
98
+ }
99
+ async waitForConversation() {
100
+ if (this.state.name !== 'waitForConversation') {
101
+ this.log.debug(this.state, 'conv.begin waitForConversation');
102
+ this.state.prevWaitName = this.state.name;
103
+ this.state.name = 'waitForConversation';
104
+ }
105
+ else if (this.event.name === '_conv') {
106
+ this.log.debug(this.state, 'conv.end waitForConversation');
107
+ this.gotoState({ ...this.state, name: this.state.prevWaitName, prevWaitName: undefined });
108
+ }
109
+ else {
110
+ this.log.debug(this.state, 'conv.skip waitForConversation');
111
+ }
112
+ }
113
+ async onSkipEvent() {
114
+ this.log.debug('onSkipEvent');
115
+ this.state.name = this.state.prevSkipName;
116
+ delete this.state.prevSkipName;
117
+ }
118
+ async cancel() {
119
+ if (this.isGlobal) {
120
+ this.log.debug('conv.cannot cancel global');
121
+ return;
122
+ }
123
+ const conv = await this._getConversation();
124
+ const activeStep = await this.activeStep(false);
125
+ if (activeStep != null) {
126
+ this.log.debug('conv.cancel', activeStep);
127
+ conv.lcl.splice(0);
128
+ await this.updateData();
129
+ await this.sendEventToStep({ toGlobal: false, action: 'cancel', toStep: activeStep });
130
+ }
131
+ else {
132
+ this.log.debug('conv.nothing to cancel');
133
+ }
134
+ }
135
+ async onCancel() {
136
+ if (this.getExitStepId('cancel')) {
137
+ this.log.debug('conv.cancel exit');
138
+ this.exitStep('cancel');
139
+ }
140
+ else {
141
+ const conversationThread = this.state.thread ?? this.thread.id;
142
+ if (conversationThread === this.thread.id) {
143
+ this.log.debug('conv.cancel wait for end', this.conversation);
144
+ this.gotoState({ ...this.state, name: 'waitCancelEnd', direct: true });
145
+ }
146
+ else {
147
+ this.log.debug('conv.cancel end', this.conversation);
148
+ this.end();
149
+ }
150
+ }
151
+ }
152
+ async waitCancelEnd() {
153
+ this.exitFlow();
154
+ }
155
+ async pause() {
156
+ const conv = await this._getConversation();
157
+ const activeStep = await this.activeStep(false);
158
+ if (activeStep != null) {
159
+ this.log.debug('conv.pause', activeStep);
160
+ conv.stk.push(conv.lcl.splice(0)); // save que to stk
161
+ await this.sendEventToStep({ toGlobal: false, action: 'pause', toStep: activeStep });
162
+ }
163
+ else {
164
+ this.log.debug('conv.nothing to pause');
165
+ }
166
+ }
167
+ async resume() {
168
+ const conv = await this._getConversation();
169
+ if (conv.stk.length > 0) {
170
+ conv.lcl.unshift(...(conv.stk.pop() ?? [])); // restore que from stk
171
+ await this.sendEventToStep({ toGlobal: false, action: 'resume' });
172
+ }
173
+ else {
174
+ this.log.debug('conv.nothing to resume');
175
+ }
176
+ }
177
+ async sendEventToStep({ toGlobal, toStep, action, event = { name: '_conv', action } }) {
178
+ toStep || (toStep = await this.activeStep(toGlobal));
179
+ if (toStep != null) {
180
+ const target = { type: 'session', name: toStep.key, id: toStep.thread };
181
+ return await this.thread.eventManager.emit(event, { invocationType: 'async', target });
182
+ }
183
+ return undefined;
184
+ }
185
+ async activeStep(isGlobal = this.isGlobal) {
186
+ const conv = await this._getConversation();
187
+ return isGlobal ? conv.glb[conv.glb.length - 1] : conv.lcl[0];
188
+ }
189
+ /** @returns true if current conv is active */
190
+ async pushConvStep() {
191
+ const conv = await this._getConversation();
192
+ const sessionKey = this.session.key;
193
+ if (sessionKey == null)
194
+ throw new Error('session is required');
195
+ const que = this.isGlobal ? conv.glb : conv.lcl;
196
+ const queIndex = que.findIndex(stp => stp.key === sessionKey && this.thread.id === stp.thread);
197
+ if (queIndex < 0) {
198
+ if (que.length > 0 && !this.isGlobal && (this.autoCancel ?? conv.acl ?? false))
199
+ await this.cancel();
200
+ que.push({ key: sessionKey, thread: this.thread.id });
201
+ await this.updateData();
202
+ return this.isGlobal ? true : que.length === 1;
203
+ }
204
+ return queIndex === (this.isGlobal ? que.length - 1 : 0);
205
+ }
206
+ /** @returns true if current conv was active */
207
+ async popConvStep() {
208
+ const conv = await this._getConversation();
209
+ const sessionKey = this.session.key;
210
+ if (sessionKey == null)
211
+ throw new Error('session is required');
212
+ const que = this.isGlobal ? conv.glb : conv.lcl;
213
+ const queIndex = que.findIndex(stp => stp.key === sessionKey && this.thread.id === stp.thread);
214
+ if (queIndex >= 0) {
215
+ // console.log('SPLICE1', this.thread.id, this.step.label, que)
216
+ que.splice(queIndex, 1);
217
+ await this.updateData();
218
+ return this.isGlobal ? queIndex === que.length : queIndex === 0;
219
+ }
220
+ let updated = false;
221
+ conv.stk.forEach((steps, stepsIdx) => {
222
+ const stpIdx = steps.findIndex(stp => stp.key === sessionKey && this.thread.id === stp.thread);
223
+ if (stpIdx >= 0) {
224
+ if (steps.length > 1)
225
+ steps.splice(stpIdx, 1);
226
+ else
227
+ conv.stk.splice(stepsIdx, 1);
228
+ updated = true;
229
+ }
230
+ });
231
+ if (updated)
232
+ await this.updateData();
233
+ return false;
234
+ }
235
+ async startConversation(data, { autoCancel = false, events }) {
236
+ this.convDataCache = {
237
+ ...data,
238
+ _conv: {
239
+ acl: (autoCancel ? 1 : undefined),
240
+ trg: events,
241
+ glb: [],
242
+ stk: [],
243
+ lcl: []
244
+ }
245
+ };
246
+ await this.updateData();
247
+ // this.state.thread = this.dataThreadId
248
+ }
249
+ async _fetchData() {
250
+ if (this.convDataCache != null)
251
+ return this.convDataCache;
252
+ const convDataThread = this.process.getSafeThread(this.dataThreadId);
253
+ this.convDataCache = await convDataThread.get(this.conversation);
254
+ // console.log('FETCH', this.conversation, this.thread.id, this.step.label, this.convDataCache?._conv.que)
255
+ return this.convDataCache;
256
+ }
257
+ async _getConversation() {
258
+ return (await this.fetchData())._conv;
259
+ }
260
+ _clearCache() {
261
+ this.convDataCache = undefined;
262
+ }
263
+ }
264
+ exports.default = ConvStep;
package/dst/voice.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ICallback, IVoiceReporterTranscriptEventArgs, IPromtpSection } from '@onereach/flow-sdk/dst/types';
2
- import ConvStep from '@onereach/step-conversation/dst/step';
2
+ import ConvStep from './step';
3
3
  import BasicError from '@onereach/flow-sdk/dst/errors/base';
4
4
  export declare type TODO = any;
5
5
  export interface IVoiceChannel {
@@ -16,20 +16,25 @@ export interface IVoiceChannel {
16
16
  asr?: TODO;
17
17
  tts?: TODO;
18
18
  sessionEndedBy?: string;
19
+ to?: string;
20
+ from?: string;
21
+ headers?: Record<string, string>;
19
22
  }
20
- export declare type EventType = 'hangup' | 'error' | 'cancel' | 'avm-detected' | 'recognition' | 'digit' | 'digits' | 'conference-start' | 'conference-end' | 'playback' | 'timeout' | 'record' | 'bridge' | 'bridge/ended';
23
+ export declare type EventType = 'hangup' | 'error' | 'cancel' | 'avm-detected' | 'recognition' | 'digit' | 'digits' | 'conference-start' | 'conference-end' | 'playback' | 'timeout' | 'record' | 'bridge' | 'bridge/ended' | 'is_flow_ready' | 'call';
21
24
  export declare class VoiceStepError extends BasicError {
22
25
  }
23
26
  export interface VoiceEvent {
24
27
  type: EventType;
25
28
  error?: Error;
26
29
  }
30
+ export interface CallStartEvent extends VoiceEvent {
31
+ channel: IVoiceChannel;
32
+ headers?: Record<string, string>;
33
+ }
27
34
  export default class VoiceStep<TIn = unknown, TOut = unknown, TParams = VoiceEvent> extends ConvStep<IVoiceChannel, TIn & {
28
35
  handleCancel?: boolean;
29
36
  }, TOut, TParams> {
30
37
  get autoCancel(): boolean | undefined;
31
- onCancel(): Promise<void>;
32
- waitForEnd(): Promise<void>;
33
38
  sendCommands({ id, type, callback }: IVoiceChannel, commands: TODO[]): Promise<unknown>;
34
39
  extractSectionMessages(sections: IPromtpSection[]): string;
35
40
  extractSectionFiles(sections: IPromtpSection[]): Array<{
package/dst/voice.js CHANGED
@@ -5,7 +5,8 @@ exports.VoiceStepError = void 0;
5
5
  const tslib_1 = require("tslib");
6
6
  const lodash_1 = tslib_1.__importDefault(require("lodash"));
7
7
  const uuid_1 = require("uuid");
8
- const step_1 = tslib_1.__importDefault(require("@onereach/step-conversation/dst/step"));
8
+ // TODO: !!!!! import ConvStep from '@onereach/step-conversation/dst/step' !!!!!
9
+ const step_1 = tslib_1.__importDefault(require("./step"));
9
10
  const base_1 = tslib_1.__importDefault(require("@onereach/flow-sdk/dst/errors/base"));
10
11
  class VoiceStepError extends base_1.default {
11
12
  }
@@ -15,17 +16,6 @@ class VoiceStep extends step_1.default {
15
16
  get autoCancel() {
16
17
  return true;
17
18
  }
18
- async onCancel() {
19
- if (this.data.handleCancel === true) {
20
- this.exitStep('cancel');
21
- }
22
- else {
23
- this.gotoState('waitForEnd');
24
- }
25
- }
26
- async waitForEnd() {
27
- this.exitFlow();
28
- }
29
19
  async sendCommands({ id, type, callback }, commands) {
30
20
  if (lodash_1.default.isEmpty(commands))
31
21
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onereach/step-voice",
3
- "version": "4.0.13",
3
+ "version": "4.0.16",
4
4
  "author": "Roman Zolotarov <roman.zolotarov@onereach.com>",
5
5
  "contributors": [
6
6
  "Roman Zolotarov",
@@ -13,12 +13,12 @@
13
13
  "npm": ">= 6.0.0"
14
14
  },
15
15
  "dependencies": {
16
- "@onereach/step-conversation": "^1.0.33",
16
+ "@onereach/step-conversation": "^1.0.40",
17
17
  "lodash": "^4.17.21",
18
18
  "uuid": "^8.3.2"
19
19
  },
20
20
  "devDependencies": {
21
- "@onereach/flow-sdk": "^3.0.14",
21
+ "@onereach/flow-sdk": "^3.1.3",
22
22
  "@swc/cli": "^0.1.57",
23
23
  "@swc/core": "^1.2.197",
24
24
  "@swc/jest": "^0.2.21",
@@ -26,7 +26,7 @@
26
26
  "@types/lodash": "^4.14.182",
27
27
  "@types/timestring": "^6.0.2",
28
28
  "@types/uuid": "^8.3.4",
29
- "aws-sdk": "^2.1149.0",
29
+ "aws-sdk": "^2.1151.0",
30
30
  "babel-runtime": "^6.26.0",
31
31
  "docdash": "^1.2.0",
32
32
  "husky": "^8.0.1",