@ray-js/t-agent-plugin-aistream 0.2.0-beta-11 → 0.2.0-beta-12
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/utils/AIStream.js +6 -5
- package/dist/utils/defaultMock.js +15 -10
- package/dist/utils/sendMessage.js +118 -23
- package/dist/withAIStream.js +8 -7
- package/package.json +2 -2
package/dist/utils/AIStream.js
CHANGED
|
@@ -347,7 +347,7 @@ export class AIStreamEvent {
|
|
|
347
347
|
userData: chunk.userData
|
|
348
348
|
});
|
|
349
349
|
}
|
|
350
|
-
|
|
350
|
+
sendEventPayloadEnd({
|
|
351
351
|
eventId: this.eventId,
|
|
352
352
|
sessionId: this.sessionId,
|
|
353
353
|
dataChannel
|
|
@@ -380,7 +380,7 @@ export class AIStreamEvent {
|
|
|
380
380
|
stream.started = true;
|
|
381
381
|
if (source.type === 'audio') {
|
|
382
382
|
if (source.amplitudeCount) {
|
|
383
|
-
|
|
383
|
+
registerRecordAmplitudes({
|
|
384
384
|
count: source.amplitudeCount
|
|
385
385
|
});
|
|
386
386
|
}
|
|
@@ -404,7 +404,7 @@ export class AIStreamEvent {
|
|
|
404
404
|
}
|
|
405
405
|
if (source.type === 'audio') {
|
|
406
406
|
if (source.amplitudeCount) {
|
|
407
|
-
|
|
407
|
+
unregisterVoiceAmplitudes({
|
|
408
408
|
count: source.amplitudeCount
|
|
409
409
|
});
|
|
410
410
|
}
|
|
@@ -421,7 +421,7 @@ export class AIStreamEvent {
|
|
|
421
421
|
// userData: source.userData,
|
|
422
422
|
// });
|
|
423
423
|
}
|
|
424
|
-
|
|
424
|
+
sendEventPayloadEnd({
|
|
425
425
|
eventId: this.eventId,
|
|
426
426
|
sessionId: this.sessionId,
|
|
427
427
|
dataChannel
|
|
@@ -449,7 +449,8 @@ export class AIStreamEvent {
|
|
|
449
449
|
return;
|
|
450
450
|
}
|
|
451
451
|
if (this.sessionId) {
|
|
452
|
-
|
|
452
|
+
// 故意不等,直接发送中断事件
|
|
453
|
+
sendEventChatBreak({
|
|
453
454
|
eventId: this.eventId,
|
|
454
455
|
sessionId: this.sessionId,
|
|
455
456
|
userData: options === null || options === void 0 ? void 0 : options.userData
|
|
@@ -153,14 +153,18 @@ mock.hooks.hook('closeSession', context => {
|
|
|
153
153
|
map.delete(sessionId);
|
|
154
154
|
context.result = true;
|
|
155
155
|
});
|
|
156
|
-
mock.hooks.hook('sendEventStart', context => {
|
|
156
|
+
mock.hooks.hook('sendEventStart', async context => {
|
|
157
157
|
const {
|
|
158
158
|
options
|
|
159
159
|
} = context;
|
|
160
160
|
const {
|
|
161
161
|
sessionId
|
|
162
162
|
} = options;
|
|
163
|
+
|
|
164
|
+
// throw new Error('sendEventStart is deprecated, use sendEventStartV2 instead');
|
|
165
|
+
|
|
163
166
|
const session = getSession(sessionId);
|
|
167
|
+
await mock.sleep(200);
|
|
164
168
|
if (session.currentEvent) {
|
|
165
169
|
throw new Error('sendEventStart already in event');
|
|
166
170
|
}
|
|
@@ -216,13 +220,14 @@ mock.hooks.hook('unregisterVoiceAmplitudes', context => {
|
|
|
216
220
|
mock.data.delete('recordAmplitudesCount');
|
|
217
221
|
context.result = true;
|
|
218
222
|
});
|
|
219
|
-
mock.hooks.hook('sendEventEnd', context => {
|
|
223
|
+
mock.hooks.hook('sendEventEnd', async context => {
|
|
220
224
|
const session = getSession(context.options.sessionId, context.options.eventId);
|
|
221
225
|
context.result = true;
|
|
222
226
|
const event = session.currentEvent;
|
|
223
227
|
if (event.eventId !== context.options.eventId) {
|
|
224
228
|
throw new Error('sendEventEnd eventId mismatch');
|
|
225
229
|
}
|
|
230
|
+
await mock.sleep(100);
|
|
226
231
|
(async () => {
|
|
227
232
|
var _ctx$responseSkills;
|
|
228
233
|
await event.asr.promise;
|
|
@@ -249,7 +254,6 @@ mock.hooks.hook('sendEventEnd', context => {
|
|
|
249
254
|
return;
|
|
250
255
|
}
|
|
251
256
|
event.replyEvent(EventType.EVENT_END);
|
|
252
|
-
console.log('No data to send, ending event, session.currentEvent = null');
|
|
253
257
|
session.currentEvent = null;
|
|
254
258
|
return;
|
|
255
259
|
}
|
|
@@ -319,28 +323,28 @@ mock.hooks.hook('sendEventEnd', context => {
|
|
|
319
323
|
return;
|
|
320
324
|
}
|
|
321
325
|
event.replyEvent(EventType.EVENT_END);
|
|
322
|
-
console.log('finish sendEventEnd session.currentEvent = null');
|
|
323
326
|
session.currentEvent = null;
|
|
324
327
|
})();
|
|
325
328
|
});
|
|
326
|
-
mock.hooks.hook('sendEventPayloadEnd', context => {
|
|
329
|
+
mock.hooks.hook('sendEventPayloadEnd', async context => {
|
|
327
330
|
getSession(context.options.sessionId, context.options.eventId);
|
|
328
331
|
context.result = true;
|
|
332
|
+
await mock.sleep(100);
|
|
329
333
|
});
|
|
330
|
-
mock.hooks.hook('sendEventChatBreak', context => {
|
|
334
|
+
mock.hooks.hook('sendEventChatBreak', async context => {
|
|
331
335
|
const session = getSession(context.options.sessionId, context.options.eventId);
|
|
332
336
|
session.currentEvent.controller.abort(new Error('sendEventChatBreak'));
|
|
333
|
-
console.log('sendEventChatBreak currentEvent = null');
|
|
334
337
|
session.currentEvent = null;
|
|
335
338
|
context.result = true;
|
|
336
339
|
});
|
|
337
|
-
mock.hooks.hook('startRecordAndSendAudioData', context => {
|
|
340
|
+
mock.hooks.hook('startRecordAndSendAudioData', async context => {
|
|
338
341
|
const session = getSession(context.options.sessionId);
|
|
339
342
|
if (!session.currentEvent) {
|
|
340
343
|
throw new Error('startRecordAndSendAudioData event not exists');
|
|
341
344
|
}
|
|
342
345
|
const event = session.currentEvent;
|
|
343
346
|
context.result = true;
|
|
347
|
+
await mock.sleep(100);
|
|
344
348
|
(async () => {
|
|
345
349
|
const {
|
|
346
350
|
finishController
|
|
@@ -378,7 +382,7 @@ mock.hooks.hook('startRecordAndSendAudioData', context => {
|
|
|
378
382
|
}
|
|
379
383
|
|
|
380
384
|
// 终止识别到出完整结果的延迟
|
|
381
|
-
await mock.sleep(
|
|
385
|
+
await mock.sleep(500);
|
|
382
386
|
if (event.controller.signal.aborted) {
|
|
383
387
|
return;
|
|
384
388
|
}
|
|
@@ -437,13 +441,14 @@ mock.hooks.hook('startRecordAndSendAudioData', context => {
|
|
|
437
441
|
}
|
|
438
442
|
})();
|
|
439
443
|
});
|
|
440
|
-
mock.hooks.hook('stopRecordAndSendAudioData', context => {
|
|
444
|
+
mock.hooks.hook('stopRecordAndSendAudioData', async context => {
|
|
441
445
|
const session = getSession(context.options.sessionId);
|
|
442
446
|
if (!session.currentEvent) {
|
|
443
447
|
throw new Error('stopRecordAndSendAudioData event not exists');
|
|
444
448
|
}
|
|
445
449
|
session.currentEvent.asr.finishController.abort(new Error('stopRecordAndSendAudioData'));
|
|
446
450
|
context.result = true;
|
|
451
|
+
await mock.sleep(100);
|
|
447
452
|
});
|
|
448
453
|
mock.hooks.hook('startRecordAndSendVideoData', context => {
|
|
449
454
|
context.result = true;
|
|
@@ -7,6 +7,7 @@ import { AIStreamAttributePayloadType, AIStreamAttributeType, AIStreamChatSysWor
|
|
|
7
7
|
import { EmitterEvent, generateId, safeParseJSON, StreamResponse } from '@ray-js/t-agent';
|
|
8
8
|
import { tryCatch } from './misc';
|
|
9
9
|
import { AIStreamConnectionError } from './errors';
|
|
10
|
+
import logger from './logger';
|
|
10
11
|
const mimeTypeToFormatMap = {
|
|
11
12
|
'video/mp4': FileFormat.MP4,
|
|
12
13
|
'text/json': FileFormat.JSON,
|
|
@@ -21,6 +22,7 @@ export class AIStreamSessionError extends Error {
|
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
24
|
export function sendBlocksToAIStream(params) {
|
|
25
|
+
logger.debug('sendBlocksToAIStream start');
|
|
24
26
|
const {
|
|
25
27
|
session,
|
|
26
28
|
blocks,
|
|
@@ -52,11 +54,59 @@ export function sendBlocksToAIStream(params) {
|
|
|
52
54
|
const stream = new ReadableStream({
|
|
53
55
|
async start(controller) {
|
|
54
56
|
const enqueue = part => {
|
|
55
|
-
if (canceled || closed) {
|
|
57
|
+
if (signal !== null && signal !== void 0 && signal.aborted || canceled || closed) {
|
|
56
58
|
return;
|
|
57
59
|
}
|
|
58
60
|
controller.enqueue(part);
|
|
59
61
|
};
|
|
62
|
+
let aborting = false;
|
|
63
|
+
const abort = async () => {
|
|
64
|
+
if (aborting || canceled || closed) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
aborting = true;
|
|
68
|
+
canceled = true;
|
|
69
|
+
if (event) {
|
|
70
|
+
await event.abort();
|
|
71
|
+
}
|
|
72
|
+
aborting = false;
|
|
73
|
+
};
|
|
74
|
+
const close = () => {
|
|
75
|
+
if (!closed) {
|
|
76
|
+
logger.debug('sendBlocksToAIStream close');
|
|
77
|
+
closed = true;
|
|
78
|
+
if (!canceled && !(signal !== null && signal !== void 0 && signal.aborted)) {
|
|
79
|
+
controller.close();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// signal?.addEventListener('abort', async () => {
|
|
85
|
+
// logger.debug('sendBlocksToAIStream signal aborted');
|
|
86
|
+
// abortPromise = abort();
|
|
87
|
+
// await abortPromise;
|
|
88
|
+
// logger.debug('sendBlocksToAIStream signal aborted done');
|
|
89
|
+
// close();
|
|
90
|
+
// });
|
|
91
|
+
|
|
92
|
+
let pendingCancel = false;
|
|
93
|
+
if (audioEmitter) {
|
|
94
|
+
audioEmitter.addEventListener('confirm', () => {
|
|
95
|
+
// 在确认发送时,如果事件还没创建,则取消发送
|
|
96
|
+
if (!event) {
|
|
97
|
+
logger.debug('sendBlocksToAIStream audioEmitter confirm before event start');
|
|
98
|
+
// event 留到后面再关
|
|
99
|
+
pendingCancel = true;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
audioEmitter.addEventListener('cancel', () => {
|
|
103
|
+
if (!event) {
|
|
104
|
+
logger.debug('sendBlocksToAIStream audioEmitter cancel before event start');
|
|
105
|
+
// event 留到后面再关
|
|
106
|
+
pendingCancel = true;
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}
|
|
60
110
|
let error;
|
|
61
111
|
[error, event] = await tryCatch(() => session.startEvent({
|
|
62
112
|
userData: [{
|
|
@@ -65,15 +115,26 @@ export function sendBlocksToAIStream(params) {
|
|
|
65
115
|
value: JSON.stringify(attribute)
|
|
66
116
|
}]
|
|
67
117
|
}));
|
|
68
|
-
if (
|
|
69
|
-
|
|
70
|
-
|
|
118
|
+
if (error) {
|
|
119
|
+
const e = new AIStreamSessionError(error.message, error.code || 0);
|
|
120
|
+
enqueue({
|
|
121
|
+
type: 'error',
|
|
122
|
+
error: e,
|
|
123
|
+
level: 'error',
|
|
124
|
+
meta: {}
|
|
125
|
+
});
|
|
126
|
+
if (audioEmitter) {
|
|
127
|
+
audioEmitter.dispatchEvent(new EmitterEvent('error', {
|
|
128
|
+
detail: e
|
|
129
|
+
}));
|
|
130
|
+
}
|
|
131
|
+
close();
|
|
71
132
|
return;
|
|
72
133
|
}
|
|
73
|
-
if (
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
134
|
+
if (signal !== null && signal !== void 0 && signal.aborted || pendingCancel) {
|
|
135
|
+
logger.debug('sendBlocksToAIStream pendingCancel aborted');
|
|
136
|
+
await abort();
|
|
137
|
+
close();
|
|
77
138
|
return;
|
|
78
139
|
}
|
|
79
140
|
const meta = {
|
|
@@ -91,6 +152,7 @@ export function sendBlocksToAIStream(params) {
|
|
|
91
152
|
}
|
|
92
153
|
const packet = safeParseJSON(data.body.text);
|
|
93
154
|
if (packet.bizType === ReceivedTextPacketType.NLG) {
|
|
155
|
+
logger.debug('sendBlocksToAIStream Receive NLG', packet.data.content);
|
|
94
156
|
const text = prevText + packet.data.content;
|
|
95
157
|
enqueue({
|
|
96
158
|
type: 'text',
|
|
@@ -100,6 +162,7 @@ export function sendBlocksToAIStream(params) {
|
|
|
100
162
|
});
|
|
101
163
|
prevText = text;
|
|
102
164
|
} else if (packet.bizType === ReceivedTextPacketType.SKILL) {
|
|
165
|
+
logger.debug('sendBlocksToAIStream Receive SKILL', packet.data);
|
|
103
166
|
enqueue({
|
|
104
167
|
id: generateId(),
|
|
105
168
|
type: 'attachment',
|
|
@@ -110,11 +173,15 @@ export function sendBlocksToAIStream(params) {
|
|
|
110
173
|
} else if (packet.bizType === ReceivedTextPacketType.ASR && audioEmitter) {
|
|
111
174
|
if (packet.eof === ReceivedTextPacketEof.END) {
|
|
112
175
|
if (packet.data.text === '') {
|
|
176
|
+
logger.debug('sendBlocksToAIStream Receive ASR EOF EMPTY');
|
|
113
177
|
// 没识别出任何文本
|
|
114
178
|
audioEmitter.dispatchEvent(new EmitterEvent('error', {
|
|
115
|
-
detail: {
|
|
179
|
+
detail: {
|
|
180
|
+
name: 'AsrEmptyError'
|
|
181
|
+
}
|
|
116
182
|
}));
|
|
117
183
|
} else {
|
|
184
|
+
logger.debug('sendBlocksToAIStream Receive ASR EOF', packet.data.text);
|
|
118
185
|
audioEmitter.dispatchEvent(new EmitterEvent('finish', {
|
|
119
186
|
detail: {
|
|
120
187
|
text: packet.data.text
|
|
@@ -122,6 +189,7 @@ export function sendBlocksToAIStream(params) {
|
|
|
122
189
|
}));
|
|
123
190
|
}
|
|
124
191
|
} else {
|
|
192
|
+
logger.debug('sendBlocksToAIStream Receive ASR', packet.data.text);
|
|
125
193
|
audioEmitter.dispatchEvent(new EmitterEvent('update', {
|
|
126
194
|
detail: {
|
|
127
195
|
text: packet.data.text
|
|
@@ -165,35 +233,48 @@ export function sendBlocksToAIStream(params) {
|
|
|
165
233
|
}
|
|
166
234
|
} else if (data.type === 'sessionState') {
|
|
167
235
|
if (data.body.sessionState === SessionState.CLOSED || data.body.sessionState === SessionState.CREATE_FAILED) {
|
|
236
|
+
const e = new AIStreamSessionError('Session closed', data.body.code);
|
|
168
237
|
enqueue({
|
|
169
238
|
type: 'error',
|
|
170
|
-
error:
|
|
239
|
+
error: e,
|
|
171
240
|
level: 'error',
|
|
172
241
|
meta
|
|
173
242
|
});
|
|
243
|
+
if (audioEmitter) {
|
|
244
|
+
audioEmitter.dispatchEvent(new EmitterEvent('error', {
|
|
245
|
+
detail: e
|
|
246
|
+
}));
|
|
247
|
+
}
|
|
248
|
+
close();
|
|
174
249
|
}
|
|
175
250
|
} else if (data.type === 'connectionState') {
|
|
176
251
|
if (data.body.connectState === ConnectState.DISCONNECTED || data.body.connectState === ConnectState.CLOSED) {
|
|
252
|
+
const e = new AIStreamConnectionError('Connection disconnected', data.body.code);
|
|
177
253
|
enqueue({
|
|
178
254
|
type: 'error',
|
|
179
|
-
error:
|
|
255
|
+
error: e,
|
|
180
256
|
level: 'error',
|
|
181
257
|
meta
|
|
182
258
|
});
|
|
259
|
+
if (audioEmitter) {
|
|
260
|
+
audioEmitter.dispatchEvent(new EmitterEvent('error', {
|
|
261
|
+
detail: e
|
|
262
|
+
}));
|
|
263
|
+
}
|
|
264
|
+
close();
|
|
183
265
|
}
|
|
184
266
|
}
|
|
185
267
|
});
|
|
186
268
|
event.on('close', () => {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
269
|
+
logger.debug('sendBlocksToAIStream event closed');
|
|
270
|
+
if (!canceled) {
|
|
271
|
+
close();
|
|
190
272
|
}
|
|
191
273
|
});
|
|
192
274
|
event.on('finish', () => {
|
|
275
|
+
logger.debug('sendBlocksToAIStream event finished');
|
|
193
276
|
if (!canceled) {
|
|
194
|
-
|
|
195
|
-
// 当取消后,不需要关闭控制器
|
|
196
|
-
controller.close();
|
|
277
|
+
close();
|
|
197
278
|
}
|
|
198
279
|
});
|
|
199
280
|
event.on('error', error => {
|
|
@@ -238,26 +319,40 @@ export function sendBlocksToAIStream(params) {
|
|
|
238
319
|
type: 'audio',
|
|
239
320
|
amplitudeCount
|
|
240
321
|
});
|
|
241
|
-
audioEmitter.addEventListener('confirm', () => {
|
|
242
|
-
|
|
322
|
+
audioEmitter.addEventListener('confirm', async () => {
|
|
323
|
+
if (!canceled) {
|
|
324
|
+
await s.stop();
|
|
325
|
+
}
|
|
326
|
+
resolve();
|
|
243
327
|
});
|
|
244
328
|
audioEmitter.addEventListener('cancel', async () => {
|
|
245
|
-
await s.stop();
|
|
246
329
|
if (!canceled) {
|
|
247
|
-
|
|
248
|
-
await event.abort();
|
|
330
|
+
await s.stop();
|
|
249
331
|
}
|
|
332
|
+
logger.debug('sendBlocksToAIStream audio cancel aborted');
|
|
333
|
+
await abort();
|
|
250
334
|
resolve();
|
|
251
335
|
});
|
|
252
336
|
s.start();
|
|
253
337
|
});
|
|
338
|
+
if (signal !== null && signal !== void 0 && signal.aborted) {
|
|
339
|
+
logger.debug('sendBlocksToAIStream after audio aborted');
|
|
340
|
+
await abort();
|
|
341
|
+
close();
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
254
344
|
}
|
|
255
345
|
await event.end();
|
|
346
|
+
if (signal !== null && signal !== void 0 && signal.aborted) {
|
|
347
|
+
await abort();
|
|
348
|
+
close();
|
|
349
|
+
}
|
|
256
350
|
},
|
|
257
|
-
async cancel() {
|
|
351
|
+
async cancel(reason) {
|
|
258
352
|
if (!canceled) {
|
|
259
353
|
var _event;
|
|
260
354
|
canceled = true;
|
|
355
|
+
logger.debug('sendBlocksToAIStream stream canceled', reason);
|
|
261
356
|
await ((_event = event) === null || _event === void 0 ? void 0 : _event.abort());
|
|
262
357
|
}
|
|
263
358
|
}
|
package/dist/withAIStream.js
CHANGED
|
@@ -209,6 +209,7 @@ export function withAIStream() {
|
|
|
209
209
|
return result;
|
|
210
210
|
};
|
|
211
211
|
const chat = async (blocks, signal, options) => {
|
|
212
|
+
logger.log('withAIStream chat agent.chat start');
|
|
212
213
|
const {
|
|
213
214
|
sendBy = 'user',
|
|
214
215
|
responseBy = 'assistant',
|
|
@@ -303,6 +304,7 @@ export function withAIStream() {
|
|
|
303
304
|
await userMsg.show();
|
|
304
305
|
await userMsg.persist();
|
|
305
306
|
}
|
|
307
|
+
logger.log('withAIStream chat agent.chat send');
|
|
306
308
|
const {
|
|
307
309
|
response,
|
|
308
310
|
metaPromise
|
|
@@ -310,6 +312,7 @@ export function withAIStream() {
|
|
|
310
312
|
if (audioPromise) {
|
|
311
313
|
try {
|
|
312
314
|
await audioPromise;
|
|
315
|
+
logger.log('withAIStream chat agent.chat audioPromise finish');
|
|
313
316
|
} catch (e) {
|
|
314
317
|
// 没有识别到文字
|
|
315
318
|
return [];
|
|
@@ -320,6 +323,7 @@ export function withAIStream() {
|
|
|
320
323
|
role: responseBy
|
|
321
324
|
});
|
|
322
325
|
const skills = [];
|
|
326
|
+
logger.debug('withAIStream chat agent.flushStreamToShow');
|
|
323
327
|
const result = {
|
|
324
328
|
messages: await agent.flushStreamToShow(message, response, {
|
|
325
329
|
attachmentCompose: async (respMsg, part) => {
|
|
@@ -334,18 +338,15 @@ export function withAIStream() {
|
|
|
334
338
|
}
|
|
335
339
|
})
|
|
336
340
|
};
|
|
341
|
+
logger.debug('withAIStream chat agent.flushStreamToShow end');
|
|
337
342
|
if (skills.length) {
|
|
338
343
|
await hooks.callHook('onSkillsEnd', skills, message, result);
|
|
339
344
|
await message.update();
|
|
340
345
|
}
|
|
341
|
-
if (message.bubble.
|
|
342
|
-
if (message.bubble.text) {
|
|
343
|
-
await message.persist();
|
|
344
|
-
} else {
|
|
345
|
-
await message.remove();
|
|
346
|
-
}
|
|
347
|
-
} else {
|
|
346
|
+
if (message.bubble.text) {
|
|
348
347
|
await message.persist();
|
|
348
|
+
} else {
|
|
349
|
+
await message.remove();
|
|
349
350
|
}
|
|
350
351
|
return [userMsg, ...result.messages];
|
|
351
352
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ray-js/t-agent-plugin-aistream",
|
|
3
|
-
"version": "0.2.0-beta-
|
|
3
|
+
"version": "0.2.0-beta-12",
|
|
4
4
|
"author": "Tuya.inc",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": false,
|
|
@@ -35,5 +35,5 @@
|
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/url-parse": "^1.4.11"
|
|
37
37
|
},
|
|
38
|
-
"gitHead": "
|
|
38
|
+
"gitHead": "a4e65a8f099f9ffa6e215ae005589c63f40587fe"
|
|
39
39
|
}
|