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

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 (104) hide show
  1. package/dist/Manager-6BwbaI_H.d.ts +19 -0
  2. package/dist/StateMachine-7c1gcu94.d.ts +2 -0
  3. package/dist/addEvent-1Mi5CEiq.esm.js +16 -0
  4. package/dist/chunk-C_Yo44FK.esm.js +49 -0
  5. package/dist/email.d.ts +264 -0
  6. package/dist/email.esm.js +479 -0
  7. package/dist/endpoints-D_pUMaqA.esm.js +1701 -0
  8. package/dist/flow.d.ts +578 -0
  9. package/dist/flow.esm.js +628 -0
  10. package/dist/index.d.ts +226 -0
  11. package/dist/index.esm.js +155 -0
  12. package/dist/lib-CyIAFRfr.esm.js +12499 -0
  13. package/dist/permissionServices-CVR0Pq38.esm.js +72 -0
  14. package/dist/phone.d.ts +292 -0
  15. package/dist/phone.esm.js +550 -0
  16. package/dist/selfie.d.ts +758 -0
  17. package/dist/selfie.esm.js +978 -0
  18. package/dist/types-tq1ypYSL.d.ts +5 -0
  19. package/dist/warmup-Dr7OcFND.d.ts +55 -0
  20. package/dist/xstate.esm-B_rda9yU.esm.js +3261 -0
  21. package/package.json +14 -11
  22. package/src/camera/cameraActor.ts +0 -21
  23. package/src/camera/cameraService.test.ts +0 -437
  24. package/src/camera/cameraService.ts +0 -165
  25. package/src/camera/cameraServices.test.ts +0 -66
  26. package/src/camera/cameraServices.ts +0 -26
  27. package/src/camera/cameraStateMachine.test.ts +0 -602
  28. package/src/camera/cameraStateMachine.ts +0 -264
  29. package/src/camera/index.ts +0 -5
  30. package/src/camera/types.ts +0 -17
  31. package/src/device/getBrowser.ts +0 -31
  32. package/src/device/getDeviceClass.ts +0 -29
  33. package/src/device/index.ts +0 -2
  34. package/src/email/__mocks__/emailMocks.ts +0 -59
  35. package/src/email/emailActor.ts +0 -15
  36. package/src/email/emailManager.test.ts +0 -573
  37. package/src/email/emailManager.ts +0 -427
  38. package/src/email/emailServices.ts +0 -66
  39. package/src/email/emailStateMachine.test.ts +0 -741
  40. package/src/email/emailStateMachine.ts +0 -367
  41. package/src/email/index.ts +0 -39
  42. package/src/email/types.ts +0 -60
  43. package/src/events/addEvent.ts +0 -20
  44. package/src/events/types.ts +0 -7
  45. package/src/flow/__mocks__/flowMocks.ts +0 -84
  46. package/src/flow/flowActor.ts +0 -13
  47. package/src/flow/flowAnalyzer.test.ts +0 -266
  48. package/src/flow/flowAnalyzer.ts +0 -37
  49. package/src/flow/flowCompletionService.ts +0 -21
  50. package/src/flow/flowManager.test.ts +0 -560
  51. package/src/flow/flowManager.ts +0 -235
  52. package/src/flow/flowServices.test.ts +0 -109
  53. package/src/flow/flowServices.ts +0 -13
  54. package/src/flow/flowStateMachine.test.ts +0 -334
  55. package/src/flow/flowStateMachine.ts +0 -182
  56. package/src/flow/index.ts +0 -21
  57. package/src/flow/moduleLoader.test.ts +0 -136
  58. package/src/flow/moduleLoader.ts +0 -73
  59. package/src/flow/orchestratedFlowManager.test.ts +0 -240
  60. package/src/flow/orchestratedFlowManager.ts +0 -231
  61. package/src/flow/orchestratedFlowStateMachine.test.ts +0 -199
  62. package/src/flow/orchestratedFlowStateMachine.ts +0 -325
  63. package/src/flow/types.ts +0 -434
  64. package/src/http/__mocks__/api.ts +0 -88
  65. package/src/http/api.test.ts +0 -231
  66. package/src/http/api.ts +0 -90
  67. package/src/http/endpoints.ts +0 -17
  68. package/src/index.ts +0 -33
  69. package/src/permissions/index.ts +0 -2
  70. package/src/permissions/permissionServices.ts +0 -31
  71. package/src/permissions/types.ts +0 -3
  72. package/src/phone/__mocks__/phoneMocks.ts +0 -71
  73. package/src/phone/index.ts +0 -39
  74. package/src/phone/phoneActor.ts +0 -15
  75. package/src/phone/phoneManager.test.ts +0 -393
  76. package/src/phone/phoneManager.ts +0 -458
  77. package/src/phone/phoneServices.ts +0 -98
  78. package/src/phone/phoneStateMachine.test.ts +0 -918
  79. package/src/phone/phoneStateMachine.ts +0 -422
  80. package/src/phone/types.ts +0 -83
  81. package/src/recordings/recordingsRepository.test.ts +0 -87
  82. package/src/recordings/recordingsRepository.ts +0 -48
  83. package/src/recordings/streamingEvents.ts +0 -10
  84. package/src/selfie/__mocks__/selfieMocks.ts +0 -26
  85. package/src/selfie/index.ts +0 -14
  86. package/src/selfie/selfieActor.ts +0 -17
  87. package/src/selfie/selfieErrorUtils.test.ts +0 -116
  88. package/src/selfie/selfieErrorUtils.ts +0 -66
  89. package/src/selfie/selfieManager.test.ts +0 -297
  90. package/src/selfie/selfieManager.ts +0 -301
  91. package/src/selfie/selfieServices.ts +0 -362
  92. package/src/selfie/selfieStateMachine.test.ts +0 -283
  93. package/src/selfie/selfieStateMachine.ts +0 -804
  94. package/src/selfie/selfieUploadService.test.ts +0 -90
  95. package/src/selfie/selfieUploadService.ts +0 -81
  96. package/src/selfie/types.ts +0 -103
  97. package/src/session/index.ts +0 -5
  98. package/src/session/sessionService.ts +0 -78
  99. package/src/setup.test.ts +0 -61
  100. package/src/setup.ts +0 -171
  101. package/tsconfig.json +0 -13
  102. package/tsdown.config.ts +0 -22
  103. package/vitest.config.ts +0 -37
  104. 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
- });