@ray-js/t-agent-plugin-aistream 0.2.0-beta-1

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.
Files changed (46) hide show
  1. package/LICENSE.md +21 -0
  2. package/README-zh_CN.md +12 -0
  3. package/README.md +12 -0
  4. package/dist/AIStreamTypes.d.ts +1413 -0
  5. package/dist/AIStreamTypes.js +216 -0
  6. package/dist/ChatHistoryStore.d.ts +66 -0
  7. package/dist/ChatHistoryStore.js +160 -0
  8. package/dist/global.d.ts +4 -0
  9. package/dist/global.js +4 -0
  10. package/dist/index.d.ts +4 -0
  11. package/dist/index.js +4 -0
  12. package/dist/polyfill.d.ts +1 -0
  13. package/dist/polyfill.js +8 -0
  14. package/dist/utils/AIStream.d.ts +137 -0
  15. package/dist/utils/AIStream.js +486 -0
  16. package/dist/utils/abort.d.ts +38 -0
  17. package/dist/utils/abort.js +177 -0
  18. package/dist/utils/actions.d.ts +48 -0
  19. package/dist/utils/actions.js +76 -0
  20. package/dist/utils/apis.d.ts +15 -0
  21. package/dist/utils/apis.js +10 -0
  22. package/dist/utils/defaultMock.d.ts +1 -0
  23. package/dist/utils/defaultMock.js +429 -0
  24. package/dist/utils/index.d.ts +11 -0
  25. package/dist/utils/index.js +11 -0
  26. package/dist/utils/logger.d.ts +2 -0
  27. package/dist/utils/logger.js +3 -0
  28. package/dist/utils/mock.d.ts +48 -0
  29. package/dist/utils/mock.js +72 -0
  30. package/dist/utils/observer.d.ts +61 -0
  31. package/dist/utils/observer.js +152 -0
  32. package/dist/utils/parsers.d.ts +10 -0
  33. package/dist/utils/parsers.js +13 -0
  34. package/dist/utils/promisify.d.ts +18 -0
  35. package/dist/utils/promisify.js +82 -0
  36. package/dist/utils/sendMessage.d.ts +21 -0
  37. package/dist/utils/sendMessage.js +241 -0
  38. package/dist/utils/ttt.d.ts +99 -0
  39. package/dist/utils/ttt.js +97 -0
  40. package/dist/utils/url.d.ts +11 -0
  41. package/dist/utils/url.js +31 -0
  42. package/dist/utils/version.d.ts +1 -0
  43. package/dist/utils/version.js +63 -0
  44. package/dist/withAIStream.d.ts +64 -0
  45. package/dist/withAIStream.js +420 -0
  46. package/package.json +39 -0
@@ -0,0 +1,486 @@
1
+ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
+ import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
3
+ import "core-js/modules/esnext.iterator.constructor.js";
4
+ import "core-js/modules/esnext.iterator.find.js";
5
+ import "core-js/modules/esnext.iterator.for-each.js";
6
+ import "core-js/modules/esnext.iterator.map.js";
7
+ import "core-js/modules/web.dom-collections.iterator.js";
8
+ import { AIStreamErrorCode, BizTag, ConnectClientType, ConnectState, EventType, SessionState } from '../AIStreamTypes';
9
+ import { closeSession, connect, createSession, disconnect, getCurrentHomeInfo, queryAgentToken, registerRecordAmplitudes, sendEventChatBreak, sendEventEnd, sendEventPayloadEnd, sendEventStart, sendImageData, sendTextData, startRecordAndSendAudioData, stopRecordAndSendAudioData, unregisterVoiceAmplitudes } from './ttt';
10
+ import { AIStreamObserver, AIStreamObserverPool } from './observer';
11
+ import { isAbortError } from '@ray-js/t-agent';
12
+ export class AIStreamClient {
13
+ constructor() {
14
+ _defineProperty(this, "pool", new AIStreamObserverPool());
15
+ _defineProperty(this, "cached", new Map());
16
+ }
17
+ getConnection(options) {
18
+ const key = "".concat(options.clientType, "|").concat(options.deviceId || '');
19
+ let connection = this.cached.get(key);
20
+ if (!connection) {
21
+ connection = new AIStreamConnection(this.pool, options);
22
+ }
23
+ return connection;
24
+ }
25
+ }
26
+ export class AIStreamConnection {
27
+ constructor(pool, options) {
28
+ _defineProperty(this, "connectionId", null);
29
+ _defineProperty(this, "state", ConnectState.INIT);
30
+ _defineProperty(this, "activeSessions", new Set());
31
+ _defineProperty(this, "promise", null);
32
+ _defineProperty(this, "observer", null);
33
+ _defineProperty(this, "onStateChanged", entry => {
34
+ if (entry.type === 'connectionState' && entry.body.connectionId === this.connectionId) {
35
+ this.activeSessions.forEach(session => {
36
+ if (session.sessionId) {
37
+ session._onStateChanged(entry);
38
+ }
39
+ });
40
+ if (entry.body.connectState === ConnectState.DISCONNECTED || entry.body.connectState === ConnectState.CLOSED) {
41
+ // 事件触发的时候,只做清理
42
+ this.state = entry.body.connectState;
43
+ this.cleanup();
44
+ }
45
+ }
46
+ if (entry.type === 'sessionState') {
47
+ this.activeSessions.forEach(session => {
48
+ if (session.sessionId && session.sessionId === entry.body.sessionId) {
49
+ session._onStateChanged(entry);
50
+ if (entry.body.sessionState === SessionState.CLOSED || entry.body.sessionState === SessionState.CREATE_FAILED) {
51
+ this.activeSessions.delete(session);
52
+ }
53
+ }
54
+ });
55
+ }
56
+ });
57
+ this.pool = pool;
58
+ this.options = options;
59
+ }
60
+ _ensureConnected() {
61
+ if (this.promise) {
62
+ return this.promise;
63
+ }
64
+ if (this.state === ConnectState.CONNECTED) {
65
+ return Promise.resolve();
66
+ }
67
+ this.promise = (async () => {
68
+ // 监听断开事件,重置 state & 清理
69
+ this.observer = new AIStreamObserver(this.onStateChanged, this.pool);
70
+ this.observer.observe({
71
+ connectionState: true,
72
+ sessionState: true
73
+ });
74
+ // 调用 SDK connect
75
+ const res = await connect(this.options);
76
+ this.connectionId = res.connectionId;
77
+ this.state = ConnectState.CONNECTED;
78
+ this.promise = null;
79
+ })();
80
+ return this.promise;
81
+ }
82
+ cleanup() {
83
+ var _this$observer;
84
+ (_this$observer = this.observer) === null || _this$observer === void 0 || _this$observer.disconnect();
85
+ this.observer = null;
86
+ this.connectionId = null;
87
+ this.promise = null;
88
+ this.activeSessions.forEach(s => s.cleanup());
89
+ this.activeSessions.clear();
90
+ }
91
+ createSession(options) {
92
+ const session = new AIStreamSession(this, this.pool, options);
93
+ this.activeSessions.add(session);
94
+ return session;
95
+ }
96
+ async closeSession(session) {
97
+ if (session.sessionId && this.connectionId) {
98
+ await closeSession({
99
+ sessionId: session.sessionId,
100
+ code: AIStreamErrorCode.OK
101
+ });
102
+ }
103
+ this.activeSessions.delete(session);
104
+ }
105
+
106
+ // 断连
107
+ async close() {
108
+ if (this.connectionId) {
109
+ // 只有设备端才需要断开连接,App 端由 App 来维持
110
+ if (this.options.clientType === ConnectClientType.DEVICE) {
111
+ await disconnect({
112
+ connectionId: this.connectionId
113
+ });
114
+ }
115
+ this.state = ConnectState.CLOSED;
116
+ this.cleanup();
117
+ }
118
+ }
119
+ }
120
+ export class AIStreamSession {
121
+ constructor(connection, pool, options) {
122
+ _defineProperty(this, "sessionId", null);
123
+ _defineProperty(this, "sendDataChannels", []);
124
+ _defineProperty(this, "revDataChannels", []);
125
+ _defineProperty(this, "promise", null);
126
+ _defineProperty(this, "_onStateChanged", entry => {
127
+ var _this$activeEvent;
128
+ (_this$activeEvent = this.activeEvent) === null || _this$activeEvent === void 0 || _this$activeEvent.emit('data', entry);
129
+ if (entry.type === 'sessionState' && (entry.body.sessionState === SessionState.CLOSED || entry.body.sessionState === SessionState.CREATE_FAILED)) {
130
+ this.cleanup();
131
+ }
132
+ });
133
+ _defineProperty(this, "onDataEntry", entry => {
134
+ var _this$activeEvent2;
135
+ if (!this.activeEvent) {
136
+ return;
137
+ }
138
+ (_this$activeEvent2 = this.activeEvent) === null || _this$activeEvent2 === void 0 || _this$activeEvent2.emit('data', entry);
139
+ if (entry.type === 'event' && entry.body.eventId === this.activeEvent.eventId) {
140
+ const {
141
+ eventType
142
+ } = entry.body;
143
+ if (eventType === EventType.EVENT_END || eventType === EventType.CHAT_BREAK || eventType === EventType.ONE_SHOT) {
144
+ var _this$activeEvent3;
145
+ (_this$activeEvent3 = this.activeEvent) === null || _this$activeEvent3 === void 0 || _this$activeEvent3.emit('finish');
146
+ this.cleanupEvent();
147
+ }
148
+ }
149
+ });
150
+ this.connection = connection;
151
+ this.pool = pool;
152
+ this.options = options;
153
+ }
154
+ ensureSession() {
155
+ if (this.promise) {
156
+ return this.promise;
157
+ }
158
+ if (this.sessionId) {
159
+ return Promise.resolve();
160
+ }
161
+ this.promise = (async () => {
162
+ await this.connection._ensureConnected();
163
+ let ownerId = this.options.ownerId;
164
+ if (!ownerId) {
165
+ if (this.connection.options.clientType === ConnectClientType.APP) {
166
+ const {
167
+ homeId
168
+ } = await getCurrentHomeInfo();
169
+ ownerId = homeId;
170
+ } else {
171
+ ownerId = this.connection.options.deviceId;
172
+ }
173
+ this.options.ownerId = ownerId;
174
+ }
175
+ const options = _objectSpread({
176
+ bizTag: BizTag.DEFAULT,
177
+ ownerId,
178
+ extParams: {}
179
+ }, this.options);
180
+ const {
181
+ agentToken,
182
+ bizConfig
183
+ } = await queryAgentToken(options);
184
+ const res = await createSession({
185
+ bizTag: options.bizTag,
186
+ agentToken,
187
+ bizConfig,
188
+ userData: options.userData
189
+ });
190
+ this.sessionId = res.sessionId;
191
+ this.sendDataChannels = res.sendDataChannels;
192
+ this.revDataChannels = res.revDataChannels;
193
+ })();
194
+ return this.promise;
195
+ }
196
+ async startEvent() {
197
+ let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
198
+ if (this.activeEvent) {
199
+ throw new Error('Cannot start a new event while another is active');
200
+ }
201
+ await this.ensureSession();
202
+ const {
203
+ eventId
204
+ } = await sendEventStart(_objectSpread({
205
+ sessionId: this.sessionId
206
+ }, options));
207
+ this.activeEvent = new AIStreamEvent({
208
+ eventId,
209
+ sessionId: this.sessionId,
210
+ sendDataChannels: this.sendDataChannels
211
+ });
212
+ const onError = error => {
213
+ if (isAbortError(error)) {
214
+ this.cleanupEvent();
215
+ }
216
+ };
217
+ this.activeEvent.on('error', onError);
218
+ const observerOptions = {
219
+ event: true,
220
+ dataChannels: this.revDataChannels,
221
+ sessionId: this.sessionId
222
+ };
223
+ this.activeObserver = new AIStreamObserver(this.onDataEntry, this.pool);
224
+ for (const revDataChannel of this.revDataChannels) {
225
+ if (revDataChannel.startsWith('text')) {
226
+ observerOptions.text = true;
227
+ }
228
+ if (revDataChannel.startsWith('audio')) {
229
+ observerOptions.audio = true;
230
+ }
231
+ if (revDataChannel.startsWith('video')) {
232
+ observerOptions.video = true;
233
+ }
234
+ if (revDataChannel.startsWith('file')) {
235
+ observerOptions.file = true;
236
+ }
237
+ if (revDataChannel.startsWith('image')) {
238
+ observerOptions.image = true;
239
+ }
240
+ }
241
+ this.activeObserver.observe(observerOptions);
242
+ return this.activeEvent;
243
+ }
244
+ cleanupEvent() {
245
+ var _this$activeObserver, _this$activeEvent4;
246
+ (_this$activeObserver = this.activeObserver) === null || _this$activeObserver === void 0 || _this$activeObserver.disconnect();
247
+ this.activeObserver = null;
248
+ (_this$activeEvent4 = this.activeEvent) === null || _this$activeEvent4 === void 0 || _this$activeEvent4.emit('close');
249
+ this.activeEvent = null;
250
+ }
251
+ cleanup() {
252
+ this.cleanupEvent();
253
+ this.sessionId = null;
254
+ this.sendDataChannels = [];
255
+ this.revDataChannels = [];
256
+ }
257
+
258
+ // 会话关闭清理
259
+ async close() {
260
+ await this.connection.closeSession(this);
261
+ if (this.sessionId) {
262
+ this.cleanup();
263
+ }
264
+ }
265
+ }
266
+ export class AIStreamEvent {
267
+ constructor(init) {
268
+ _defineProperty(this, "closed", false);
269
+ _defineProperty(this, "chains", Object.create(null));
270
+ _defineProperty(this, "streams", Object.create(null));
271
+ _defineProperty(this, "listeners", {
272
+ finish: new Set(),
273
+ error: new Set(),
274
+ data: new Set(),
275
+ close: new Set()
276
+ });
277
+ this.eventId = init.eventId;
278
+ this.sessionId = init.sessionId;
279
+ this.sendDataChannels = init.sendDataChannels;
280
+ }
281
+ findFirstCode(type) {
282
+ const code = this.sendDataChannels.find(code => code.startsWith(type));
283
+ if (!code) {
284
+ throw new Error("No available data code for type: ".concat(type));
285
+ }
286
+ return code;
287
+ }
288
+ write(chunk) {
289
+ if (this.closed) {
290
+ throw new Error('Cannot write to a closed event');
291
+ }
292
+ const dataChannel = chunk.dataChannel || this.findFirstCode(chunk.type);
293
+ let promise = this.chains[dataChannel];
294
+ if (!promise) {
295
+ promise = Promise.resolve();
296
+ }
297
+ this.chains[dataChannel] = promise.then(async () => {
298
+ if (this.closed) {
299
+ return;
300
+ }
301
+ if (chunk.type === 'text') {
302
+ await sendTextData({
303
+ sessionId: this.sessionId,
304
+ text: chunk.text,
305
+ dataChannel,
306
+ userData: chunk.userData
307
+ });
308
+ } else if (chunk.type === 'file') {
309
+ // await sendFileData({
310
+ // sessionId: this.sessionId,
311
+ // path: chunk.path,
312
+ // format: chunk.format,
313
+ // dataChannel,
314
+ // userData: chunk.userData,
315
+ // });
316
+ } else if (chunk.type === 'image') {
317
+ await sendImageData({
318
+ sessionId: this.sessionId,
319
+ path: chunk.path,
320
+ userData: chunk.userData
321
+ });
322
+ }
323
+ await sendEventPayloadEnd({
324
+ eventId: this.eventId,
325
+ sessionId: this.sessionId,
326
+ dataChannel
327
+ });
328
+ }).catch(error => {
329
+ this.emit('error', error);
330
+ throw error;
331
+ });
332
+ return this.chains[dataChannel];
333
+ }
334
+ stream(source) {
335
+ if (this.closed) {
336
+ throw new Error('Cannot stream to a closed event');
337
+ }
338
+ const dataChannel = source.dataChannel || this.findFirstCode(source.type);
339
+ if (this.streams[dataChannel]) {
340
+ throw new Error("".concat(dataChannel, " stream already exists"));
341
+ }
342
+ const stream = {
343
+ dataChannel,
344
+ type: source.type,
345
+ started: false,
346
+ start: async () => {
347
+ if (this.closed) {
348
+ throw new Error('Cannot stream to a closed event');
349
+ }
350
+ if (stream.started) {
351
+ return;
352
+ }
353
+ stream.started = true;
354
+ if (source.type === 'audio') {
355
+ if (source.amplitudeCount) {
356
+ await registerRecordAmplitudes({
357
+ count: source.amplitudeCount
358
+ });
359
+ }
360
+ await startRecordAndSendAudioData({
361
+ sessionId: this.sessionId,
362
+ dataChannel,
363
+ userData: source.userData
364
+ });
365
+ } else if (source.type === 'video') {
366
+ // const cameraType = source.cameraType || VideoCameraType.BACK;
367
+ // await startRecordAndSendVideoData({
368
+ // dataChannel,
369
+ // cameraType,
370
+ // userData: source.userData,
371
+ // });
372
+ }
373
+ },
374
+ stop: async () => {
375
+ if (!stream.started || this.closed) {
376
+ return;
377
+ }
378
+ if (source.type === 'audio') {
379
+ if (source.amplitudeCount) {
380
+ await unregisterVoiceAmplitudes({
381
+ count: source.amplitudeCount
382
+ });
383
+ }
384
+ await stopRecordAndSendAudioData({
385
+ sessionId: this.sessionId,
386
+ dataChannel,
387
+ userData: source.userData
388
+ });
389
+ } else if (source.type === 'video') {
390
+ // const cameraType = source.cameraType || VideoCameraType.BACK;
391
+ // await stopRecordAndSendVideoData({
392
+ // dataChannel,
393
+ // cameraType,
394
+ // userData: source.userData,
395
+ // });
396
+ }
397
+ await sendEventPayloadEnd({
398
+ eventId: this.eventId,
399
+ sessionId: this.sessionId,
400
+ dataChannel
401
+ });
402
+ delete this.streams[dataChannel];
403
+ stream.started = false;
404
+ }
405
+ };
406
+ this.streams[dataChannel] = stream;
407
+ return stream;
408
+ }
409
+ async end(options) {
410
+ if (this.closed) {
411
+ return;
412
+ }
413
+ await Promise.all([...Object.values(this.chains), ...Object.values(this.streams).map(s => s.stop())]);
414
+ await sendEventEnd({
415
+ eventId: this.eventId,
416
+ sessionId: this.sessionId,
417
+ userData: options === null || options === void 0 ? void 0 : options.userData
418
+ });
419
+ }
420
+ async abort(options) {
421
+ if (this.sessionId) {
422
+ await sendEventChatBreak({
423
+ eventId: this.eventId,
424
+ sessionId: this.sessionId,
425
+ userData: options === null || options === void 0 ? void 0 : options.userData
426
+ });
427
+ }
428
+ const error = new Error('This operation was aborted');
429
+ error.name = 'AbortError';
430
+ // 发送 break 后,stream 自动会关掉,在这里提前关闭
431
+ Object.values(this.streams).forEach(s => {
432
+ s.started = false;
433
+ });
434
+ this.emit('error', error);
435
+ this.emit('close');
436
+ }
437
+ on(name, callback) {
438
+ if (name === 'finish') {
439
+ this.listeners.finish.add(callback);
440
+ } else if (name === 'error') {
441
+ this.listeners.error.add(callback);
442
+ } else if (name === 'data') {
443
+ this.listeners.data.add(callback);
444
+ } else if (name === 'close') {
445
+ this.listeners.close.add(callback);
446
+ }
447
+ }
448
+ off(name, callback) {
449
+ if (name === 'finish') {
450
+ this.listeners.finish.delete(callback);
451
+ } else if (name === 'error') {
452
+ this.listeners.error.delete(callback);
453
+ } else if (name === 'data') {
454
+ this.listeners.data.delete(callback);
455
+ } else if (name === 'close') {
456
+ this.listeners.close.delete(callback);
457
+ }
458
+ }
459
+ emit(name, data) {
460
+ if (this.closed) {
461
+ return;
462
+ }
463
+ if (name === 'finish') {
464
+ this.listeners.finish.forEach(cb => cb());
465
+ this.emit('close');
466
+ } else if (name === 'error') {
467
+ this.listeners.error.forEach(cb => cb(data));
468
+ } else if (name === 'data') {
469
+ this.listeners.data.forEach(cb => cb(data));
470
+ } else if (name === 'close') {
471
+ this.closed = true;
472
+ this.listeners.close.forEach(cb => cb());
473
+ this.dispose();
474
+ }
475
+ }
476
+ dispose() {
477
+ this.sessionId = null;
478
+ this.listeners.finish.clear();
479
+ this.listeners.error.clear();
480
+ this.listeners.data.clear();
481
+ this.listeners.close.clear();
482
+ Object.values(this.streams).forEach(s => s.stop());
483
+ this.streams = Object.create(null);
484
+ this.chains = Object.create(null);
485
+ }
486
+ }
@@ -0,0 +1,38 @@
1
+ import { Emitter, EmitterEvent, AbortSignalObject } from '@ray-js/t-agent';
2
+ type EventCallback = (event: EmitterEvent) => void;
3
+ export declare class AbortSignal extends Emitter implements AbortSignalObject {
4
+ aborted: boolean;
5
+ onabort: EventCallback;
6
+ reason: any;
7
+ constructor();
8
+ toString(): string;
9
+ dispatchEvent(event: EmitterEvent): boolean;
10
+ /**
11
+ * @see {@link https://developer.mozilla.org/zh-CN/docs/Web/API/AbortSignal/throwIfAborted}
12
+ */
13
+ throwIfAborted(): void;
14
+ /**
15
+ * @see {@link https://developer.mozilla.org/zh-CN/docs/Web/API/AbortSignal/timeout_static}
16
+ * @param {number} time The "active" time in milliseconds before the returned {@link AbortSignalObject} will abort.
17
+ * The value must be within range of 0 and {@link Number.MAX_SAFE_INTEGER}.
18
+ * @returns {AbortSignalObject} The signal will abort with its {@link AbortSignalObject.reason} property set to a `TimeoutError` {@link DOMException} on timeout,
19
+ * or an `AbortError` {@link DOMException} if the operation was user-triggered.
20
+ */
21
+ static timeout(time: number): AbortSignal;
22
+ /**
23
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/any_static}
24
+ * @param {Iterable<AbortSignalObject>} iterable An {@link Iterable} (such as an {@link Array}) of abort signals.
25
+ * @returns {AbortSignalObject} - **Already aborted**, if any of the abort signals given is already aborted.
26
+ * The returned {@link AbortSignalObject}'s reason will be already set to the `reason` of the first abort signal that was already aborted.
27
+ * - **Asynchronously aborted**, when any abort signal in `iterable` aborts.
28
+ * The `reason` will be set to the reason of the first abort signal that is aborted.
29
+ */
30
+ static any(iterable: Iterable<AbortSignal>): AbortSignal;
31
+ }
32
+ export declare class AbortController {
33
+ signal: AbortSignal;
34
+ constructor();
35
+ abort(reason: any): void;
36
+ toString(): string;
37
+ }
38
+ export default AbortController;
@@ -0,0 +1,177 @@
1
+ import "core-js/modules/es.symbol.description.js";
2
+ import "core-js/modules/web.dom-collections.iterator.js";
3
+ // source: https://github.com/mo/abortcontroller-polyfill
4
+ import { Emitter } from '@ray-js/t-agent';
5
+ function createAbortEvent(reason) {
6
+ let event;
7
+ try {
8
+ event = new Event('abort');
9
+ } catch (e) {
10
+ if (typeof document !== 'undefined') {
11
+ if (!document.createEvent) {
12
+ // For Internet Explorer 8:
13
+ // @ts-ignore
14
+ event = document.createEventObject();
15
+ event.type = 'abort';
16
+ } else {
17
+ // For Internet Explorer 11:
18
+ event = document.createEvent('Event');
19
+ event.initEvent('abort', false, false);
20
+ }
21
+ } else {
22
+ // Fallback where document isn't available:
23
+ event = {
24
+ type: 'abort',
25
+ bubbles: false,
26
+ cancelable: false
27
+ };
28
+ }
29
+ }
30
+ event.reason = reason;
31
+ return event;
32
+ }
33
+ function normalizeAbortReason(reason) {
34
+ if (reason === undefined) {
35
+ if (typeof document === 'undefined') {
36
+ reason = new Error('This operation was aborted');
37
+ reason.name = 'AbortError';
38
+ } else {
39
+ try {
40
+ reason = new DOMException('signal is aborted without reason');
41
+ // The DOMException does not support setting the name property directly.
42
+ Object.defineProperty(reason, 'name', {
43
+ value: 'AbortError'
44
+ });
45
+ } catch (err) {
46
+ // IE 11 does not support calling the DOMException constructor, use a
47
+ // regular error object on it instead.
48
+ reason = new Error('This operation was aborted');
49
+ reason.name = 'AbortError';
50
+ }
51
+ }
52
+ }
53
+ return reason;
54
+ }
55
+ export class AbortSignal extends Emitter {
56
+ constructor() {
57
+ super();
58
+ // Some versions of babel does not transpile super() correctly for IE <= 10, if the parent
59
+ // constructor has failed to run, then "this.listeners" will still be undefined and then we call
60
+ // the parent constructor directly instead as a workaround. For general details, see babel bug:
61
+ // https://github.com/babel/babel/issues/3041
62
+ // This hack was added as a fix for the issue described here:
63
+ // https://github.com/Financial-Times/polyfill-library/pull/59#issuecomment-477558042
64
+ if (!this.listeners) {
65
+ Emitter.call(this);
66
+ }
67
+
68
+ // Compared to assignment, Object.defineProperty makes properties non-enumerable by default and
69
+ // we want Object.keys(new AbortController().signal) to be [] for compat with the native impl
70
+ Object.defineProperty(this, 'aborted', {
71
+ value: false,
72
+ writable: true,
73
+ configurable: true
74
+ });
75
+ Object.defineProperty(this, 'onabort', {
76
+ value: null,
77
+ writable: true,
78
+ configurable: true
79
+ });
80
+ Object.defineProperty(this, 'reason', {
81
+ value: undefined,
82
+ writable: true,
83
+ configurable: true
84
+ });
85
+ }
86
+ toString() {
87
+ return '[object AbortSignal]';
88
+ }
89
+ dispatchEvent(event) {
90
+ if (event.type === 'abort') {
91
+ this.aborted = true;
92
+ if (typeof this.onabort === 'function') {
93
+ this.onabort.call(this, event);
94
+ }
95
+ }
96
+ return super.dispatchEvent(event);
97
+ }
98
+
99
+ /**
100
+ * @see {@link https://developer.mozilla.org/zh-CN/docs/Web/API/AbortSignal/throwIfAborted}
101
+ */
102
+ throwIfAborted() {
103
+ const {
104
+ aborted,
105
+ reason = 'Aborted'
106
+ } = this;
107
+ if (!aborted) return;
108
+ throw reason;
109
+ }
110
+
111
+ /**
112
+ * @see {@link https://developer.mozilla.org/zh-CN/docs/Web/API/AbortSignal/timeout_static}
113
+ * @param {number} time The "active" time in milliseconds before the returned {@link AbortSignalObject} will abort.
114
+ * The value must be within range of 0 and {@link Number.MAX_SAFE_INTEGER}.
115
+ * @returns {AbortSignalObject} The signal will abort with its {@link AbortSignalObject.reason} property set to a `TimeoutError` {@link DOMException} on timeout,
116
+ * or an `AbortError` {@link DOMException} if the operation was user-triggered.
117
+ */
118
+ static timeout(time) {
119
+ const controller = new AbortController();
120
+ setTimeout(() => controller.abort(new DOMException("This signal is timeout in ".concat(time, "ms"), 'TimeoutError')), time);
121
+ return controller.signal;
122
+ }
123
+
124
+ /**
125
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/any_static}
126
+ * @param {Iterable<AbortSignalObject>} iterable An {@link Iterable} (such as an {@link Array}) of abort signals.
127
+ * @returns {AbortSignalObject} - **Already aborted**, if any of the abort signals given is already aborted.
128
+ * The returned {@link AbortSignalObject}'s reason will be already set to the `reason` of the first abort signal that was already aborted.
129
+ * - **Asynchronously aborted**, when any abort signal in `iterable` aborts.
130
+ * The `reason` will be set to the reason of the first abort signal that is aborted.
131
+ */
132
+ static any(iterable) {
133
+ const controller = new AbortController();
134
+ function clean() {
135
+ for (const signal of iterable) signal.removeEventListener('abort', abort);
136
+ }
137
+ /**
138
+ * @this AbortSignalObject
139
+ */
140
+ function abort() {
141
+ controller.abort(this.reason);
142
+ clean();
143
+ }
144
+ for (const signal of iterable) if (signal.aborted) {
145
+ controller.abort(signal.reason);
146
+ break;
147
+ } else signal.addEventListener('abort', abort);
148
+ return controller.signal;
149
+ }
150
+ }
151
+ export class AbortController {
152
+ constructor() {
153
+ // Compared to assignment, Object.defineProperty makes properties non-enumerable by default and
154
+ // we want Object.keys(new AbortController()) to be [] for compat with the native impl
155
+ Object.defineProperty(this, 'signal', {
156
+ value: new AbortSignal(),
157
+ writable: true,
158
+ configurable: true
159
+ });
160
+ }
161
+ abort(reason) {
162
+ const signalReason = normalizeAbortReason(reason);
163
+ const event = createAbortEvent(signalReason);
164
+ this.signal.reason = signalReason;
165
+ this.signal.dispatchEvent(event);
166
+ }
167
+ toString() {
168
+ return '[object AbortController]';
169
+ }
170
+ }
171
+ if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
172
+ // These are necessary to make sure that we get correct output for:
173
+ // Object.prototype.toString.call(new AbortController())
174
+ AbortController.prototype[Symbol.toStringTag] = 'AbortController';
175
+ AbortSignal.prototype[Symbol.toStringTag] = 'AbortSignal';
176
+ }
177
+ export default AbortController;