mobilewright 0.0.26 → 0.0.28
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/README.md +1 -1
- package/dist/cli.js +55 -5
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +3 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +18 -3
- package/dist/config.js.map +1 -1
- package/dist/config.test.d.ts +2 -0
- package/dist/config.test.d.ts.map +1 -0
- package/dist/config.test.js +22 -0
- package/dist/config.test.js.map +1 -0
- package/dist/device-pool/adapters/http-client.d.ts +16 -0
- package/dist/device-pool/adapters/http-client.d.ts.map +1 -0
- package/dist/device-pool/adapters/http-client.js +91 -0
- package/dist/device-pool/adapters/http-client.js.map +1 -0
- package/dist/device-pool/adapters/http-client.test.d.ts +2 -0
- package/dist/device-pool/adapters/http-client.test.d.ts.map +1 -0
- package/dist/device-pool/adapters/http-client.test.js +72 -0
- package/dist/device-pool/adapters/http-client.test.js.map +1 -0
- package/dist/device-pool/adapters/http-server.d.ts +19 -0
- package/dist/device-pool/adapters/http-server.d.ts.map +1 -0
- package/dist/device-pool/adapters/http-server.js +126 -0
- package/dist/device-pool/adapters/http-server.js.map +1 -0
- package/dist/device-pool/adapters/http-server.test.d.ts +2 -0
- package/dist/device-pool/adapters/http-server.test.d.ts.map +1 -0
- package/dist/device-pool/adapters/http-server.test.js +203 -0
- package/dist/device-pool/adapters/http-server.test.js.map +1 -0
- package/dist/device-pool/adapters/mobile-use-allocator.d.ts +13 -0
- package/dist/device-pool/adapters/mobile-use-allocator.d.ts.map +1 -0
- package/dist/device-pool/adapters/mobile-use-allocator.js +31 -0
- package/dist/device-pool/adapters/mobile-use-allocator.js.map +1 -0
- package/dist/device-pool/adapters/mobilecli-allocator.d.ts +19 -0
- package/dist/device-pool/adapters/mobilecli-allocator.d.ts.map +1 -0
- package/dist/device-pool/adapters/mobilecli-allocator.js +26 -0
- package/dist/device-pool/adapters/mobilecli-allocator.js.map +1 -0
- package/dist/device-pool/adapters/mobilecli-allocator.test.d.ts +2 -0
- package/dist/device-pool/adapters/mobilecli-allocator.test.d.ts.map +1 -0
- package/dist/device-pool/adapters/mobilecli-allocator.test.js +61 -0
- package/dist/device-pool/adapters/mobilecli-allocator.test.js.map +1 -0
- package/dist/device-pool/allocator-factory.d.ts +10 -0
- package/dist/device-pool/allocator-factory.d.ts.map +1 -0
- package/dist/device-pool/allocator-factory.js +25 -0
- package/dist/device-pool/allocator-factory.js.map +1 -0
- package/dist/device-pool/application/device-pool.d.ts +29 -0
- package/dist/device-pool/application/device-pool.d.ts.map +1 -0
- package/dist/device-pool/application/device-pool.js +174 -0
- package/dist/device-pool/application/device-pool.js.map +1 -0
- package/dist/device-pool/application/device-pool.test.d.ts +2 -0
- package/dist/device-pool/application/device-pool.test.d.ts.map +1 -0
- package/dist/device-pool/application/device-pool.test.js +185 -0
- package/dist/device-pool/application/device-pool.test.js.map +1 -0
- package/dist/device-pool/application/ports.d.ts +44 -0
- package/dist/device-pool/application/ports.d.ts.map +1 -0
- package/dist/device-pool/application/ports.js +13 -0
- package/dist/device-pool/application/ports.js.map +1 -0
- package/dist/device-pool/client-factory.d.ts +8 -0
- package/dist/device-pool/client-factory.d.ts.map +1 -0
- package/dist/device-pool/client-factory.js +16 -0
- package/dist/device-pool/client-factory.js.map +1 -0
- package/dist/device-pool/domain/allocation.d.ts +21 -0
- package/dist/device-pool/domain/allocation.d.ts.map +1 -0
- package/dist/device-pool/domain/allocation.js +14 -0
- package/dist/device-pool/domain/allocation.js.map +1 -0
- package/dist/device-pool/domain/allocation.test.d.ts +2 -0
- package/dist/device-pool/domain/allocation.test.d.ts.map +1 -0
- package/dist/device-pool/domain/allocation.test.js +21 -0
- package/dist/device-pool/domain/allocation.test.js.map +1 -0
- package/dist/device-pool/domain/device-slot.d.ts +22 -0
- package/dist/device-pool/domain/device-slot.d.ts.map +1 -0
- package/dist/device-pool/domain/device-slot.js +53 -0
- package/dist/device-pool/domain/device-slot.js.map +1 -0
- package/dist/device-pool/domain/device-slot.test.d.ts +2 -0
- package/dist/device-pool/domain/device-slot.test.d.ts.map +1 -0
- package/dist/device-pool/domain/device-slot.test.js +53 -0
- package/dist/device-pool/domain/device-slot.test.js.map +1 -0
- package/dist/device-pool/setup.d.ts +7 -0
- package/dist/device-pool/setup.d.ts.map +1 -0
- package/dist/device-pool/setup.js +35 -0
- package/dist/device-pool/setup.js.map +1 -0
- package/dist/device-pool/teardown.d.ts +7 -0
- package/dist/device-pool/teardown.d.ts.map +1 -0
- package/dist/device-pool/teardown.js +9 -0
- package/dist/device-pool/teardown.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/launchers.d.ts +19 -1
- package/dist/launchers.d.ts.map +1 -1
- package/dist/launchers.js +53 -22
- package/dist/launchers.js.map +1 -1
- package/package.json +6 -6
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { DeviceSlot } from '../domain/device-slot.js';
|
|
2
|
+
import { Allocation } from '../domain/allocation.js';
|
|
3
|
+
import { NoDeviceAvailableError } from './ports.js';
|
|
4
|
+
export class DevicePool {
|
|
5
|
+
constructor(options) {
|
|
6
|
+
this.slots = [];
|
|
7
|
+
this.allocations = new Map();
|
|
8
|
+
this.waiters = [];
|
|
9
|
+
this.inFlightWaiters = new Set();
|
|
10
|
+
this.isShutdown = false;
|
|
11
|
+
this.allocator = options.allocator;
|
|
12
|
+
this.maxSlots = options.maxSlots;
|
|
13
|
+
this.allocationTimeoutMs = options.allocationTimeoutMs ?? 600_000;
|
|
14
|
+
}
|
|
15
|
+
allocate(criteria) {
|
|
16
|
+
if (this.isShutdown) {
|
|
17
|
+
return Promise.reject(new Error('device pool is shut down'));
|
|
18
|
+
}
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
this.waiters.push({ criteria, resolve, reject });
|
|
21
|
+
this.pump();
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
async shutdown() {
|
|
25
|
+
this.isShutdown = true;
|
|
26
|
+
const drained = this.waiters.splice(0);
|
|
27
|
+
for (const waiter of drained) {
|
|
28
|
+
waiter.reject(new Error('device pool shutdown'));
|
|
29
|
+
}
|
|
30
|
+
for (const waiter of this.inFlightWaiters) {
|
|
31
|
+
waiter.reject(new Error('device pool shutdown'));
|
|
32
|
+
}
|
|
33
|
+
this.inFlightWaiters.clear();
|
|
34
|
+
const releases = [];
|
|
35
|
+
for (const slot of this.slots) {
|
|
36
|
+
if (slot.state !== 'allocating' && slot.deviceId !== undefined) {
|
|
37
|
+
releases.push(this.allocator.release(slot.deviceId).catch(() => { }));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
await Promise.all(releases);
|
|
41
|
+
this.slots.length = 0;
|
|
42
|
+
this.allocations.clear();
|
|
43
|
+
}
|
|
44
|
+
async release(allocationId) {
|
|
45
|
+
const allocation = this.allocations.get(allocationId);
|
|
46
|
+
if (!allocation) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
this.allocations.delete(allocationId);
|
|
50
|
+
this.slots[allocation.slotIndex].release();
|
|
51
|
+
this.pump();
|
|
52
|
+
}
|
|
53
|
+
recordAppInstalled(allocationId, bundleId) {
|
|
54
|
+
const allocation = this.allocations.get(allocationId);
|
|
55
|
+
if (!allocation) {
|
|
56
|
+
throw new Error(`unknown allocationId: ${allocationId}`);
|
|
57
|
+
}
|
|
58
|
+
this.slots[allocation.slotIndex].recordAppInstalled(bundleId);
|
|
59
|
+
}
|
|
60
|
+
isAppInstalled(allocationId, bundleId) {
|
|
61
|
+
const allocation = this.allocations.get(allocationId);
|
|
62
|
+
if (!allocation) {
|
|
63
|
+
throw new Error(`unknown allocationId: ${allocationId}`);
|
|
64
|
+
}
|
|
65
|
+
return this.slots[allocation.slotIndex].isAppInstalled(bundleId);
|
|
66
|
+
}
|
|
67
|
+
pump() {
|
|
68
|
+
while (this.waiters.length > 0) {
|
|
69
|
+
const waiter = this.waiters[0];
|
|
70
|
+
const slotIndex = this.findFreeSlot(waiter.criteria);
|
|
71
|
+
if (slotIndex !== -1) {
|
|
72
|
+
this.waiters.shift();
|
|
73
|
+
this.grantSlot(slotIndex, waiter);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (this.slots.length < this.maxSlots) {
|
|
77
|
+
this.waiters.shift();
|
|
78
|
+
void this.startAllocationForWaiter(waiter);
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
findFreeSlot(criteria) {
|
|
85
|
+
for (let i = 0; i < this.slots.length; i++) {
|
|
86
|
+
const slot = this.slots[i];
|
|
87
|
+
if (slot.state === 'available' && slotMatches(slot, criteria)) {
|
|
88
|
+
return i;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return -1;
|
|
92
|
+
}
|
|
93
|
+
grantSlot(slotIndex, waiter) {
|
|
94
|
+
const slot = this.slots[slotIndex];
|
|
95
|
+
const deviceId = slot.deviceId;
|
|
96
|
+
const platform = slot.platform;
|
|
97
|
+
if (deviceId === undefined || platform === undefined) {
|
|
98
|
+
waiter.reject(new Error('internal: slot missing deviceId/platform'));
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const allocation = Allocation.create({ deviceId, platform, slotIndex });
|
|
102
|
+
slot.claim(allocation.allocationId);
|
|
103
|
+
this.allocations.set(allocation.allocationId, allocation);
|
|
104
|
+
waiter.resolve({
|
|
105
|
+
allocationId: allocation.allocationId,
|
|
106
|
+
deviceId: allocation.deviceId,
|
|
107
|
+
platform: allocation.platform,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
async startAllocationForWaiter(waiter) {
|
|
111
|
+
const slot = new DeviceSlot();
|
|
112
|
+
this.slots.push(slot);
|
|
113
|
+
const slotIndex = this.slots.length - 1;
|
|
114
|
+
this.inFlightWaiters.add(waiter);
|
|
115
|
+
const abortController = new AbortController();
|
|
116
|
+
const timer = setTimeout(() => abortController.abort(), this.allocationTimeoutMs);
|
|
117
|
+
let result;
|
|
118
|
+
try {
|
|
119
|
+
result = await this.allocator.allocate(waiter.criteria, this.takenDeviceIds(), abortController.signal);
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
clearTimeout(timer);
|
|
123
|
+
if (!this.inFlightWaiters.delete(waiter)) {
|
|
124
|
+
// Shutdown already rejected this waiter.
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
this.slots.splice(slotIndex, 1);
|
|
128
|
+
if (abortController.signal.aborted) {
|
|
129
|
+
waiter.reject(new Error(`device allocation timed out after ${this.allocationTimeoutMs}ms`));
|
|
130
|
+
this.pump();
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
// NoDeviceAvailableError is a temporary condition: all matching devices
|
|
134
|
+
// are currently taken. Re-queue the waiter so it is served when an
|
|
135
|
+
// existing slot releases its device.
|
|
136
|
+
if (err instanceof NoDeviceAvailableError) {
|
|
137
|
+
this.waiters.push(waiter);
|
|
138
|
+
// Only pump if a free slot appeared concurrently while we were allocating.
|
|
139
|
+
const hasFreeSlot = this.findFreeSlot(waiter.criteria) !== -1;
|
|
140
|
+
if (hasFreeSlot) {
|
|
141
|
+
this.pump();
|
|
142
|
+
}
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
waiter.reject(err);
|
|
146
|
+
this.pump();
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
clearTimeout(timer);
|
|
150
|
+
if (!this.inFlightWaiters.delete(waiter)) {
|
|
151
|
+
// Shutdown already rejected this waiter; just discard the device.
|
|
152
|
+
this.allocator.release(result.deviceId).catch(() => { });
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
slot.markAvailable(result.deviceId, result.platform);
|
|
156
|
+
this.waiters.unshift(waiter);
|
|
157
|
+
this.pump();
|
|
158
|
+
}
|
|
159
|
+
takenDeviceIds() {
|
|
160
|
+
return new Set(this.slots
|
|
161
|
+
.map((slot) => slot.deviceId)
|
|
162
|
+
.filter((id) => id !== undefined));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
function slotMatches(slot, criteria) {
|
|
166
|
+
if (criteria.platform && slot.platform !== criteria.platform) {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
if (criteria.deviceId && slot.deviceId !== criteria.deviceId) {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=device-pool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-pool.js","sourceRoot":"","sources":["../../../src/device-pool/application/device-pool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-pool.test.d.ts","sourceRoot":"","sources":["../../../src/device-pool/application/device-pool.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { test, expect } from '@playwright/test';
|
|
2
|
+
import { DevicePool } from './device-pool.js';
|
|
3
|
+
import { NoDeviceAvailableError } from './ports.js';
|
|
4
|
+
function makeAllocator(devices) {
|
|
5
|
+
let i = 0;
|
|
6
|
+
return {
|
|
7
|
+
async allocate() {
|
|
8
|
+
if (i >= devices.length) {
|
|
9
|
+
throw new Error('no more fake devices');
|
|
10
|
+
}
|
|
11
|
+
return devices[i++];
|
|
12
|
+
},
|
|
13
|
+
async release() { },
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
test('first allocate spins up a slot and returns a handle', async () => {
|
|
17
|
+
const allocator = makeAllocator([{ deviceId: 'd1', platform: 'ios' }]);
|
|
18
|
+
const pool = new DevicePool({ allocator, maxSlots: 2 });
|
|
19
|
+
const handle = await pool.allocate({ platform: 'ios' });
|
|
20
|
+
expect(handle.deviceId).toBe('d1');
|
|
21
|
+
expect(handle.platform).toBe('ios');
|
|
22
|
+
expect(handle.allocationId).toMatch(/^alloc-/);
|
|
23
|
+
});
|
|
24
|
+
test('a released slot is reused by a subsequent allocate', async () => {
|
|
25
|
+
const allocator = makeAllocator([{ deviceId: 'd1', platform: 'ios' }]);
|
|
26
|
+
const pool = new DevicePool({ allocator, maxSlots: 2 });
|
|
27
|
+
const first = await pool.allocate({ platform: 'ios' });
|
|
28
|
+
await pool.release(first.allocationId);
|
|
29
|
+
const second = await pool.allocate({ platform: 'ios' });
|
|
30
|
+
expect(second.deviceId).toBe('d1');
|
|
31
|
+
expect(second.allocationId).not.toBe(first.allocationId);
|
|
32
|
+
});
|
|
33
|
+
test('a second concurrent allocate when no free slot triggers parallel allocation', async () => {
|
|
34
|
+
let calls = 0;
|
|
35
|
+
const allocator = {
|
|
36
|
+
async allocate() {
|
|
37
|
+
calls++;
|
|
38
|
+
return { deviceId: `d${calls}`, platform: 'ios' };
|
|
39
|
+
},
|
|
40
|
+
async release() { },
|
|
41
|
+
};
|
|
42
|
+
const pool = new DevicePool({ allocator, maxSlots: 2 });
|
|
43
|
+
const [a, b] = await Promise.all([
|
|
44
|
+
pool.allocate({ platform: 'ios' }),
|
|
45
|
+
pool.allocate({ platform: 'ios' }),
|
|
46
|
+
]);
|
|
47
|
+
const ids = [a.deviceId, b.deviceId].sort();
|
|
48
|
+
expect(ids).toEqual(['d1', 'd2']);
|
|
49
|
+
expect(calls).toBe(2);
|
|
50
|
+
});
|
|
51
|
+
test('waiter resolves when an existing allocated slot is released', async () => {
|
|
52
|
+
const allocator = makeAllocator([{ deviceId: 'd1', platform: 'ios' }]);
|
|
53
|
+
const pool = new DevicePool({ allocator, maxSlots: 1 });
|
|
54
|
+
const first = await pool.allocate({ platform: 'ios' });
|
|
55
|
+
let secondHandle;
|
|
56
|
+
const secondPromise = pool.allocate({ platform: 'ios' }).then((h) => { secondHandle = h; });
|
|
57
|
+
await Promise.resolve();
|
|
58
|
+
expect(secondHandle).toBeUndefined();
|
|
59
|
+
await pool.release(first.allocationId);
|
|
60
|
+
await secondPromise;
|
|
61
|
+
expect(secondHandle?.deviceId).toBe('d1');
|
|
62
|
+
});
|
|
63
|
+
test('NoDeviceAvailableError re-queues the waiter to be served on next release', async () => {
|
|
64
|
+
// Simulates 3 workers competing for 2 devices.
|
|
65
|
+
// Workers 0 and 1 allocate. Worker 2 gets NoDeviceAvailableError from the
|
|
66
|
+
// allocator. It should re-queue and be served when worker 0 releases.
|
|
67
|
+
let counter = 0;
|
|
68
|
+
const devices = ['sim-a', 'sim-b'];
|
|
69
|
+
const allocator = {
|
|
70
|
+
async allocate(_c, takenDeviceIds) {
|
|
71
|
+
const available = devices.filter(id => !takenDeviceIds.has(id));
|
|
72
|
+
if (available.length === 0) {
|
|
73
|
+
throw new NoDeviceAvailableError('no device available');
|
|
74
|
+
}
|
|
75
|
+
const deviceId = available[counter++ % available.length];
|
|
76
|
+
return { deviceId, platform: 'ios' };
|
|
77
|
+
},
|
|
78
|
+
async release() { },
|
|
79
|
+
};
|
|
80
|
+
const pool = new DevicePool({ allocator, maxSlots: 3 });
|
|
81
|
+
const w0 = await pool.allocate({ platform: 'ios' });
|
|
82
|
+
const w1 = await pool.allocate({ platform: 'ios' });
|
|
83
|
+
// w2 should block because both devices are taken.
|
|
84
|
+
let w2Handle;
|
|
85
|
+
const w2Promise = pool.allocate({ platform: 'ios' }).then(h => { w2Handle = h; });
|
|
86
|
+
await Promise.resolve();
|
|
87
|
+
expect(w2Handle).toBeUndefined();
|
|
88
|
+
// Releasing w0 should unblock w2.
|
|
89
|
+
await pool.release(w0.allocationId);
|
|
90
|
+
await w2Promise;
|
|
91
|
+
expect(w2Handle?.deviceId).toBe('sim-a');
|
|
92
|
+
});
|
|
93
|
+
test('allocation failure rejects the requesting waiter and drops the slot', async () => {
|
|
94
|
+
let attempts = 0;
|
|
95
|
+
const allocator = {
|
|
96
|
+
async allocate() {
|
|
97
|
+
attempts++;
|
|
98
|
+
if (attempts === 1) {
|
|
99
|
+
throw new Error('boom');
|
|
100
|
+
}
|
|
101
|
+
return { deviceId: `d${attempts}`, platform: 'ios' };
|
|
102
|
+
},
|
|
103
|
+
async release() { },
|
|
104
|
+
};
|
|
105
|
+
const pool = new DevicePool({ allocator, maxSlots: 2 });
|
|
106
|
+
await expect(pool.allocate({ platform: 'ios' })).rejects.toThrow('boom');
|
|
107
|
+
const handle = await pool.allocate({ platform: 'ios' });
|
|
108
|
+
expect(handle.deviceId).toBe('d2');
|
|
109
|
+
});
|
|
110
|
+
test('FIFO order across multiple waiters', async () => {
|
|
111
|
+
const allocator = makeAllocator([{ deviceId: 'd1', platform: 'ios' }]);
|
|
112
|
+
const pool = new DevicePool({ allocator, maxSlots: 1 });
|
|
113
|
+
const first = await pool.allocate({ platform: 'ios' });
|
|
114
|
+
const order = [];
|
|
115
|
+
const w1 = pool.allocate({ platform: 'ios' }).then((h) => order.push(`w1:${h.allocationId}`));
|
|
116
|
+
const w2 = pool.allocate({ platform: 'ios' }).then((h) => order.push(`w2:${h.allocationId}`));
|
|
117
|
+
await pool.release(first.allocationId);
|
|
118
|
+
await w1;
|
|
119
|
+
const firstWaiterAllocId = order[0].split(':')[1];
|
|
120
|
+
await pool.release(firstWaiterAllocId);
|
|
121
|
+
await w2;
|
|
122
|
+
expect(order.length).toBe(2);
|
|
123
|
+
expect(order[0]).toMatch(/^w1:/);
|
|
124
|
+
expect(order[1]).toMatch(/^w2:/);
|
|
125
|
+
});
|
|
126
|
+
test('isAppInstalled is false until recordAppInstalled is called', async () => {
|
|
127
|
+
const allocator = makeAllocator([{ deviceId: 'd1', platform: 'ios' }]);
|
|
128
|
+
const pool = new DevicePool({ allocator, maxSlots: 1 });
|
|
129
|
+
const handle = await pool.allocate({ platform: 'ios' });
|
|
130
|
+
expect(pool.isAppInstalled(handle.allocationId, 'app.ipa')).toBe(false);
|
|
131
|
+
pool.recordAppInstalled(handle.allocationId, 'app.ipa');
|
|
132
|
+
expect(pool.isAppInstalled(handle.allocationId, 'app.ipa')).toBe(true);
|
|
133
|
+
});
|
|
134
|
+
test('install tracking persists across releases of the same slot', async () => {
|
|
135
|
+
const allocator = makeAllocator([{ deviceId: 'd1', platform: 'ios' }]);
|
|
136
|
+
const pool = new DevicePool({ allocator, maxSlots: 1 });
|
|
137
|
+
const first = await pool.allocate({ platform: 'ios' });
|
|
138
|
+
pool.recordAppInstalled(first.allocationId, 'app.ipa');
|
|
139
|
+
await pool.release(first.allocationId);
|
|
140
|
+
const second = await pool.allocate({ platform: 'ios' });
|
|
141
|
+
expect(pool.isAppInstalled(second.allocationId, 'app.ipa')).toBe(true);
|
|
142
|
+
});
|
|
143
|
+
test('shutdown calls allocator.release for every available slot', async () => {
|
|
144
|
+
const released = [];
|
|
145
|
+
let counter = 0;
|
|
146
|
+
const allocator = {
|
|
147
|
+
async allocate() {
|
|
148
|
+
counter++;
|
|
149
|
+
return { deviceId: `d${counter}`, platform: 'ios' };
|
|
150
|
+
},
|
|
151
|
+
async release(deviceId) { released.push(deviceId); },
|
|
152
|
+
};
|
|
153
|
+
const pool = new DevicePool({ allocator, maxSlots: 2 });
|
|
154
|
+
const a = await pool.allocate({ platform: 'ios' });
|
|
155
|
+
const b = await pool.allocate({ platform: 'ios' });
|
|
156
|
+
await pool.release(a.allocationId);
|
|
157
|
+
await pool.shutdown();
|
|
158
|
+
expect(released.sort()).toEqual([a.deviceId, b.deviceId].sort());
|
|
159
|
+
});
|
|
160
|
+
test('shutdown rejects in-flight waiters', async () => {
|
|
161
|
+
const allocator = {
|
|
162
|
+
async allocate() {
|
|
163
|
+
return new Promise(() => { });
|
|
164
|
+
},
|
|
165
|
+
async release() { },
|
|
166
|
+
};
|
|
167
|
+
const pool = new DevicePool({ allocator, maxSlots: 1 });
|
|
168
|
+
const promise = pool.allocate({ platform: 'ios' });
|
|
169
|
+
await Promise.resolve();
|
|
170
|
+
await pool.shutdown();
|
|
171
|
+
await expect(promise).rejects.toThrow(/shutdown/i);
|
|
172
|
+
});
|
|
173
|
+
test('allocation that exceeds allocationTimeoutMs rejects with timeout error', async () => {
|
|
174
|
+
const allocator = {
|
|
175
|
+
async allocate(_c, _t, signal) {
|
|
176
|
+
return new Promise((_, reject) => {
|
|
177
|
+
signal?.addEventListener('abort', () => reject(new Error('aborted')));
|
|
178
|
+
});
|
|
179
|
+
},
|
|
180
|
+
async release() { },
|
|
181
|
+
};
|
|
182
|
+
const pool = new DevicePool({ allocator, maxSlots: 1, allocationTimeoutMs: 50 });
|
|
183
|
+
await expect(pool.allocate({ platform: 'ios' })).rejects.toThrow(/timed out/i);
|
|
184
|
+
});
|
|
185
|
+
//# sourceMappingURL=device-pool.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-pool.test.js","sourceRoot":"","sources":["../../../src/device-pool/application/device-pool.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Platform } from '@mobilewright/protocol';
|
|
2
|
+
/**
|
|
3
|
+
* Thrown by a DeviceAllocator when no device is currently available but one
|
|
4
|
+
* may become available later (e.g. all matching devices are already taken).
|
|
5
|
+
* DevicePool treats this as a temporary condition and re-queues the waiter
|
|
6
|
+
* rather than rejecting it outright.
|
|
7
|
+
*/
|
|
8
|
+
export declare class NoDeviceAvailableError extends Error {
|
|
9
|
+
constructor(message: string);
|
|
10
|
+
}
|
|
11
|
+
export interface AllocationCriteria {
|
|
12
|
+
platform?: Platform;
|
|
13
|
+
/** Serialized regex source — `RegExp.prototype.source`. The allocator reconstructs `new RegExp(...)`. */
|
|
14
|
+
deviceNamePattern?: string;
|
|
15
|
+
deviceId?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface AllocateResult {
|
|
18
|
+
deviceId: string;
|
|
19
|
+
platform: Platform;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Driver-specific allocator. Implementations are at the outer adapter layer.
|
|
23
|
+
* `takenDeviceIds` lets the allocator avoid handing out devices the pool already has.
|
|
24
|
+
*/
|
|
25
|
+
export interface DeviceAllocator {
|
|
26
|
+
allocate(criteria: AllocationCriteria, takenDeviceIds: ReadonlySet<string>, signal?: AbortSignal): Promise<AllocateResult>;
|
|
27
|
+
/** Called at pool shutdown for every slot in `available` or `allocated` state. */
|
|
28
|
+
release(deviceId: string): Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
export interface AllocationHandle {
|
|
31
|
+
allocationId: string;
|
|
32
|
+
deviceId: string;
|
|
33
|
+
platform: Platform;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Port consumed by the test fixture. The HTTP adapter is one implementation.
|
|
37
|
+
*/
|
|
38
|
+
export interface DevicePoolClient {
|
|
39
|
+
allocate(criteria: AllocationCriteria): Promise<AllocationHandle>;
|
|
40
|
+
release(allocationId: string): Promise<void>;
|
|
41
|
+
isAppInstalled(allocationId: string, bundleId: string): Promise<boolean>;
|
|
42
|
+
recordAppInstalled(allocationId: string, bundleId: string): Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=ports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ports.d.ts","sourceRoot":"","sources":["../../../src/device-pool/application/ports.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAEvD;;;;;GAKG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,yGAAyG;IACzG,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CACN,QAAQ,EAAE,kBAAkB,EAC5B,cAAc,EAAE,WAAW,CAAC,MAAM,CAAC,EACnC,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,cAAc,CAAC,CAAC;IAE3B,kFAAkF;IAClF,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAClE,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACzE,kBAAkB,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3E"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thrown by a DeviceAllocator when no device is currently available but one
|
|
3
|
+
* may become available later (e.g. all matching devices are already taken).
|
|
4
|
+
* DevicePool treats this as a temporary condition and re-queues the waiter
|
|
5
|
+
* rather than rejecting it outright.
|
|
6
|
+
*/
|
|
7
|
+
export class NoDeviceAvailableError extends Error {
|
|
8
|
+
constructor(message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = 'NoDeviceAvailableError';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=ports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ports.js","sourceRoot":"","sources":["../../../src/device-pool/application/ports.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IAC/C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;IACvC,CAAC;CACF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { DevicePoolClient } from './application/ports.js';
|
|
2
|
+
export declare const COORDINATOR_URL_ENV = "MOBILEWRIGHT_COORDINATOR_URL";
|
|
3
|
+
/**
|
|
4
|
+
* Internal factory used by the test fixture. Throws if the coordinator was
|
|
5
|
+
* not started (i.e. the user bypassed `defineConfig`).
|
|
6
|
+
*/
|
|
7
|
+
export declare function createDevicePoolClient(): DevicePoolClient;
|
|
8
|
+
//# sourceMappingURL=client-factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-factory.d.ts","sourceRoot":"","sources":["../../src/device-pool/client-factory.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,eAAO,MAAM,mBAAmB,iCAAiC,CAAC;AAElE;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,gBAAgB,CAUzD"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { HttpDevicePoolClient } from './adapters/http-client.js';
|
|
2
|
+
export const COORDINATOR_URL_ENV = 'MOBILEWRIGHT_COORDINATOR_URL';
|
|
3
|
+
/**
|
|
4
|
+
* Internal factory used by the test fixture. Throws if the coordinator was
|
|
5
|
+
* not started (i.e. the user bypassed `defineConfig`).
|
|
6
|
+
*/
|
|
7
|
+
export function createDevicePoolClient() {
|
|
8
|
+
const baseUrl = process.env[COORDINATOR_URL_ENV];
|
|
9
|
+
if (!baseUrl) {
|
|
10
|
+
throw new Error(`${COORDINATOR_URL_ENV} is not set. ` +
|
|
11
|
+
'Did you use defineConfig() in your mobilewright.config.ts? ' +
|
|
12
|
+
'It auto-injects the device-pool coordinator.');
|
|
13
|
+
}
|
|
14
|
+
return new HttpDevicePoolClient({ baseUrl });
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=client-factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-factory.js","sourceRoot":"","sources":["../../src/device-pool/client-factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAGjE,MAAM,CAAC,MAAM,mBAAmB,GAAG,8BAA8B,CAAC;AAElE;;;GAGG;AACH,MAAM,UAAU,sBAAsB;IACpC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACjD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,GAAG,mBAAmB,eAAe;YACrC,6DAA6D;YAC7D,8CAA8C,CAC/C,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,oBAAoB,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Platform } from '@mobilewright/protocol';
|
|
2
|
+
export interface AllocationParams {
|
|
3
|
+
allocationId: string;
|
|
4
|
+
deviceId: string;
|
|
5
|
+
platform: Platform;
|
|
6
|
+
slotIndex: number;
|
|
7
|
+
}
|
|
8
|
+
export interface AllocationCreateParams {
|
|
9
|
+
deviceId: string;
|
|
10
|
+
platform: Platform;
|
|
11
|
+
slotIndex: number;
|
|
12
|
+
}
|
|
13
|
+
export declare class Allocation {
|
|
14
|
+
readonly allocationId: string;
|
|
15
|
+
readonly deviceId: string;
|
|
16
|
+
readonly platform: Platform;
|
|
17
|
+
readonly slotIndex: number;
|
|
18
|
+
constructor(params: AllocationParams);
|
|
19
|
+
static create(params: AllocationCreateParams): Allocation;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=allocation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"allocation.d.ts","sourceRoot":"","sources":["../../../src/device-pool/domain/allocation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAEvD,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,UAAU;IACrB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAEf,MAAM,EAAE,gBAAgB;IAOpC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,sBAAsB,GAAG,UAAU;CAI1D"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
export class Allocation {
|
|
3
|
+
constructor(params) {
|
|
4
|
+
this.allocationId = params.allocationId;
|
|
5
|
+
this.deviceId = params.deviceId;
|
|
6
|
+
this.platform = params.platform;
|
|
7
|
+
this.slotIndex = params.slotIndex;
|
|
8
|
+
}
|
|
9
|
+
static create(params) {
|
|
10
|
+
const id = `alloc-${randomBytes(8).toString('hex')}`;
|
|
11
|
+
return new Allocation({ allocationId: id, ...params });
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=allocation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"allocation.js","sourceRoot":"","sources":["../../../src/device-pool/domain/allocation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAgB1C,MAAM,OAAO,UAAU;IAMrB,YAAY,MAAwB;QAClC,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC;QACxC,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QAChC,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QAChC,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;IACpC,CAAC;IAED,MAAM,CAAC,MAAM,CAAC,MAA8B;QAC1C,MAAM,EAAE,GAAG,SAAS,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACrD,OAAO,IAAI,UAAU,CAAC,EAAE,YAAY,EAAE,EAAE,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;IACzD,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"allocation.test.d.ts","sourceRoot":"","sources":["../../../src/device-pool/domain/allocation.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { test, expect } from '@playwright/test';
|
|
2
|
+
import { Allocation } from './allocation.js';
|
|
3
|
+
test('Allocation carries id, deviceId, platform, and slotIndex', () => {
|
|
4
|
+
const allocation = new Allocation({
|
|
5
|
+
allocationId: 'alloc-1',
|
|
6
|
+
deviceId: 'device-1',
|
|
7
|
+
platform: 'ios',
|
|
8
|
+
slotIndex: 3,
|
|
9
|
+
});
|
|
10
|
+
expect(allocation.allocationId).toBe('alloc-1');
|
|
11
|
+
expect(allocation.deviceId).toBe('device-1');
|
|
12
|
+
expect(allocation.platform).toBe('ios');
|
|
13
|
+
expect(allocation.slotIndex).toBe(3);
|
|
14
|
+
});
|
|
15
|
+
test('Allocation generates a fresh id when one is not provided', () => {
|
|
16
|
+
const a = Allocation.create({ deviceId: 'd', platform: 'ios', slotIndex: 0 });
|
|
17
|
+
const b = Allocation.create({ deviceId: 'd', platform: 'ios', slotIndex: 0 });
|
|
18
|
+
expect(a.allocationId).toMatch(/^alloc-/);
|
|
19
|
+
expect(a.allocationId).not.toBe(b.allocationId);
|
|
20
|
+
});
|
|
21
|
+
//# sourceMappingURL=allocation.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"allocation.test.js","sourceRoot":"","sources":["../../../src/device-pool/domain/allocation.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,IAAI,CAAC,0DAA0D,EAAE,GAAG,EAAE;IACpE,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC;QAChC,YAAY,EAAE,SAAS;QACvB,QAAQ,EAAE,UAAU;QACpB,QAAQ,EAAE,KAAK;QACf,SAAS,EAAE,CAAC;KACb,CAAC,CAAC;IAEH,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAChD,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC7C,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACvC,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,0DAA0D,EAAE,GAAG,EAAE;IACpE,MAAM,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9E,MAAM,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9E,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC1C,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;AAClD,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Platform } from '@mobilewright/protocol';
|
|
2
|
+
export type DeviceSlotState = 'allocating' | 'available' | 'allocated';
|
|
3
|
+
export declare class DeviceSlotStateError extends Error {
|
|
4
|
+
constructor(message: string);
|
|
5
|
+
}
|
|
6
|
+
export declare class DeviceSlot {
|
|
7
|
+
private _state;
|
|
8
|
+
private _deviceId?;
|
|
9
|
+
private _platform?;
|
|
10
|
+
private _allocationId?;
|
|
11
|
+
private readonly _installedApps;
|
|
12
|
+
get state(): DeviceSlotState;
|
|
13
|
+
get deviceId(): string | undefined;
|
|
14
|
+
get platform(): Platform | undefined;
|
|
15
|
+
get allocationId(): string | undefined;
|
|
16
|
+
markAvailable(deviceId: string, platform: Platform): void;
|
|
17
|
+
claim(allocationId: string): void;
|
|
18
|
+
release(): void;
|
|
19
|
+
recordAppInstalled(bundleId: string): void;
|
|
20
|
+
isAppInstalled(bundleId: string): boolean;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=device-slot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-slot.d.ts","sourceRoot":"","sources":["../../../src/device-pool/domain/device-slot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAEvD,MAAM,MAAM,eAAe,GAAG,YAAY,GAAG,WAAW,GAAG,WAAW,CAAC;AAEvE,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,SAAS,CAAC,CAAS;IAC3B,OAAO,CAAC,SAAS,CAAC,CAAW;IAC7B,OAAO,CAAC,aAAa,CAAC,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAqB;IAEpD,IAAI,KAAK,IAAI,eAAe,CAE3B;IAED,IAAI,QAAQ,IAAI,MAAM,GAAG,SAAS,CAEjC;IAED,IAAI,QAAQ,IAAI,QAAQ,GAAG,SAAS,CAEnC;IAED,IAAI,YAAY,IAAI,MAAM,GAAG,SAAS,CAErC;IAED,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAWzD,KAAK,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IAUjC,OAAO,IAAI,IAAI;IAUf,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAI1C,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;CAG1C"}
|