@evolu/react-native 16.0.0 → 16.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/LockManager.d.ts.map +1 -1
- package/dist/src/LockManager.js +2 -0
- package/dist/src/Polyfills.d.ts.map +1 -1
- package/dist/src/Polyfills.js +7 -2
- package/dist/src/Task.d.ts +2 -1
- package/dist/src/Task.d.ts.map +1 -1
- package/dist/src/Task.js +5 -2
- package/dist/src/components/EvoluIdenticon.js +2 -2
- package/dist/src/sqlite-drivers/createExpoSqliteDriver.d.ts.map +1 -1
- package/dist/src/sqlite-drivers/createExpoSqliteDriver.js +1 -0
- package/package.json +8 -6
- package/src/ErrorUtils.d.ts +2 -1
- package/src/LockManager.test.ts +537 -0
- package/src/LockManager.ts +2 -0
- package/src/Polyfills.test.ts +623 -0
- package/src/Polyfills.ts +7 -2
- package/src/Task.test.ts +82 -0
- package/src/Task.ts +8 -3
- package/src/components/EvoluIdenticon.tsx +2 -2
- package/src/shared.ts +1 -1
- package/src/sqlite-drivers/createExpoSqliteDriver.ts +5 -1
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assertEqual,
|
|
3
|
+
assertRejectsInstanceOf,
|
|
4
|
+
assertRejectsSame,
|
|
5
|
+
testName,
|
|
6
|
+
} from "@evolu/common";
|
|
7
|
+
import { describe, it } from "node:test";
|
|
8
|
+
import { lockManager } from "./LockManager.ts";
|
|
9
|
+
|
|
10
|
+
const assertRejectsWithName = async (
|
|
11
|
+
promise: PromiseLike<unknown>,
|
|
12
|
+
name: string,
|
|
13
|
+
): Promise<void> => {
|
|
14
|
+
const error = await assertRejectsInstanceOf(promise, Error);
|
|
15
|
+
assertEqual(error.name, name);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
describe("lockManager", () => {
|
|
19
|
+
describe("request", () => {
|
|
20
|
+
it("holds an exclusive lock until the callback settles", async () => {
|
|
21
|
+
const first = Promise.withResolvers<void>();
|
|
22
|
+
|
|
23
|
+
let secondStarted = false;
|
|
24
|
+
|
|
25
|
+
const firstRequest = lockManager.request(testName, async (lock) => {
|
|
26
|
+
assertEqual(lock, { mode: "exclusive", name: testName });
|
|
27
|
+
await first.promise;
|
|
28
|
+
return "first";
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const secondRequest = lockManager.request(testName, (lock) => {
|
|
32
|
+
assertEqual(lock, { mode: "exclusive", name: testName });
|
|
33
|
+
secondStarted = true;
|
|
34
|
+
return "second";
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
assertEqual(secondStarted, false);
|
|
38
|
+
|
|
39
|
+
first.resolve();
|
|
40
|
+
|
|
41
|
+
assertEqual(await firstRequest, "first");
|
|
42
|
+
assertEqual(await secondRequest, "second");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("grants compatible shared requests before a queued exclusive request", async () => {
|
|
46
|
+
const releaseShared = Promise.withResolvers<void>();
|
|
47
|
+
const steps: Array<string> = [];
|
|
48
|
+
|
|
49
|
+
const firstSharedRequest = lockManager.request(
|
|
50
|
+
testName,
|
|
51
|
+
{ mode: "shared" },
|
|
52
|
+
async (lock) => {
|
|
53
|
+
assertEqual(lock, { mode: "shared", name: testName });
|
|
54
|
+
steps.push("shared-1-start");
|
|
55
|
+
await releaseShared.promise;
|
|
56
|
+
steps.push("shared-1-end");
|
|
57
|
+
return "shared-1";
|
|
58
|
+
},
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
const exclusiveRequest = lockManager.request(testName, (lock) => {
|
|
62
|
+
assertEqual(lock, { mode: "exclusive", name: testName });
|
|
63
|
+
steps.push("exclusive-start");
|
|
64
|
+
return "exclusive";
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const secondSharedRequest = lockManager.request(
|
|
68
|
+
testName,
|
|
69
|
+
{ mode: "shared" },
|
|
70
|
+
(lock) => {
|
|
71
|
+
assertEqual(lock, { mode: "shared", name: testName });
|
|
72
|
+
steps.push("shared-2-start");
|
|
73
|
+
return "shared-2";
|
|
74
|
+
},
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
await Promise.resolve();
|
|
78
|
+
|
|
79
|
+
assertEqual(steps, ["shared-1-start"]);
|
|
80
|
+
|
|
81
|
+
releaseShared.resolve();
|
|
82
|
+
|
|
83
|
+
assertEqual(await firstSharedRequest, "shared-1");
|
|
84
|
+
assertEqual(await exclusiveRequest, "exclusive");
|
|
85
|
+
assertEqual(await secondSharedRequest, "shared-2");
|
|
86
|
+
assertEqual(steps, [
|
|
87
|
+
"shared-1-start",
|
|
88
|
+
"shared-1-end",
|
|
89
|
+
"exclusive-start",
|
|
90
|
+
"shared-2-start",
|
|
91
|
+
]);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("grants compatible shared requests together when no exclusive request blocks them", async () => {
|
|
95
|
+
const releaseShared = Promise.withResolvers<void>();
|
|
96
|
+
const steps: Array<string> = [];
|
|
97
|
+
|
|
98
|
+
const firstSharedRequest = lockManager.request(
|
|
99
|
+
testName,
|
|
100
|
+
{ mode: "shared" },
|
|
101
|
+
async (lock) => {
|
|
102
|
+
assertEqual(lock, { mode: "shared", name: testName });
|
|
103
|
+
steps.push("shared-1-start");
|
|
104
|
+
await releaseShared.promise;
|
|
105
|
+
return "shared-1";
|
|
106
|
+
},
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
const secondSharedRequest = lockManager.request(
|
|
110
|
+
testName,
|
|
111
|
+
{ mode: "shared" },
|
|
112
|
+
async (lock) => {
|
|
113
|
+
assertEqual(lock, { mode: "shared", name: testName });
|
|
114
|
+
steps.push("shared-2-start");
|
|
115
|
+
await releaseShared.promise;
|
|
116
|
+
return "shared-2";
|
|
117
|
+
},
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
await Promise.resolve();
|
|
121
|
+
|
|
122
|
+
assertEqual(steps, ["shared-1-start", "shared-2-start"]);
|
|
123
|
+
|
|
124
|
+
releaseShared.resolve();
|
|
125
|
+
|
|
126
|
+
assertEqual(await firstSharedRequest, "shared-1");
|
|
127
|
+
assertEqual(await secondSharedRequest, "shared-2");
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("invokes the callback with null asynchronously when ifAvailable cannot grant immediately", async () => {
|
|
131
|
+
const first = Promise.withResolvers<void>();
|
|
132
|
+
let secondCallbackCalled = false;
|
|
133
|
+
|
|
134
|
+
const firstRequest = lockManager.request(testName, async (lock) => {
|
|
135
|
+
assertEqual(lock, { mode: "exclusive", name: testName });
|
|
136
|
+
await first.promise;
|
|
137
|
+
return "first";
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const secondRequest = lockManager.request(
|
|
141
|
+
testName,
|
|
142
|
+
{ ifAvailable: true },
|
|
143
|
+
(lock) => {
|
|
144
|
+
secondCallbackCalled = true;
|
|
145
|
+
assertEqual(lock, null);
|
|
146
|
+
return "unavailable";
|
|
147
|
+
},
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
assertEqual(secondCallbackCalled, false);
|
|
151
|
+
|
|
152
|
+
assertEqual(await secondRequest, "unavailable");
|
|
153
|
+
|
|
154
|
+
first.resolve();
|
|
155
|
+
assertEqual(await firstRequest, "first");
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("grants an exclusive ifAvailable request immediately when the name is free", async () => {
|
|
159
|
+
assertEqual(
|
|
160
|
+
await lockManager.request(testName, { ifAvailable: true }, (lock) => {
|
|
161
|
+
assertEqual(lock, { mode: "exclusive", name: testName });
|
|
162
|
+
return "granted";
|
|
163
|
+
}),
|
|
164
|
+
"granted",
|
|
165
|
+
);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it("invokes the callback with null when ifAvailable sees a queued request", async () => {
|
|
169
|
+
const releaseFirst = Promise.withResolvers<void>();
|
|
170
|
+
|
|
171
|
+
const firstRequest = lockManager.request(testName, async (lock) => {
|
|
172
|
+
assertEqual(lock, { mode: "exclusive", name: testName });
|
|
173
|
+
await releaseFirst.promise;
|
|
174
|
+
return "first";
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
const queuedRequest = lockManager.request(testName, (lock) => {
|
|
178
|
+
assertEqual(lock, { mode: "exclusive", name: testName });
|
|
179
|
+
return "queued";
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
const ifAvailableResult = await lockManager.request(
|
|
183
|
+
testName,
|
|
184
|
+
{ ifAvailable: true },
|
|
185
|
+
(lock) => {
|
|
186
|
+
assertEqual(lock, null);
|
|
187
|
+
return "unavailable";
|
|
188
|
+
},
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
assertEqual(ifAvailableResult, "unavailable");
|
|
192
|
+
|
|
193
|
+
releaseFirst.resolve();
|
|
194
|
+
assertEqual(await firstRequest, "first");
|
|
195
|
+
assertEqual(await queuedRequest, "queued");
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it("grants a shared ifAvailable request when shared locks already hold the name", async () => {
|
|
199
|
+
const releaseShared = Promise.withResolvers<void>();
|
|
200
|
+
|
|
201
|
+
const firstSharedRequest = lockManager.request(
|
|
202
|
+
testName,
|
|
203
|
+
{ mode: "shared" },
|
|
204
|
+
async (lock) => {
|
|
205
|
+
assertEqual(lock, { mode: "shared", name: testName });
|
|
206
|
+
await releaseShared.promise;
|
|
207
|
+
return "shared-1";
|
|
208
|
+
},
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
const secondSharedResult = await lockManager.request(
|
|
212
|
+
testName,
|
|
213
|
+
{ ifAvailable: true, mode: "shared" },
|
|
214
|
+
(lock) => {
|
|
215
|
+
assertEqual(lock, { mode: "shared", name: testName });
|
|
216
|
+
return "shared-2";
|
|
217
|
+
},
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
assertEqual(secondSharedResult, "shared-2");
|
|
221
|
+
|
|
222
|
+
releaseShared.resolve();
|
|
223
|
+
assertEqual(await firstSharedRequest, "shared-1");
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it("rejects with the abort reason when the signal is already aborted", async () => {
|
|
227
|
+
const controller = new AbortController();
|
|
228
|
+
controller.abort(
|
|
229
|
+
new DOMException("The request was aborted.", "AbortError"),
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
await assertRejectsWithName(
|
|
233
|
+
lockManager.request(
|
|
234
|
+
testName,
|
|
235
|
+
{ signal: controller.signal },
|
|
236
|
+
() => "unreachable",
|
|
237
|
+
),
|
|
238
|
+
"AbortError",
|
|
239
|
+
);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it("rejects a queued request when its signal aborts before grant", async () => {
|
|
243
|
+
const releaseFirst = Promise.withResolvers<void>();
|
|
244
|
+
const controller = new AbortController();
|
|
245
|
+
|
|
246
|
+
const firstRequest = lockManager.request(testName, async (lock) => {
|
|
247
|
+
assertEqual(lock, { mode: "exclusive", name: testName });
|
|
248
|
+
await releaseFirst.promise;
|
|
249
|
+
return "first";
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
const secondRequest = lockManager.request(
|
|
253
|
+
testName,
|
|
254
|
+
{ signal: controller.signal },
|
|
255
|
+
() => "second",
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
controller.abort(
|
|
259
|
+
new DOMException("The request was aborted.", "AbortError"),
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
await assertRejectsWithName(secondRequest, "AbortError");
|
|
263
|
+
|
|
264
|
+
releaseFirst.resolve();
|
|
265
|
+
assertEqual(await firstRequest, "first");
|
|
266
|
+
assertEqual(await lockManager.query(), {
|
|
267
|
+
held: [],
|
|
268
|
+
pending: [],
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
it("does not invoke the callback when the signal aborts after grant but before callback starts", async () => {
|
|
273
|
+
const controller = new AbortController();
|
|
274
|
+
let callbackCalled = false;
|
|
275
|
+
|
|
276
|
+
const request = lockManager.request(
|
|
277
|
+
testName,
|
|
278
|
+
{ signal: controller.signal },
|
|
279
|
+
(lock) => {
|
|
280
|
+
callbackCalled = true;
|
|
281
|
+
assertEqual(lock, { mode: "exclusive", name: testName });
|
|
282
|
+
return "granted";
|
|
283
|
+
},
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
controller.abort(
|
|
287
|
+
new DOMException("The request was aborted.", "AbortError"),
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
await assertRejectsWithName(request, "AbortError");
|
|
291
|
+
assertEqual(callbackCalled, false);
|
|
292
|
+
|
|
293
|
+
assertEqual(
|
|
294
|
+
await lockManager.request(testName, (lock) => {
|
|
295
|
+
assertEqual(lock, { mode: "exclusive", name: testName });
|
|
296
|
+
return "next";
|
|
297
|
+
}),
|
|
298
|
+
"next",
|
|
299
|
+
);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it("ignores signal aborts after the lock has been granted", async () => {
|
|
303
|
+
const controller = new AbortController();
|
|
304
|
+
|
|
305
|
+
const result = await lockManager.request(
|
|
306
|
+
testName,
|
|
307
|
+
{ signal: controller.signal },
|
|
308
|
+
(lock) => {
|
|
309
|
+
assertEqual(lock, { mode: "exclusive", name: testName });
|
|
310
|
+
controller.abort(
|
|
311
|
+
new DOMException("The request was aborted.", "AbortError"),
|
|
312
|
+
);
|
|
313
|
+
return "granted";
|
|
314
|
+
},
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
assertEqual(result, "granted");
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
it("releases the lock when the callback throws", async () => {
|
|
321
|
+
const error = new Error("boom");
|
|
322
|
+
|
|
323
|
+
const firstRequest = lockManager.request(testName, () => {
|
|
324
|
+
throw error;
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
const secondRequest = lockManager.request(testName, (lock) => {
|
|
328
|
+
assertEqual(lock, { mode: "exclusive", name: testName });
|
|
329
|
+
return "second";
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
await assertRejectsSame(firstRequest, error);
|
|
333
|
+
assertEqual(await secondRequest, "second");
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
it("rejects names starting with a hyphen", async () => {
|
|
337
|
+
await assertRejectsWithName(
|
|
338
|
+
lockManager.request("-reserved", () => "unreachable"),
|
|
339
|
+
"NotSupportedError",
|
|
340
|
+
);
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
it("rejects using ifAvailable together with steal", async () => {
|
|
344
|
+
await assertRejectsWithName(
|
|
345
|
+
lockManager.request(
|
|
346
|
+
testName,
|
|
347
|
+
{ ifAvailable: true, steal: true },
|
|
348
|
+
() => "unreachable",
|
|
349
|
+
),
|
|
350
|
+
"NotSupportedError",
|
|
351
|
+
);
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
it("rejects using steal with shared mode", async () => {
|
|
355
|
+
await assertRejectsWithName(
|
|
356
|
+
lockManager.request(
|
|
357
|
+
testName,
|
|
358
|
+
{ mode: "shared", steal: true },
|
|
359
|
+
() => "unreachable",
|
|
360
|
+
),
|
|
361
|
+
"NotSupportedError",
|
|
362
|
+
);
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
it("rejects using signal with ifAvailable", async () => {
|
|
366
|
+
const controller = new AbortController();
|
|
367
|
+
|
|
368
|
+
await assertRejectsWithName(
|
|
369
|
+
lockManager.request(
|
|
370
|
+
testName,
|
|
371
|
+
{ ifAvailable: true, signal: controller.signal },
|
|
372
|
+
() => "unreachable",
|
|
373
|
+
),
|
|
374
|
+
"NotSupportedError",
|
|
375
|
+
);
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
it("rejects using signal with steal", async () => {
|
|
379
|
+
const controller = new AbortController();
|
|
380
|
+
|
|
381
|
+
await assertRejectsWithName(
|
|
382
|
+
lockManager.request(
|
|
383
|
+
testName,
|
|
384
|
+
{ signal: controller.signal, steal: true },
|
|
385
|
+
() => "unreachable",
|
|
386
|
+
),
|
|
387
|
+
"NotSupportedError",
|
|
388
|
+
);
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
it("steal preempts held and queued requests for the same name", async () => {
|
|
392
|
+
const releaseFirst = Promise.withResolvers<void>();
|
|
393
|
+
const steps: Array<string> = [];
|
|
394
|
+
|
|
395
|
+
const firstRequest = lockManager.request(testName, async (lock) => {
|
|
396
|
+
assertEqual(lock, { mode: "exclusive", name: testName });
|
|
397
|
+
steps.push("first-start");
|
|
398
|
+
await releaseFirst.promise;
|
|
399
|
+
steps.push("first-end");
|
|
400
|
+
return "first";
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
const queuedRequest = lockManager.request(testName, () => {
|
|
404
|
+
steps.push("queued-start");
|
|
405
|
+
return "queued";
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
const stolenRequest = lockManager.request(
|
|
409
|
+
testName,
|
|
410
|
+
{ steal: true },
|
|
411
|
+
(lock) => {
|
|
412
|
+
assertEqual(lock, { mode: "exclusive", name: testName });
|
|
413
|
+
steps.push("steal-start");
|
|
414
|
+
return "steal";
|
|
415
|
+
},
|
|
416
|
+
);
|
|
417
|
+
|
|
418
|
+
await assertRejectsWithName(firstRequest, "AbortError");
|
|
419
|
+
assertEqual(await stolenRequest, "steal");
|
|
420
|
+
|
|
421
|
+
assertEqual(steps, ["first-start", "steal-start", "queued-start"]);
|
|
422
|
+
|
|
423
|
+
releaseFirst.resolve();
|
|
424
|
+
|
|
425
|
+
assertEqual(await queuedRequest, "queued");
|
|
426
|
+
assertEqual(steps, [
|
|
427
|
+
"first-start",
|
|
428
|
+
"steal-start",
|
|
429
|
+
"queued-start",
|
|
430
|
+
"first-end",
|
|
431
|
+
]);
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
it("steal behaves like a normal exclusive request when nothing is held", async () => {
|
|
435
|
+
assertEqual(
|
|
436
|
+
await lockManager.request(testName, { steal: true }, (lock) => {
|
|
437
|
+
assertEqual(lock, { mode: "exclusive", name: testName });
|
|
438
|
+
return "steal";
|
|
439
|
+
}),
|
|
440
|
+
"steal",
|
|
441
|
+
);
|
|
442
|
+
});
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
describe("query", () => {
|
|
446
|
+
it("returns held and pending arrays in the snapshot", async () => {
|
|
447
|
+
const releaseLock = Promise.withResolvers<void>();
|
|
448
|
+
|
|
449
|
+
const firstRequest = lockManager.request(testName, async (lock) => {
|
|
450
|
+
assertEqual(lock, { mode: "exclusive", name: testName });
|
|
451
|
+
await releaseLock.promise;
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
const secondRequest = lockManager.request(testName, () => undefined);
|
|
455
|
+
|
|
456
|
+
await Promise.resolve();
|
|
457
|
+
|
|
458
|
+
assertEqual(await lockManager.query(), {
|
|
459
|
+
held: [
|
|
460
|
+
{
|
|
461
|
+
clientId: "react-native-main-thread",
|
|
462
|
+
mode: "exclusive",
|
|
463
|
+
name: testName,
|
|
464
|
+
},
|
|
465
|
+
],
|
|
466
|
+
pending: [
|
|
467
|
+
{
|
|
468
|
+
clientId: "react-native-main-thread",
|
|
469
|
+
mode: "exclusive",
|
|
470
|
+
name: testName,
|
|
471
|
+
},
|
|
472
|
+
],
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
releaseLock.resolve();
|
|
476
|
+
await firstRequest;
|
|
477
|
+
await secondRequest;
|
|
478
|
+
|
|
479
|
+
assertEqual(await lockManager.query(), {
|
|
480
|
+
held: [],
|
|
481
|
+
pending: [],
|
|
482
|
+
});
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
it("preserves pending request order for the same resource", async () => {
|
|
486
|
+
const releaseLock = Promise.withResolvers<void>();
|
|
487
|
+
|
|
488
|
+
const firstRequest = lockManager.request(testName, async (lock) => {
|
|
489
|
+
assertEqual(lock, { mode: "exclusive", name: testName });
|
|
490
|
+
await releaseLock.promise;
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
const secondRequest = lockManager.request(
|
|
494
|
+
testName,
|
|
495
|
+
{ mode: "shared" },
|
|
496
|
+
(lock) => {
|
|
497
|
+
assertEqual(lock, { mode: "shared", name: testName });
|
|
498
|
+
return "second";
|
|
499
|
+
},
|
|
500
|
+
);
|
|
501
|
+
|
|
502
|
+
const thirdRequest = lockManager.request(testName, (lock) => {
|
|
503
|
+
assertEqual(lock, { mode: "exclusive", name: testName });
|
|
504
|
+
return "third";
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
await Promise.resolve();
|
|
508
|
+
|
|
509
|
+
assertEqual(await lockManager.query(), {
|
|
510
|
+
held: [
|
|
511
|
+
{
|
|
512
|
+
clientId: "react-native-main-thread",
|
|
513
|
+
mode: "exclusive",
|
|
514
|
+
name: testName,
|
|
515
|
+
},
|
|
516
|
+
],
|
|
517
|
+
pending: [
|
|
518
|
+
{
|
|
519
|
+
clientId: "react-native-main-thread",
|
|
520
|
+
mode: "shared",
|
|
521
|
+
name: testName,
|
|
522
|
+
},
|
|
523
|
+
{
|
|
524
|
+
clientId: "react-native-main-thread",
|
|
525
|
+
mode: "exclusive",
|
|
526
|
+
name: testName,
|
|
527
|
+
},
|
|
528
|
+
],
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
releaseLock.resolve();
|
|
532
|
+
assertEqual(await firstRequest, undefined);
|
|
533
|
+
assertEqual(await secondRequest, "second");
|
|
534
|
+
assertEqual(await thirdRequest, "third");
|
|
535
|
+
});
|
|
536
|
+
});
|
|
537
|
+
});
|
package/src/LockManager.ts
CHANGED
|
@@ -91,6 +91,7 @@ const createLockManagerPonyfill = ({
|
|
|
91
91
|
);
|
|
92
92
|
pendingRequest.phase = "running";
|
|
93
93
|
|
|
94
|
+
// oxlint-disable-next-line unicorn/no-useless-promise-resolve-reject -- Normalizes generic T to Awaited<T> for the lock request contract.
|
|
94
95
|
return Promise.resolve(
|
|
95
96
|
pendingRequest.callback({ mode: pendingRequest.mode, name }),
|
|
96
97
|
);
|
|
@@ -205,6 +206,7 @@ const createLockManagerPonyfill = ({
|
|
|
205
206
|
}
|
|
206
207
|
|
|
207
208
|
if (options.ifAvailable && !canGrantImmediately(name, mode)) {
|
|
209
|
+
// oxlint-disable-next-line unicorn/no-useless-promise-resolve-reject -- Normalizes generic T to Awaited<T> for the lock request contract.
|
|
208
210
|
return Promise.resolve().then(() => Promise.resolve(callback(null)));
|
|
209
211
|
}
|
|
210
212
|
|