@incodetech/core 2.0.0-alpha.1 → 2.0.0-alpha.10

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 (106) hide show
  1. package/dist/Manager-BGfxEmyv.d.ts +19 -0
  2. package/dist/OpenViduLogger-BdPfiZO6.esm.js +3 -0
  3. package/dist/OpenViduLogger-CQyDxBvM.esm.js +803 -0
  4. package/dist/StateMachine-DRE1oH2B.d.ts +2 -0
  5. package/dist/addEvent-W0ORK0jT.esm.js +16 -0
  6. package/dist/chunk-C_Yo44FK.esm.js +49 -0
  7. package/dist/email.d.ts +264 -0
  8. package/dist/email.esm.js +479 -0
  9. package/dist/endpoints-BSTFaHYo.esm.js +1706 -0
  10. package/dist/flow.d.ts +578 -0
  11. package/dist/flow.esm.js +628 -0
  12. package/dist/index.d.ts +226 -0
  13. package/dist/index.esm.js +155 -0
  14. package/dist/lib-Bu9XGMBW.esm.js +11700 -0
  15. package/dist/permissionServices-I6vX6DBy.esm.js +72 -0
  16. package/dist/phone.d.ts +292 -0
  17. package/dist/phone.esm.js +550 -0
  18. package/dist/selfie.d.ts +759 -0
  19. package/dist/selfie.esm.js +995 -0
  20. package/dist/types-iZi2rawo.d.ts +5 -0
  21. package/dist/warmup-CEJTfxQr.d.ts +55 -0
  22. package/dist/xstate.esm-B_rda9yU.esm.js +3261 -0
  23. package/package.json +14 -11
  24. package/src/camera/cameraActor.ts +0 -21
  25. package/src/camera/cameraService.test.ts +0 -437
  26. package/src/camera/cameraService.ts +0 -165
  27. package/src/camera/cameraServices.test.ts +0 -66
  28. package/src/camera/cameraServices.ts +0 -26
  29. package/src/camera/cameraStateMachine.test.ts +0 -602
  30. package/src/camera/cameraStateMachine.ts +0 -264
  31. package/src/camera/index.ts +0 -5
  32. package/src/camera/types.ts +0 -17
  33. package/src/device/getBrowser.ts +0 -31
  34. package/src/device/getDeviceClass.ts +0 -29
  35. package/src/device/index.ts +0 -2
  36. package/src/email/__mocks__/emailMocks.ts +0 -59
  37. package/src/email/emailActor.ts +0 -15
  38. package/src/email/emailManager.test.ts +0 -573
  39. package/src/email/emailManager.ts +0 -427
  40. package/src/email/emailServices.ts +0 -66
  41. package/src/email/emailStateMachine.test.ts +0 -741
  42. package/src/email/emailStateMachine.ts +0 -367
  43. package/src/email/index.ts +0 -39
  44. package/src/email/types.ts +0 -60
  45. package/src/events/addEvent.ts +0 -20
  46. package/src/events/types.ts +0 -7
  47. package/src/flow/__mocks__/flowMocks.ts +0 -84
  48. package/src/flow/flowActor.ts +0 -13
  49. package/src/flow/flowAnalyzer.test.ts +0 -266
  50. package/src/flow/flowAnalyzer.ts +0 -37
  51. package/src/flow/flowCompletionService.ts +0 -21
  52. package/src/flow/flowManager.test.ts +0 -560
  53. package/src/flow/flowManager.ts +0 -235
  54. package/src/flow/flowServices.test.ts +0 -109
  55. package/src/flow/flowServices.ts +0 -13
  56. package/src/flow/flowStateMachine.test.ts +0 -334
  57. package/src/flow/flowStateMachine.ts +0 -182
  58. package/src/flow/index.ts +0 -21
  59. package/src/flow/moduleLoader.test.ts +0 -136
  60. package/src/flow/moduleLoader.ts +0 -73
  61. package/src/flow/orchestratedFlowManager.test.ts +0 -240
  62. package/src/flow/orchestratedFlowManager.ts +0 -231
  63. package/src/flow/orchestratedFlowStateMachine.test.ts +0 -199
  64. package/src/flow/orchestratedFlowStateMachine.ts +0 -325
  65. package/src/flow/types.ts +0 -434
  66. package/src/http/__mocks__/api.ts +0 -88
  67. package/src/http/api.test.ts +0 -231
  68. package/src/http/api.ts +0 -90
  69. package/src/http/endpoints.ts +0 -17
  70. package/src/index.ts +0 -33
  71. package/src/permissions/index.ts +0 -2
  72. package/src/permissions/permissionServices.ts +0 -31
  73. package/src/permissions/types.ts +0 -3
  74. package/src/phone/__mocks__/phoneMocks.ts +0 -71
  75. package/src/phone/index.ts +0 -39
  76. package/src/phone/phoneActor.ts +0 -15
  77. package/src/phone/phoneManager.test.ts +0 -393
  78. package/src/phone/phoneManager.ts +0 -458
  79. package/src/phone/phoneServices.ts +0 -98
  80. package/src/phone/phoneStateMachine.test.ts +0 -918
  81. package/src/phone/phoneStateMachine.ts +0 -422
  82. package/src/phone/types.ts +0 -83
  83. package/src/recordings/recordingsRepository.test.ts +0 -87
  84. package/src/recordings/recordingsRepository.ts +0 -48
  85. package/src/recordings/streamingEvents.ts +0 -10
  86. package/src/selfie/__mocks__/selfieMocks.ts +0 -26
  87. package/src/selfie/index.ts +0 -14
  88. package/src/selfie/selfieActor.ts +0 -17
  89. package/src/selfie/selfieErrorUtils.test.ts +0 -116
  90. package/src/selfie/selfieErrorUtils.ts +0 -66
  91. package/src/selfie/selfieManager.test.ts +0 -297
  92. package/src/selfie/selfieManager.ts +0 -301
  93. package/src/selfie/selfieServices.ts +0 -362
  94. package/src/selfie/selfieStateMachine.test.ts +0 -283
  95. package/src/selfie/selfieStateMachine.ts +0 -804
  96. package/src/selfie/selfieUploadService.test.ts +0 -90
  97. package/src/selfie/selfieUploadService.ts +0 -81
  98. package/src/selfie/types.ts +0 -103
  99. package/src/session/index.ts +0 -5
  100. package/src/session/sessionService.ts +0 -78
  101. package/src/setup.test.ts +0 -61
  102. package/src/setup.ts +0 -171
  103. package/tsconfig.json +0 -13
  104. package/tsdown.config.ts +0 -22
  105. package/vitest.config.ts +0 -37
  106. package/vitest.setup.ts +0 -135
@@ -1,66 +0,0 @@
1
- import { MockCameraProvider } from '@incodetech/infra';
2
- import { describe, expect, it, vi } from 'vitest';
3
- import { createCameraServices } from './cameraServices';
4
-
5
- describe('createCameraServices', () => {
6
- describe('checkPermission', () => {
7
- it('should call camera capability checkPermission', async () => {
8
- const camera = new MockCameraProvider();
9
- const services = createCameraServices(camera);
10
-
11
- const result = await services.checkPermission();
12
-
13
- expect(['granted', 'denied', 'prompt']).toContain(result);
14
- });
15
- });
16
-
17
- describe('requestStream', () => {
18
- it('should call camera capability requestStream with config', async () => {
19
- const camera = new MockCameraProvider();
20
- const mockStream = new MediaStream();
21
- camera.setMockStream(mockStream);
22
- const requestSpy = vi.spyOn(camera, 'requestStream');
23
-
24
- const services = createCameraServices(camera);
25
-
26
- const stream = await services.requestStream({
27
- facingMode: 'environment',
28
- deviceId: 'device1',
29
- });
30
-
31
- expect(requestSpy).toHaveBeenCalledWith({
32
- facingMode: 'environment',
33
- deviceId: 'device1',
34
- });
35
- expect(stream).toBe(mockStream);
36
- });
37
- });
38
-
39
- describe('stopStream', () => {
40
- it('should call camera capability stopStream', () => {
41
- const camera = new MockCameraProvider();
42
- const mockStream = new MediaStream();
43
- const stopSpy = vi.spyOn(camera, 'stopStream');
44
-
45
- const services = createCameraServices(camera);
46
-
47
- services.stopStream(mockStream);
48
-
49
- expect(stopSpy).toHaveBeenCalledWith(mockStream);
50
- });
51
- });
52
-
53
- describe('captureFrame', () => {
54
- it('should call camera capability captureFrame', () => {
55
- const camera = new MockCameraProvider();
56
- const video = document.createElement('video');
57
- const captureSpy = vi.spyOn(camera, 'captureFrame');
58
-
59
- const services = createCameraServices(camera);
60
-
61
- services.captureFrame(video);
62
-
63
- expect(captureSpy).toHaveBeenCalledWith(video);
64
- });
65
- });
66
- });
@@ -1,26 +0,0 @@
1
- import type { ICameraCapability } from '@incodetech/infra';
2
- import { queryCameraPermission } from '@incodetech/infra';
3
- import type { CameraConfig } from './types';
4
-
5
- export function createCameraServices(camera: ICameraCapability) {
6
- return {
7
- async checkPermission() {
8
- return queryCameraPermission();
9
- },
10
-
11
- async requestStream(config: CameraConfig) {
12
- return camera.requestStream({
13
- facingMode: config.facingMode,
14
- deviceId: config.deviceId,
15
- });
16
- },
17
-
18
- stopStream(stream: MediaStream) {
19
- camera.stopStream(stream);
20
- },
21
-
22
- captureFrame(video: HTMLVideoElement) {
23
- return camera.captureFrame(video);
24
- },
25
- };
26
- }
@@ -1,602 +0,0 @@
1
- import { createActor, MockCameraProvider } from '@incodetech/infra';
2
- import { beforeEach, describe, expect, it, vi } from 'vitest';
3
- import { cameraMachine } from './cameraStateMachine';
4
-
5
- const createTestActor = () => {
6
- const camera = new MockCameraProvider();
7
- return createActor(cameraMachine, {
8
- input: { camera },
9
- }).start();
10
- };
11
-
12
- // Helper to mock permission query result
13
- const mockPermissionQuery = (state: 'granted' | 'denied' | 'prompt') => {
14
- const setPermissionState = (
15
- globalThis as {
16
- __setPermissionState?: (state: 'granted' | 'denied' | 'prompt') => void;
17
- }
18
- ).__setPermissionState;
19
- if (setPermissionState) {
20
- setPermissionState(state);
21
- }
22
- };
23
-
24
- describe('CameraStateMachine', () => {
25
- describe('Initial state', () => {
26
- it('should start in idle state', () => {
27
- const actor = createTestActor();
28
-
29
- expect(actor.getSnapshot().value).toBe('idle');
30
- actor.stop();
31
- });
32
-
33
- it('should have initial context with camera capability', () => {
34
- const actor = createTestActor();
35
-
36
- const { context } = actor.getSnapshot();
37
- expect(context.camera).toBeDefined();
38
- expect(context.stream).toBeUndefined();
39
- expect(context.permissionResult).toBeUndefined();
40
- expect(context.error).toBeUndefined();
41
- expect(context.errorType).toBeUndefined();
42
-
43
- actor.stop();
44
- });
45
- });
46
-
47
- describe('START event', () => {
48
- it('should transition from idle to checkingPermission', () => {
49
- const actor = createTestActor();
50
-
51
- actor.send({ type: 'START' });
52
-
53
- expect(actor.getSnapshot().value).toBe('checkingPermission');
54
- actor.stop();
55
- });
56
- });
57
-
58
- describe('Permission checking flow', () => {
59
- it('should transition to routing after permission check', async () => {
60
- const actor = createTestActor();
61
-
62
- actor.send({ type: 'START' });
63
-
64
- await vi.waitFor(
65
- () => {
66
- const snapshot = actor.getSnapshot();
67
- expect(['routing', 'requesting', 'streaming']).toContain(
68
- snapshot.value,
69
- );
70
- },
71
- { timeout: 2000 },
72
- );
73
-
74
- actor.stop();
75
- });
76
-
77
- it('should set permission result in context', async () => {
78
- const actor = createTestActor();
79
-
80
- actor.send({ type: 'START' });
81
-
82
- await vi.waitFor(
83
- () => {
84
- const snapshot = actor.getSnapshot();
85
- if (
86
- snapshot.value === 'routing' ||
87
- snapshot.value === 'requesting' ||
88
- snapshot.value === 'streaming'
89
- ) {
90
- expect(snapshot.context.permissionResult).toBeDefined();
91
- }
92
- },
93
- { timeout: 2000 },
94
- );
95
-
96
- actor.stop();
97
- });
98
- });
99
-
100
- describe('Stream request flow', () => {
101
- it('should transition to streaming on successful stream', async () => {
102
- const camera = new MockCameraProvider();
103
- const mockStream = new MediaStream();
104
- camera.setMockStream(mockStream);
105
- const actor = createActor(cameraMachine, {
106
- input: { camera },
107
- }).start();
108
-
109
- actor.send({ type: 'START' });
110
-
111
- await vi.waitFor(
112
- () => {
113
- const value = actor.getSnapshot().value;
114
- if (value !== 'streaming' && value !== 'error') {
115
- throw new Error(`Still in state: ${value}`);
116
- }
117
- },
118
- { timeout: 5000, interval: 50 },
119
- );
120
-
121
- const snapshot = actor.getSnapshot();
122
- expect(snapshot.value).toBe('streaming');
123
- expect(snapshot.context.stream).toBe(mockStream);
124
-
125
- actor.stop();
126
- });
127
-
128
- it('should transition to error on stream failure', async () => {
129
- const camera = new MockCameraProvider();
130
- camera.setShouldReject(true);
131
- const actor = createActor(cameraMachine, {
132
- input: { camera },
133
- }).start();
134
-
135
- actor.send({ type: 'START' });
136
-
137
- await vi.waitFor(
138
- () => {
139
- const value = actor.getSnapshot().value;
140
- if (value !== 'error' && value !== 'streaming') {
141
- throw new Error(`Still in state: ${value}`);
142
- }
143
- },
144
- { timeout: 5000, interval: 50 },
145
- );
146
-
147
- const snapshot = actor.getSnapshot();
148
- expect(snapshot.value).toBe('error');
149
- expect(snapshot.context.error).toBeDefined();
150
- expect(snapshot.context.errorType).toBeDefined();
151
-
152
- actor.stop();
153
- });
154
- });
155
-
156
- describe('STOP event', () => {
157
- it('should transition from checkingPermission to idle', () => {
158
- const actor = createTestActor();
159
-
160
- actor.send({ type: 'START' });
161
- actor.send({ type: 'STOP' });
162
-
163
- expect(actor.getSnapshot().value).toBe('idle');
164
- actor.stop();
165
- });
166
-
167
- it('should transition from requesting to idle', () => {
168
- const actor = createTestActor();
169
-
170
- actor.send({ type: 'START' });
171
- actor.send({ type: 'STOP' });
172
-
173
- expect(actor.getSnapshot().value).toBe('idle');
174
- actor.stop();
175
- });
176
- });
177
-
178
- describe('Routing state', () => {
179
- beforeEach(() => {
180
- // Reset permission mock to default
181
- mockPermissionQuery('prompt');
182
- });
183
-
184
- it('should route to requesting when permission is granted', async () => {
185
- // Set mock BEFORE creating actor
186
- mockPermissionQuery('granted');
187
- const camera = new MockCameraProvider();
188
- const mockStream = new MediaStream();
189
- camera.setMockStream(mockStream);
190
- const actor = createActor(cameraMachine, {
191
- input: { camera },
192
- }).start();
193
-
194
- actor.send({ type: 'START' });
195
-
196
- // Wait for streaming state (granted -> routing -> requesting -> streaming)
197
- await vi.waitFor(
198
- () => {
199
- const value = actor.getSnapshot().value;
200
- if (value !== 'streaming' && value !== 'error') {
201
- throw new Error(`Still in state: ${value}`);
202
- }
203
- },
204
- { timeout: 5000, interval: 50 },
205
- );
206
-
207
- expect(actor.getSnapshot().value).toBe('streaming');
208
- expect(actor.getSnapshot().context.permissionResult).toBe('granted');
209
-
210
- actor.stop();
211
- });
212
-
213
- it('should route to error when permission is denied', async () => {
214
- // Set mock BEFORE creating actor
215
- mockPermissionQuery('denied');
216
- const camera = new MockCameraProvider();
217
- const actor = createActor(cameraMachine, {
218
- input: { camera },
219
- }).start();
220
-
221
- actor.send({ type: 'START' });
222
-
223
- // Wait for error state (denied -> routing -> error)
224
- await vi.waitFor(
225
- () => {
226
- const value = actor.getSnapshot().value;
227
- if (value !== 'error' && value !== 'streaming') {
228
- throw new Error(`Still in state: ${value}`);
229
- }
230
- },
231
- { timeout: 5000, interval: 50 },
232
- );
233
-
234
- const snapshot = actor.getSnapshot();
235
- expect(snapshot.value).toBe('error');
236
- expect(snapshot.context.permissionResult).toBe('denied');
237
- expect(snapshot.context.errorType).toBe('permission_denied');
238
-
239
- actor.stop();
240
- });
241
-
242
- it('should route to requesting when permission is prompt', async () => {
243
- // Set mock BEFORE creating actor
244
- mockPermissionQuery('prompt');
245
- const camera = new MockCameraProvider();
246
- const mockStream = new MediaStream();
247
- camera.setMockStream(mockStream);
248
- const actor = createActor(cameraMachine, {
249
- input: { camera },
250
- }).start();
251
-
252
- actor.send({ type: 'START' });
253
-
254
- // Wait for streaming (prompt -> routing -> requesting -> streaming)
255
- await vi.waitFor(
256
- () => {
257
- const value = actor.getSnapshot().value;
258
- if (value !== 'streaming' && value !== 'error') {
259
- throw new Error(`Still in state: ${value}`);
260
- }
261
- },
262
- { timeout: 5000, interval: 50 },
263
- );
264
-
265
- expect(actor.getSnapshot().value).toBe('streaming');
266
- expect(actor.getSnapshot().context.permissionResult).toBe('prompt');
267
-
268
- actor.stop();
269
- });
270
- });
271
-
272
- describe('Streaming state', () => {
273
- it('should transition to idle when STOP is sent from streaming', async () => {
274
- const camera = new MockCameraProvider();
275
- const mockStream = new MediaStream();
276
- camera.setMockStream(mockStream);
277
- const stopSpy = vi.spyOn(camera, 'stopStream');
278
- const actor = createActor(cameraMachine, {
279
- input: { camera },
280
- }).start();
281
-
282
- actor.send({ type: 'START' });
283
-
284
- // Wait for streaming state
285
- await vi.waitFor(
286
- () => {
287
- const snapshot = actor.getSnapshot();
288
- if (snapshot.value !== 'streaming' || !snapshot.context.stream) {
289
- throw new Error(`Not streaming yet: ${snapshot.value}`);
290
- }
291
- },
292
- { timeout: 5000, interval: 50 },
293
- );
294
-
295
- // Send STOP
296
- actor.send({ type: 'STOP' });
297
-
298
- // STOP should transition immediately (synchronous)
299
- const stopSnapshot = actor.getSnapshot();
300
- expect(stopSnapshot.value).toBe('idle');
301
-
302
- // stopStream should be called because stream was in context
303
- expect(stopSpy).toHaveBeenCalled();
304
-
305
- actor.stop();
306
- });
307
- });
308
-
309
- describe('Error state', () => {
310
- it('should transition to idle when RESET is sent from error', () => {
311
- const actor = createTestActor();
312
-
313
- // Manually transition to error state
314
- actor.send({ type: 'START' });
315
- actor.send({
316
- type: 'STREAM_ERROR',
317
- error: 'Test error',
318
- errorType: 'unknown',
319
- });
320
-
321
- // Wait a tick for state update
322
- const errorSnapshot = actor.getSnapshot();
323
- if (errorSnapshot.value === 'error') {
324
- actor.send({ type: 'RESET' });
325
- expect(actor.getSnapshot().value).toBe('idle');
326
- expect(actor.getSnapshot().context.error).toBeUndefined();
327
- expect(actor.getSnapshot().context.errorType).toBeUndefined();
328
- }
329
-
330
- actor.stop();
331
- });
332
-
333
- it('should transition to idle when STOP is sent from error', () => {
334
- const actor = createTestActor();
335
-
336
- // Manually transition to error state
337
- actor.send({ type: 'START' });
338
- actor.send({
339
- type: 'STREAM_ERROR',
340
- error: 'Test error',
341
- errorType: 'unknown',
342
- });
343
-
344
- // Wait a tick for state update
345
- const errorSnapshot = actor.getSnapshot();
346
- if (errorSnapshot.value === 'error') {
347
- actor.send({ type: 'STOP' });
348
- expect(actor.getSnapshot().value).toBe('idle');
349
- }
350
-
351
- actor.stop();
352
- });
353
- });
354
-
355
- describe('Error handling', () => {
356
- it('should set error type for NotAllowedError', async () => {
357
- const camera = new MockCameraProvider();
358
- camera.setShouldReject(
359
- true,
360
- new DOMException('Permission denied', 'NotAllowedError'),
361
- );
362
- const actor = createActor(cameraMachine, {
363
- input: { camera },
364
- }).start();
365
-
366
- actor.send({ type: 'START' });
367
-
368
- await vi.waitFor(
369
- () => {
370
- if (actor.getSnapshot().value !== 'error') {
371
- throw new Error('Not in error state yet');
372
- }
373
- },
374
- { timeout: 5000, interval: 50 },
375
- );
376
-
377
- const errorSnapshot = actor.getSnapshot();
378
- expect(errorSnapshot.value).toBe('error');
379
- expect(errorSnapshot.context.errorType).toBe('permission_denied');
380
-
381
- actor.stop();
382
- });
383
-
384
- it('should set error type for NotFoundError', async () => {
385
- const camera = new MockCameraProvider();
386
- camera.setShouldReject(
387
- true,
388
- new DOMException('Camera not found', 'NotFoundError'),
389
- );
390
- const actor = createActor(cameraMachine, {
391
- input: { camera },
392
- }).start();
393
-
394
- actor.send({ type: 'START' });
395
-
396
- await vi.waitFor(
397
- () => {
398
- if (actor.getSnapshot().value !== 'error') {
399
- throw new Error('Not in error state yet');
400
- }
401
- },
402
- { timeout: 5000, interval: 50 },
403
- );
404
-
405
- const errorSnapshot = actor.getSnapshot();
406
- expect(errorSnapshot.value).toBe('error');
407
- expect(errorSnapshot.context.errorType).toBe('not_found');
408
-
409
- actor.stop();
410
- });
411
-
412
- it('should set error type for NotReadableError', async () => {
413
- const camera = new MockCameraProvider();
414
- camera.setShouldReject(
415
- true,
416
- new DOMException('Camera in use', 'NotReadableError'),
417
- );
418
- const actor = createActor(cameraMachine, {
419
- input: { camera },
420
- }).start();
421
-
422
- actor.send({ type: 'START' });
423
-
424
- await vi.waitFor(
425
- () => {
426
- if (actor.getSnapshot().value !== 'error') {
427
- throw new Error('Not in error state yet');
428
- }
429
- },
430
- { timeout: 5000, interval: 50 },
431
- );
432
-
433
- const errorSnapshot = actor.getSnapshot();
434
- expect(errorSnapshot.value).toBe('error');
435
- expect(errorSnapshot.context.errorType).toBe('not_readable');
436
-
437
- actor.stop();
438
- });
439
-
440
- it('should set error type for OverconstrainedError', async () => {
441
- const camera = new MockCameraProvider();
442
- camera.setShouldReject(
443
- true,
444
- new DOMException('Constraints not supported', 'OverconstrainedError'),
445
- );
446
- const actor = createActor(cameraMachine, {
447
- input: { camera },
448
- }).start();
449
-
450
- actor.send({ type: 'START' });
451
-
452
- await vi.waitFor(
453
- () => {
454
- if (actor.getSnapshot().value !== 'error') {
455
- throw new Error('Not in error state yet');
456
- }
457
- },
458
- { timeout: 5000, interval: 50 },
459
- );
460
-
461
- const errorSnapshot = actor.getSnapshot();
462
- expect(errorSnapshot.value).toBe('error');
463
- expect(errorSnapshot.context.errorType).toBe('overconstrained');
464
-
465
- actor.stop();
466
- });
467
-
468
- it('should set error type for SecurityError', async () => {
469
- const camera = new MockCameraProvider();
470
- camera.setShouldReject(
471
- true,
472
- new DOMException('Security error', 'SecurityError'),
473
- );
474
- const actor = createActor(cameraMachine, {
475
- input: { camera },
476
- }).start();
477
-
478
- actor.send({ type: 'START' });
479
-
480
- await vi.waitFor(
481
- () => {
482
- if (actor.getSnapshot().value !== 'error') {
483
- throw new Error('Not in error state yet');
484
- }
485
- },
486
- { timeout: 5000, interval: 50 },
487
- );
488
-
489
- const errorSnapshot = actor.getSnapshot();
490
- expect(errorSnapshot.value).toBe('error');
491
- expect(errorSnapshot.context.errorType).toBe('security');
492
-
493
- actor.stop();
494
- });
495
-
496
- it('should set error type for AbortError', async () => {
497
- const camera = new MockCameraProvider();
498
- camera.setShouldReject(
499
- true,
500
- new DOMException('Request aborted', 'AbortError'),
501
- );
502
- const actor = createActor(cameraMachine, {
503
- input: { camera },
504
- }).start();
505
-
506
- actor.send({ type: 'START' });
507
-
508
- await vi.waitFor(
509
- () => {
510
- if (actor.getSnapshot().value !== 'error') {
511
- throw new Error('Not in error state yet');
512
- }
513
- },
514
- { timeout: 5000, interval: 50 },
515
- );
516
-
517
- const errorSnapshot = actor.getSnapshot();
518
- expect(errorSnapshot.value).toBe('error');
519
- expect(errorSnapshot.context.errorType).toBe('abort');
520
-
521
- actor.stop();
522
- });
523
-
524
- it('should set error type to unknown for unrecognized errors', async () => {
525
- const camera = new MockCameraProvider();
526
- camera.setShouldReject(true, new Error('Unknown error'));
527
- const actor = createActor(cameraMachine, {
528
- input: { camera },
529
- }).start();
530
-
531
- actor.send({ type: 'START' });
532
-
533
- await vi.waitFor(
534
- () => {
535
- if (actor.getSnapshot().value !== 'error') {
536
- throw new Error('Not in error state yet');
537
- }
538
- },
539
- { timeout: 5000, interval: 50 },
540
- );
541
-
542
- const errorSnapshot = actor.getSnapshot();
543
- expect(errorSnapshot.value).toBe('error');
544
- expect(errorSnapshot.context.errorType).toBe('unknown');
545
- expect(errorSnapshot.context.error).toBe('Unknown error');
546
-
547
- actor.stop();
548
- });
549
-
550
- it('should handle error without message', async () => {
551
- const camera = new MockCameraProvider();
552
- const errorWithoutMessage = new Error();
553
- errorWithoutMessage.message = '';
554
- camera.setShouldReject(true, errorWithoutMessage);
555
- const actor = createActor(cameraMachine, {
556
- input: { camera },
557
- }).start();
558
-
559
- actor.send({ type: 'START' });
560
-
561
- await vi.waitFor(
562
- () => {
563
- if (actor.getSnapshot().value !== 'error') {
564
- throw new Error('Not in error state yet');
565
- }
566
- },
567
- { timeout: 5000, interval: 50 },
568
- );
569
-
570
- const errorSnapshot = actor.getSnapshot();
571
- expect(errorSnapshot.value).toBe('error');
572
- expect(errorSnapshot.context.error).toBeDefined();
573
- expect(errorSnapshot.context.errorType).toBe('unknown');
574
-
575
- actor.stop();
576
- });
577
- });
578
-
579
- describe('Permission check error handling', () => {
580
- it('should handle permission check failure gracefully', async () => {
581
- const actor = createTestActor();
582
-
583
- actor.send({ type: 'START' });
584
-
585
- // Wait for permission check to complete (even if it fails)
586
- await vi.waitFor(
587
- () => {
588
- const snapshot = actor.getSnapshot();
589
- // Should transition to routing even on error (with prompt as default)
590
- return (
591
- snapshot.value === 'routing' ||
592
- snapshot.value === 'requesting' ||
593
- snapshot.value === 'streaming'
594
- );
595
- },
596
- { timeout: 2000 },
597
- );
598
-
599
- actor.stop();
600
- });
601
- });
602
- });