mobilewright 0.0.26 → 0.0.27

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 (91) hide show
  1. package/dist/cli.js +51 -3
  2. package/dist/cli.js.map +1 -1
  3. package/dist/config.d.ts +3 -2
  4. package/dist/config.d.ts.map +1 -1
  5. package/dist/config.js +18 -3
  6. package/dist/config.js.map +1 -1
  7. package/dist/config.test.d.ts +2 -0
  8. package/dist/config.test.d.ts.map +1 -0
  9. package/dist/config.test.js +22 -0
  10. package/dist/config.test.js.map +1 -0
  11. package/dist/device-pool/adapters/http-client.d.ts +16 -0
  12. package/dist/device-pool/adapters/http-client.d.ts.map +1 -0
  13. package/dist/device-pool/adapters/http-client.js +91 -0
  14. package/dist/device-pool/adapters/http-client.js.map +1 -0
  15. package/dist/device-pool/adapters/http-client.test.d.ts +2 -0
  16. package/dist/device-pool/adapters/http-client.test.d.ts.map +1 -0
  17. package/dist/device-pool/adapters/http-client.test.js +72 -0
  18. package/dist/device-pool/adapters/http-client.test.js.map +1 -0
  19. package/dist/device-pool/adapters/http-server.d.ts +19 -0
  20. package/dist/device-pool/adapters/http-server.d.ts.map +1 -0
  21. package/dist/device-pool/adapters/http-server.js +126 -0
  22. package/dist/device-pool/adapters/http-server.js.map +1 -0
  23. package/dist/device-pool/adapters/http-server.test.d.ts +2 -0
  24. package/dist/device-pool/adapters/http-server.test.d.ts.map +1 -0
  25. package/dist/device-pool/adapters/http-server.test.js +203 -0
  26. package/dist/device-pool/adapters/http-server.test.js.map +1 -0
  27. package/dist/device-pool/adapters/mobile-use-allocator.d.ts +13 -0
  28. package/dist/device-pool/adapters/mobile-use-allocator.d.ts.map +1 -0
  29. package/dist/device-pool/adapters/mobile-use-allocator.js +31 -0
  30. package/dist/device-pool/adapters/mobile-use-allocator.js.map +1 -0
  31. package/dist/device-pool/adapters/mobilecli-allocator.d.ts +19 -0
  32. package/dist/device-pool/adapters/mobilecli-allocator.d.ts.map +1 -0
  33. package/dist/device-pool/adapters/mobilecli-allocator.js +26 -0
  34. package/dist/device-pool/adapters/mobilecli-allocator.js.map +1 -0
  35. package/dist/device-pool/adapters/mobilecli-allocator.test.d.ts +2 -0
  36. package/dist/device-pool/adapters/mobilecli-allocator.test.d.ts.map +1 -0
  37. package/dist/device-pool/adapters/mobilecli-allocator.test.js +61 -0
  38. package/dist/device-pool/adapters/mobilecli-allocator.test.js.map +1 -0
  39. package/dist/device-pool/allocator-factory.d.ts +10 -0
  40. package/dist/device-pool/allocator-factory.d.ts.map +1 -0
  41. package/dist/device-pool/allocator-factory.js +25 -0
  42. package/dist/device-pool/allocator-factory.js.map +1 -0
  43. package/dist/device-pool/application/device-pool.d.ts +29 -0
  44. package/dist/device-pool/application/device-pool.d.ts.map +1 -0
  45. package/dist/device-pool/application/device-pool.js +174 -0
  46. package/dist/device-pool/application/device-pool.js.map +1 -0
  47. package/dist/device-pool/application/device-pool.test.d.ts +2 -0
  48. package/dist/device-pool/application/device-pool.test.d.ts.map +1 -0
  49. package/dist/device-pool/application/device-pool.test.js +185 -0
  50. package/dist/device-pool/application/device-pool.test.js.map +1 -0
  51. package/dist/device-pool/application/ports.d.ts +44 -0
  52. package/dist/device-pool/application/ports.d.ts.map +1 -0
  53. package/dist/device-pool/application/ports.js +13 -0
  54. package/dist/device-pool/application/ports.js.map +1 -0
  55. package/dist/device-pool/client-factory.d.ts +8 -0
  56. package/dist/device-pool/client-factory.d.ts.map +1 -0
  57. package/dist/device-pool/client-factory.js +16 -0
  58. package/dist/device-pool/client-factory.js.map +1 -0
  59. package/dist/device-pool/domain/allocation.d.ts +21 -0
  60. package/dist/device-pool/domain/allocation.d.ts.map +1 -0
  61. package/dist/device-pool/domain/allocation.js +14 -0
  62. package/dist/device-pool/domain/allocation.js.map +1 -0
  63. package/dist/device-pool/domain/allocation.test.d.ts +2 -0
  64. package/dist/device-pool/domain/allocation.test.d.ts.map +1 -0
  65. package/dist/device-pool/domain/allocation.test.js +21 -0
  66. package/dist/device-pool/domain/allocation.test.js.map +1 -0
  67. package/dist/device-pool/domain/device-slot.d.ts +22 -0
  68. package/dist/device-pool/domain/device-slot.d.ts.map +1 -0
  69. package/dist/device-pool/domain/device-slot.js +53 -0
  70. package/dist/device-pool/domain/device-slot.js.map +1 -0
  71. package/dist/device-pool/domain/device-slot.test.d.ts +2 -0
  72. package/dist/device-pool/domain/device-slot.test.d.ts.map +1 -0
  73. package/dist/device-pool/domain/device-slot.test.js +53 -0
  74. package/dist/device-pool/domain/device-slot.test.js.map +1 -0
  75. package/dist/device-pool/setup.d.ts +7 -0
  76. package/dist/device-pool/setup.d.ts.map +1 -0
  77. package/dist/device-pool/setup.js +35 -0
  78. package/dist/device-pool/setup.js.map +1 -0
  79. package/dist/device-pool/teardown.d.ts +7 -0
  80. package/dist/device-pool/teardown.d.ts.map +1 -0
  81. package/dist/device-pool/teardown.js +9 -0
  82. package/dist/device-pool/teardown.js.map +1 -0
  83. package/dist/index.d.ts +4 -0
  84. package/dist/index.d.ts.map +1 -1
  85. package/dist/index.js +4 -0
  86. package/dist/index.js.map +1 -1
  87. package/dist/launchers.d.ts +19 -1
  88. package/dist/launchers.d.ts.map +1 -1
  89. package/dist/launchers.js +53 -22
  90. package/dist/launchers.js.map +1 -1
  91. package/package.json +6 -6
@@ -0,0 +1,203 @@
1
+ import { test, expect } from '@playwright/test';
2
+ import { request as httpRequest } from 'node:http';
3
+ import { DevicePool } from '../application/device-pool.js';
4
+ import { DevicePoolHttpServer } from './http-server.js';
5
+ function makeAllocator(devices) {
6
+ let i = 0;
7
+ return {
8
+ async allocate() {
9
+ return devices[i++ % devices.length];
10
+ },
11
+ async release() { },
12
+ };
13
+ }
14
+ async function startServer(pool) {
15
+ const server = new DevicePoolHttpServer({ pool });
16
+ const port = await server.listen();
17
+ return {
18
+ url: `http://127.0.0.1:${port}`,
19
+ stop: () => server.close(),
20
+ };
21
+ }
22
+ function postAllocateAndReadFirstLine(url, body) {
23
+ return new Promise((resolve, reject) => {
24
+ const req = httpRequest(`${url}/allocate`, { method: 'POST', headers: { 'content-type': 'application/json' } }, (res) => {
25
+ let buffer = '';
26
+ res.on('data', (chunk) => {
27
+ buffer += chunk.toString('utf8');
28
+ const newlineIdx = buffer.indexOf('\n');
29
+ if (newlineIdx !== -1) {
30
+ resolve(buffer.slice(0, newlineIdx));
31
+ }
32
+ });
33
+ res.on('error', reject);
34
+ });
35
+ req.on('error', reject);
36
+ req.write(body);
37
+ req.end();
38
+ });
39
+ }
40
+ test('POST /allocate returns a JSON line with allocationId, deviceId, platform', async () => {
41
+ const pool = new DevicePool({
42
+ allocator: makeAllocator([{ deviceId: 'd1', platform: 'ios' }]),
43
+ maxSlots: 1,
44
+ });
45
+ const server = await startServer(pool);
46
+ try {
47
+ const line = await postAllocateAndReadFirstLine(server.url, JSON.stringify({ criteria: { platform: 'ios' } }));
48
+ const parsed = JSON.parse(line);
49
+ expect(parsed.deviceId).toBe('d1');
50
+ expect(parsed.platform).toBe('ios');
51
+ expect(parsed.allocationId).toMatch(/^alloc-/);
52
+ }
53
+ finally {
54
+ await server.stop();
55
+ }
56
+ });
57
+ function postReleaseRequest(url, allocationId) {
58
+ return new Promise((resolve, reject) => {
59
+ const req = httpRequest(`${url}/release`, { method: 'POST', headers: { 'content-type': 'application/json' } }, (res) => {
60
+ res.on('data', () => { });
61
+ res.on('end', () => resolve(res.statusCode ?? 0));
62
+ });
63
+ req.on('error', reject);
64
+ req.write(JSON.stringify({ allocationId }));
65
+ req.end();
66
+ });
67
+ }
68
+ test('POST /release frees the slot for the next allocate', async () => {
69
+ const pool = new DevicePool({
70
+ allocator: makeAllocator([{ deviceId: 'd1', platform: 'ios' }]),
71
+ maxSlots: 1,
72
+ });
73
+ const server = await startServer(pool);
74
+ try {
75
+ const firstLine = await postAllocateAndReadFirstLine(server.url, JSON.stringify({ criteria: { platform: 'ios' } }));
76
+ const first = JSON.parse(firstLine);
77
+ const status = await postReleaseRequest(server.url, first.allocationId);
78
+ expect(status).toBe(200);
79
+ const secondLine = await postAllocateAndReadFirstLine(server.url, JSON.stringify({ criteria: { platform: 'ios' } }));
80
+ const second = JSON.parse(secondLine);
81
+ expect(second.deviceId).toBe('d1');
82
+ await postReleaseRequest(server.url, second.allocationId);
83
+ }
84
+ finally {
85
+ await server.stop();
86
+ }
87
+ });
88
+ function startAllocateRequest(url, body) {
89
+ return new Promise((resolve, reject) => {
90
+ const req = httpRequest(`${url}/allocate`, { method: 'POST', headers: { 'content-type': 'application/json' } }, (res) => {
91
+ let buffer = '';
92
+ res.on('data', (chunk) => {
93
+ buffer += chunk.toString('utf8');
94
+ const newlineIdx = buffer.indexOf('\n');
95
+ if (newlineIdx !== -1) {
96
+ const parsed = JSON.parse(buffer.slice(0, newlineIdx));
97
+ resolve({
98
+ allocationId: parsed.allocationId,
99
+ deviceId: parsed.deviceId,
100
+ abort: () => req.destroy(),
101
+ });
102
+ }
103
+ });
104
+ });
105
+ req.on('error', reject);
106
+ req.write(body);
107
+ req.end();
108
+ });
109
+ }
110
+ test('closing the /allocate socket releases the allocation', async () => {
111
+ const pool = new DevicePool({
112
+ allocator: makeAllocator([{ deviceId: 'd1', platform: 'ios' }]),
113
+ maxSlots: 1,
114
+ });
115
+ const server = await startServer(pool);
116
+ try {
117
+ const first = await startAllocateRequest(server.url, JSON.stringify({ criteria: { platform: 'ios' } }));
118
+ first.abort();
119
+ await new Promise((r) => setTimeout(r, 50));
120
+ const secondLine = await postAllocateAndReadFirstLine(server.url, JSON.stringify({ criteria: { platform: 'ios' } }));
121
+ const second = JSON.parse(secondLine);
122
+ expect(second.deviceId).toBe('d1');
123
+ await postReleaseRequest(server.url, second.allocationId);
124
+ }
125
+ finally {
126
+ await server.stop();
127
+ }
128
+ });
129
+ test('POST /release with unknown allocationId returns 200 (idempotent)', async () => {
130
+ const pool = new DevicePool({
131
+ allocator: makeAllocator([]),
132
+ maxSlots: 1,
133
+ });
134
+ const server = await startServer(pool);
135
+ try {
136
+ const status = await postReleaseRequest(server.url, 'alloc-unknown');
137
+ expect(status).toBe(200);
138
+ }
139
+ finally {
140
+ await server.stop();
141
+ }
142
+ });
143
+ function postJson(url, path, body) {
144
+ return new Promise((resolve, reject) => {
145
+ const req = httpRequest(`${url}${path}`, { method: 'POST', headers: { 'content-type': 'application/json' } }, (res) => {
146
+ const chunks = [];
147
+ res.on('data', (c) => chunks.push(c));
148
+ res.on('end', () => resolve({
149
+ status: res.statusCode ?? 0,
150
+ body: Buffer.concat(chunks).toString('utf8'),
151
+ }));
152
+ });
153
+ req.on('error', reject);
154
+ req.write(JSON.stringify(body));
155
+ req.end();
156
+ });
157
+ }
158
+ test('/installed/is-installed and /installed/record round-trip', async () => {
159
+ const pool = new DevicePool({
160
+ allocator: makeAllocator([{ deviceId: 'd1', platform: 'ios' }]),
161
+ maxSlots: 1,
162
+ });
163
+ const server = await startServer(pool);
164
+ try {
165
+ const handleLine = await postAllocateAndReadFirstLine(server.url, JSON.stringify({ criteria: { platform: 'ios' } }));
166
+ const handle = JSON.parse(handleLine);
167
+ const before = await postJson(server.url, '/installed/is-installed', {
168
+ allocationId: handle.allocationId,
169
+ bundleId: 'app.ipa',
170
+ });
171
+ expect(JSON.parse(before.body).installed).toBe(false);
172
+ await postJson(server.url, '/installed/record', {
173
+ allocationId: handle.allocationId,
174
+ bundleId: 'app.ipa',
175
+ });
176
+ const after = await postJson(server.url, '/installed/is-installed', {
177
+ allocationId: handle.allocationId,
178
+ bundleId: 'app.ipa',
179
+ });
180
+ expect(JSON.parse(after.body).installed).toBe(true);
181
+ await postReleaseRequest(server.url, handle.allocationId);
182
+ }
183
+ finally {
184
+ await server.stop();
185
+ }
186
+ });
187
+ test('/shutdown drains the pool and rejects subsequent allocates', async () => {
188
+ const pool = new DevicePool({
189
+ allocator: makeAllocator([{ deviceId: 'd1', platform: 'ios' }]),
190
+ maxSlots: 1,
191
+ });
192
+ const server = await startServer(pool);
193
+ try {
194
+ const status = await postJson(server.url, '/shutdown', {});
195
+ expect(status.status).toBe(200);
196
+ const after = await postJson(server.url, '/allocate', { criteria: { platform: 'ios' } });
197
+ expect(after.status).toBe(503);
198
+ }
199
+ finally {
200
+ await server.stop();
201
+ }
202
+ });
203
+ //# sourceMappingURL=http-server.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-server.test.js","sourceRoot":"","sources":["../../../src/device-pool/adapters/http-server.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { MobileUseDriverOptions } from '@mobilewright/driver-mobile-use';
2
+ import type { AllocationCriteria, AllocateResult, DeviceAllocator } from '../application/ports.js';
3
+ export interface MobileUseAllocatorOptions {
4
+ driverOptions: MobileUseDriverOptions;
5
+ }
6
+ export declare class MobileUseAllocator implements DeviceAllocator {
7
+ private readonly driverOptions;
8
+ private readonly activeDrivers;
9
+ constructor(options: MobileUseAllocatorOptions);
10
+ allocate(criteria: AllocationCriteria): Promise<AllocateResult>;
11
+ release(deviceId: string): Promise<void>;
12
+ }
13
+ //# sourceMappingURL=mobile-use-allocator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mobile-use-allocator.d.ts","sourceRoot":"","sources":["../../../src/device-pool/adapters/mobile-use-allocator.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAC9E,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAInG,MAAM,WAAW,yBAAyB;IACxC,aAAa,EAAE,sBAAsB,CAAC;CACvC;AAED,qBAAa,kBAAmB,YAAW,eAAe;IACxD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAyB;IACvD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAsC;gBAExD,OAAO,EAAE,yBAAyB;IAIxC,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,cAAc,CAAC;IAa/D,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAS/C"}
@@ -0,0 +1,31 @@
1
+ import createDebug from 'debug';
2
+ import { MobileUseDriver } from '@mobilewright/driver-mobile-use';
3
+ const debug = createDebug('mw:device-pool:mobile-use');
4
+ export class MobileUseAllocator {
5
+ constructor(options) {
6
+ this.activeDrivers = new Map();
7
+ this.driverOptions = options.driverOptions;
8
+ }
9
+ async allocate(criteria) {
10
+ debug('allocating device (criteria=%o)', criteria);
11
+ const driver = new MobileUseDriver(this.driverOptions);
12
+ const session = await driver.connect({
13
+ platform: criteria.platform ?? 'ios',
14
+ deviceName: criteria.deviceNamePattern ? new RegExp(criteria.deviceNamePattern) : undefined,
15
+ deviceId: criteria.deviceId,
16
+ });
17
+ this.activeDrivers.set(session.deviceId, driver);
18
+ debug('allocated device %s (platform=%s)', session.deviceId, session.platform);
19
+ return { deviceId: session.deviceId, platform: session.platform };
20
+ }
21
+ async release(deviceId) {
22
+ debug('releasing device %s', deviceId);
23
+ const driver = this.activeDrivers.get(deviceId);
24
+ if (driver) {
25
+ this.activeDrivers.delete(deviceId);
26
+ await driver.disconnect();
27
+ debug('released device %s', deviceId);
28
+ }
29
+ }
30
+ }
31
+ //# sourceMappingURL=mobile-use-allocator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mobile-use-allocator.js","sourceRoot":"","sources":["../../../src/device-pool/adapters/mobile-use-allocator.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,OAAO,CAAC;AAChC,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAIlE,MAAM,KAAK,GAAG,WAAW,CAAC,2BAA2B,CAAC,CAAC;AAMvD,MAAM,OAAO,kBAAkB;IAI7B,YAAY,OAAkC;QAF7B,kBAAa,GAAG,IAAI,GAAG,EAA2B,CAAC;QAGlE,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,QAA4B;QACzC,KAAK,CAAC,iCAAiC,EAAE,QAAQ,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACvD,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC;YACnC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,IAAI,KAAK;YACpC,UAAU,EAAE,QAAQ,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,SAAS;YAC3F,QAAQ,EAAE,QAAQ,CAAC,QAAQ;SAC5B,CAAC,CAAC;QACH,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACjD,KAAK,CAAC,mCAAmC,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC/E,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC;IACpE,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,QAAgB;QAC5B,KAAK,CAAC,qBAAqB,EAAE,QAAQ,CAAC,CAAC;QACvC,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAChD,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YACpC,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;YAC1B,KAAK,CAAC,oBAAoB,EAAE,QAAQ,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,19 @@
1
+ import type { DeviceInfo, Platform } from '@mobilewright/protocol';
2
+ import type { AllocationCriteria, AllocateResult, DeviceAllocator } from '../application/ports.js';
3
+ interface ListDevicesOpts {
4
+ platform?: Platform;
5
+ }
6
+ interface ListDevicesDriver {
7
+ listDevices(opts?: ListDevicesOpts): Promise<DeviceInfo[]>;
8
+ }
9
+ export interface MobilecliAllocatorOptions {
10
+ driver: ListDevicesDriver;
11
+ }
12
+ export declare class MobilecliAllocator implements DeviceAllocator {
13
+ private readonly driver;
14
+ constructor(options: MobilecliAllocatorOptions);
15
+ allocate(criteria: AllocationCriteria, takenDeviceIds: ReadonlySet<string>): Promise<AllocateResult>;
16
+ release(_deviceId: string): Promise<void>;
17
+ }
18
+ export {};
19
+ //# sourceMappingURL=mobilecli-allocator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mobilecli-allocator.d.ts","sourceRoot":"","sources":["../../../src/device-pool/adapters/mobilecli-allocator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAEnE,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAEnG,UAAU,eAAe;IACvB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED,UAAU,iBAAiB;IACzB,WAAW,CAAC,IAAI,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;CAC5D;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,iBAAiB,CAAC;CAC3B;AAED,qBAAa,kBAAmB,YAAW,eAAe;IACxD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;gBAE/B,OAAO,EAAE,yBAAyB;IAIxC,QAAQ,CACZ,QAAQ,EAAE,kBAAkB,EAC5B,cAAc,EAAE,WAAW,CAAC,MAAM,CAAC,GAClC,OAAO,CAAC,cAAc,CAAC;IAwBpB,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGhD"}
@@ -0,0 +1,26 @@
1
+ import { NoDeviceAvailableError } from '../application/ports.js';
2
+ export class MobilecliAllocator {
3
+ constructor(options) {
4
+ this.driver = options.driver;
5
+ }
6
+ async allocate(criteria, takenDeviceIds) {
7
+ const devices = await this.driver.listDevices(criteria.platform ? { platform: criteria.platform } : undefined);
8
+ const namePattern = criteria.deviceNamePattern
9
+ ? new RegExp(criteria.deviceNamePattern)
10
+ : undefined;
11
+ const match = devices
12
+ .filter((d) => d.state === 'online')
13
+ .filter((d) => !takenDeviceIds.has(d.id))
14
+ .filter((d) => !criteria.deviceId || d.id === criteria.deviceId)
15
+ .filter((d) => !namePattern || namePattern.test(d.name))
16
+ .at(0);
17
+ if (!match) {
18
+ throw new NoDeviceAvailableError(`no online device available matching criteria ${JSON.stringify(criteria)}`);
19
+ }
20
+ return { deviceId: match.id, platform: match.platform };
21
+ }
22
+ async release(_deviceId) {
23
+ // mobilecli devices are local; nothing to release.
24
+ }
25
+ }
26
+ //# sourceMappingURL=mobilecli-allocator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mobilecli-allocator.js","sourceRoot":"","sources":["../../../src/device-pool/adapters/mobilecli-allocator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAejE,MAAM,OAAO,kBAAkB;IAG7B,YAAY,OAAkC;QAC5C,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,QAAQ,CACZ,QAA4B,EAC5B,cAAmC;QAEnC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,WAAW,CAC3C,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS,CAChE,CAAC;QAEF,MAAM,WAAW,GAAG,QAAQ,CAAC,iBAAiB;YAC5C,CAAC,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAC;YACxC,CAAC,CAAC,SAAS,CAAC;QAEd,MAAM,KAAK,GAAG,OAAO;aAClB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC;aACnC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;aACxC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,IAAI,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC,QAAQ,CAAC;aAC/D,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,WAAW,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;aACvD,EAAE,CAAC,CAAC,CAAC,CAAC;QAET,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,sBAAsB,CAC9B,gDAAgD,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAC3E,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;IAC1D,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,SAAiB;QAC7B,mDAAmD;IACrD,CAAC;CACF"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=mobilecli-allocator.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mobilecli-allocator.test.d.ts","sourceRoot":"","sources":["../../../src/device-pool/adapters/mobilecli-allocator.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,61 @@
1
+ import { test, expect } from '@playwright/test';
2
+ import { MobilecliAllocator } from './mobilecli-allocator.js';
3
+ import { NoDeviceAvailableError } from '../application/ports.js';
4
+ function makeFakeDriver(devices) {
5
+ return {
6
+ async listDevices() {
7
+ return devices;
8
+ },
9
+ };
10
+ }
11
+ test('allocates the first online device matching platform', async () => {
12
+ const driver = makeFakeDriver([
13
+ { id: 'a', name: 'iPhone 14', platform: 'ios', type: 'simulator', state: 'online' },
14
+ { id: 'b', name: 'iPhone 16', platform: 'ios', type: 'simulator', state: 'online' },
15
+ ]);
16
+ const allocator = new MobilecliAllocator({ driver });
17
+ const result = await allocator.allocate({ platform: 'ios' }, new Set());
18
+ expect(result.deviceId).toBe('a');
19
+ expect(result.platform).toBe('ios');
20
+ });
21
+ test('skips devices that are already taken', async () => {
22
+ const driver = makeFakeDriver([
23
+ { id: 'a', name: 'iPhone 14', platform: 'ios', type: 'simulator', state: 'online' },
24
+ { id: 'b', name: 'iPhone 16', platform: 'ios', type: 'simulator', state: 'online' },
25
+ ]);
26
+ const allocator = new MobilecliAllocator({ driver });
27
+ const result = await allocator.allocate({ platform: 'ios' }, new Set(['a']));
28
+ expect(result.deviceId).toBe('b');
29
+ });
30
+ test('filters by deviceNamePattern', async () => {
31
+ const driver = makeFakeDriver([
32
+ { id: 'a', name: 'iPhone 14', platform: 'ios', type: 'simulator', state: 'online' },
33
+ { id: 'b', name: 'iPhone 16', platform: 'ios', type: 'simulator', state: 'online' },
34
+ ]);
35
+ const allocator = new MobilecliAllocator({ driver });
36
+ const result = await allocator.allocate({ platform: 'ios', deviceNamePattern: 'iPhone 16' }, new Set());
37
+ expect(result.deviceId).toBe('b');
38
+ });
39
+ test('filters by exact deviceId', async () => {
40
+ const driver = makeFakeDriver([
41
+ { id: 'a', name: 'iPhone 14', platform: 'ios', type: 'simulator', state: 'online' },
42
+ { id: 'b', name: 'iPhone 16', platform: 'ios', type: 'simulator', state: 'online' },
43
+ ]);
44
+ const allocator = new MobilecliAllocator({ driver });
45
+ const result = await allocator.allocate({ platform: 'ios', deviceId: 'b' }, new Set());
46
+ expect(result.deviceId).toBe('b');
47
+ });
48
+ test('throws NoDeviceAvailableError when no device matches', async () => {
49
+ const driver = makeFakeDriver([
50
+ { id: 'a', name: 'iPhone 14', platform: 'ios', type: 'simulator', state: 'offline' },
51
+ ]);
52
+ const allocator = new MobilecliAllocator({ driver });
53
+ const err = await allocator.allocate({ platform: 'ios' }, new Set()).catch((e) => e);
54
+ expect(err).toBeInstanceOf(NoDeviceAvailableError);
55
+ });
56
+ test('release is a no-op for local devices', async () => {
57
+ const driver = makeFakeDriver([]);
58
+ const allocator = new MobilecliAllocator({ driver });
59
+ await expect(allocator.release('whatever')).resolves.toBeUndefined();
60
+ });
61
+ //# sourceMappingURL=mobilecli-allocator.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mobilecli-allocator.test.js","sourceRoot":"","sources":["../../../src/device-pool/adapters/mobilecli-allocator.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAEhD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAMjE,SAAS,cAAc,CAAC,OAAqB;IAC3C,OAAO;QACL,KAAK,CAAC,WAAW;YACf,OAAO,OAAO,CAAC;QACjB,CAAC;KACF,CAAC;AACJ,CAAC;AAED,IAAI,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;IACrE,MAAM,MAAM,GAAG,cAAc,CAAC;QAC5B,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE;QACnF,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE;KACpF,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,IAAI,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IAErD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;IAExE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAClC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACtC,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;IACtD,MAAM,MAAM,GAAG,cAAc,CAAC;QAC5B,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE;QACnF,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE;KACpF,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,IAAI,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IAErD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAE7E,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACpC,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;IAC9C,MAAM,MAAM,GAAG,cAAc,CAAC;QAC5B,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE;QACnF,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE;KACpF,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,IAAI,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IAErD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,QAAQ,CACrC,EAAE,QAAQ,EAAE,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,EACnD,IAAI,GAAG,EAAE,CACV,CAAC;IAEF,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACpC,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;IAC3C,MAAM,MAAM,GAAG,cAAc,CAAC;QAC5B,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE;QACnF,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE;KACpF,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,IAAI,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IAErD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,QAAQ,CACrC,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,EAClC,IAAI,GAAG,EAAE,CACV,CAAC;IAEF,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACpC,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;IACtE,MAAM,MAAM,GAAG,cAAc,CAAC;QAC5B,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE;KACrF,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,IAAI,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IAErD,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAU,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IAC9F,MAAM,CAAC,GAAG,CAAC,CAAC,cAAc,CAAC,sBAAsB,CAAC,CAAC;AACrD,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;IACtD,MAAM,MAAM,GAAG,cAAc,CAAC,EAAE,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,IAAI,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IACrD,MAAM,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;AACvE,CAAC,CAAC,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { MobilewrightConfig } from '../config.js';
2
+ import type { DeviceAllocator } from './application/ports.js';
3
+ export interface AllocatorResult {
4
+ allocator: DeviceAllocator;
5
+ serverProcess?: {
6
+ kill: () => void;
7
+ };
8
+ }
9
+ export declare function createAllocator(config: MobilewrightConfig): Promise<AllocatorResult>;
10
+ //# sourceMappingURL=allocator-factory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"allocator-factory.d.ts","sourceRoot":"","sources":["../../src/device-pool/allocator-factory.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAyB,MAAM,cAAc,CAAC;AAC9E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,eAAe,CAAC;IAC3B,aAAa,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;CACtC;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,eAAe,CAAC,CAsB1F"}
@@ -0,0 +1,25 @@
1
+ import { DEFAULT_URL, MobilecliDriver } from '@mobilewright/driver-mobilecli';
2
+ import { ensureMobilecliReachable } from '../server.js';
3
+ import { MobilecliAllocator } from './adapters/mobilecli-allocator.js';
4
+ import { MobileUseAllocator } from './adapters/mobile-use-allocator.js';
5
+ export async function createAllocator(config) {
6
+ const driverType = config.driver?.type ?? 'mobilecli';
7
+ if (driverType === 'mobilecli') {
8
+ const url = config.url ?? DEFAULT_URL;
9
+ const ensured = await ensureMobilecliReachable(url, { autoStart: config.autoStart ?? true });
10
+ const allocator = new MobilecliAllocator({ driver: new MobilecliDriver({ url }) });
11
+ return { allocator, serverProcess: ensured.serverProcess ?? undefined };
12
+ }
13
+ if (driverType === 'mobile-use') {
14
+ const mobileUseConfig = config.driver;
15
+ const allocator = new MobileUseAllocator({
16
+ driverOptions: {
17
+ region: mobileUseConfig.region,
18
+ apiKey: mobileUseConfig.apiKey,
19
+ },
20
+ });
21
+ return { allocator };
22
+ }
23
+ throw new Error(`Unsupported driver type: "${driverType}". Supported types: "mobilecli", "mobile-use".`);
24
+ }
25
+ //# sourceMappingURL=allocator-factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"allocator-factory.js","sourceRoot":"","sources":["../../src/device-pool/allocator-factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAC9E,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AASxE,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAA0B;IAC9D,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,IAAI,WAAW,CAAC;IAEtD,IAAI,UAAU,KAAK,WAAW,EAAE,CAAC;QAC/B,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,IAAI,WAAW,CAAC;QACtC,MAAM,OAAO,GAAG,MAAM,wBAAwB,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,IAAI,EAAE,CAAC,CAAC;QAC7F,MAAM,SAAS,GAAG,IAAI,kBAAkB,CAAC,EAAE,MAAM,EAAE,IAAI,eAAe,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QACnF,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,OAAO,CAAC,aAAa,IAAI,SAAS,EAAE,CAAC;IAC1E,CAAC;IAED,IAAI,UAAU,KAAK,YAAY,EAAE,CAAC;QAChC,MAAM,eAAe,GAAG,MAAM,CAAC,MAA+B,CAAC;QAC/D,MAAM,SAAS,GAAG,IAAI,kBAAkB,CAAC;YACvC,aAAa,EAAE;gBACb,MAAM,EAAE,eAAe,CAAC,MAAM;gBAC9B,MAAM,EAAE,eAAe,CAAC,MAAM;aAC/B;SACF,CAAC,CAAC;QACH,OAAO,EAAE,SAAS,EAAE,CAAC;IACvB,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,6BAA6B,UAAU,gDAAgD,CAAC,CAAC;AAC3G,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type { AllocationCriteria, AllocationHandle, DeviceAllocator } from './ports.js';
2
+ export interface DevicePoolOptions {
3
+ allocator: DeviceAllocator;
4
+ maxSlots: number;
5
+ /** Per-allocation timeout in ms. Default 600_000 (10 min). */
6
+ allocationTimeoutMs?: number;
7
+ }
8
+ export declare class DevicePool {
9
+ private readonly allocator;
10
+ private readonly maxSlots;
11
+ private readonly allocationTimeoutMs;
12
+ private readonly slots;
13
+ private readonly allocations;
14
+ private readonly waiters;
15
+ private readonly inFlightWaiters;
16
+ private isShutdown;
17
+ constructor(options: DevicePoolOptions);
18
+ allocate(criteria: AllocationCriteria): Promise<AllocationHandle>;
19
+ shutdown(): Promise<void>;
20
+ release(allocationId: string): Promise<void>;
21
+ recordAppInstalled(allocationId: string, bundleId: string): void;
22
+ isAppInstalled(allocationId: string, bundleId: string): boolean;
23
+ private pump;
24
+ private findFreeSlot;
25
+ private grantSlot;
26
+ private startAllocationForWaiter;
27
+ private takenDeviceIds;
28
+ }
29
+ //# sourceMappingURL=device-pool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device-pool.d.ts","sourceRoot":"","sources":["../../../src/device-pool/application/device-pool.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EAChB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,eAAe,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,8DAA8D;IAC9D,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAQD,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkB;IAC5C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IAC7C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoB;IAC1C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAiC;IAC7D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IACxC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqB;IACrD,OAAO,CAAC,UAAU,CAAS;gBAEf,OAAO,EAAE,iBAAiB;IAMtC,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAU3D,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAwBzB,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUlD,kBAAkB,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAQhE,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO;IAQ/D,OAAO,CAAC,IAAI;IAkBZ,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,SAAS;YAkBH,wBAAwB;IAwDtC,OAAO,CAAC,cAAc;CAOvB"}