@evolu/react-native 14.3.0 → 15.0.0-next.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/README.md +3 -3
- package/dist/src/LockManager.d.ts +13 -0
- package/dist/src/LockManager.d.ts.map +1 -0
- package/dist/src/LockManager.js +219 -0
- package/dist/src/Polyfills.d.ts +3 -0
- package/dist/src/Polyfills.d.ts.map +1 -0
- package/dist/src/Polyfills.js +209 -0
- package/dist/src/Task.d.ts +31 -0
- package/dist/src/Task.d.ts.map +1 -0
- package/dist/src/Task.js +46 -0
- package/dist/src/components/EvoluIdenticon.d.ts +9 -0
- package/dist/src/components/EvoluIdenticon.d.ts.map +1 -0
- package/dist/{components → src/components}/EvoluIdenticon.js +1 -1
- package/dist/src/createExpoDeps.d.ts +1 -0
- package/dist/src/createExpoDeps.d.ts.map +1 -0
- package/dist/src/createExpoDeps.js +163 -0
- package/dist/src/exports/bare-op-sqlite.d.ts +1 -0
- package/dist/src/exports/bare-op-sqlite.d.ts.map +1 -0
- package/dist/src/exports/bare-op-sqlite.js +31 -0
- package/dist/src/exports/expo-op-sqlite.d.ts +1 -0
- package/dist/src/exports/expo-op-sqlite.d.ts.map +1 -0
- package/dist/src/exports/expo-op-sqlite.js +16 -0
- package/dist/src/exports/expo-sqlite.d.ts +11 -0
- package/dist/src/exports/expo-sqlite.d.ts.map +1 -0
- package/dist/src/exports/expo-sqlite.js +24 -0
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +3 -0
- package/dist/src/shared.d.ts +5 -0
- package/dist/src/shared.d.ts.map +1 -0
- package/dist/src/shared.js +90 -0
- package/dist/src/sqlite-drivers/createExpoSqliteDriver.d.ts +3 -0
- package/dist/src/sqlite-drivers/createExpoSqliteDriver.d.ts.map +1 -0
- package/dist/src/sqlite-drivers/createExpoSqliteDriver.js +134 -0
- package/dist/src/sqlite-drivers/createOpSqliteDriver.d.ts +3 -0
- package/dist/src/sqlite-drivers/createOpSqliteDriver.d.ts.map +1 -0
- package/dist/src/sqlite-drivers/createOpSqliteDriver.js +119 -0
- package/dist/src/web.d.ts.map +1 -0
- package/package.json +72 -48
- package/src/ErrorUtils.d.ts +19 -0
- package/src/LockManager.ts +325 -0
- package/src/Polyfills.ts +301 -0
- package/src/Task.ts +66 -0
- package/src/components/EvoluIdenticon.tsx +2 -2
- package/src/createExpoDeps.ts +162 -160
- package/src/exports/bare-op-sqlite.ts +30 -28
- package/src/exports/expo-op-sqlite.ts +15 -14
- package/src/exports/expo-sqlite.ts +21 -4
- package/src/index.ts +2 -0
- package/src/shared.ts +115 -49
- package/src/sqlite-drivers/createExpoSqliteDriver.ts +74 -51
- package/src/sqlite-drivers/createOpSqliteDriver.ts +62 -60
- package/dist/components/EvoluIdenticon.d.ts +0 -9
- package/dist/components/EvoluIdenticon.d.ts.map +0 -1
- package/dist/createExpoDeps.d.ts +0 -7
- package/dist/createExpoDeps.d.ts.map +0 -1
- package/dist/createExpoDeps.js +0 -123
- package/dist/exports/bare-op-sqlite.d.ts +0 -10
- package/dist/exports/bare-op-sqlite.d.ts.map +0 -1
- package/dist/exports/bare-op-sqlite.js +0 -24
- package/dist/exports/expo-op-sqlite.d.ts +0 -9
- package/dist/exports/expo-op-sqlite.d.ts.map +0 -1
- package/dist/exports/expo-op-sqlite.js +0 -12
- package/dist/exports/expo-sqlite.d.ts +0 -8
- package/dist/exports/expo-sqlite.d.ts.map +0 -1
- package/dist/exports/expo-sqlite.js +0 -11
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -1
- package/dist/shared.d.ts +0 -5
- package/dist/shared.d.ts.map +0 -1
- package/dist/shared.js +0 -39
- package/dist/sqlite-drivers/createExpoSqliteDriver.d.ts +0 -3
- package/dist/sqlite-drivers/createExpoSqliteDriver.d.ts.map +0 -1
- package/dist/sqlite-drivers/createExpoSqliteDriver.js +0 -46
- package/dist/sqlite-drivers/createOpSqliteDriver.d.ts +0 -3
- package/dist/sqlite-drivers/createOpSqliteDriver.d.ts.map +0 -1
- package/dist/sqlite-drivers/createOpSqliteDriver.js +0 -54
- package/dist/web.d.ts.map +0 -1
- /package/dist/{web.d.ts → src/web.d.ts} +0 -0
- /package/dist/{web.js → src/web.js} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evolu/react-native",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "15.0.0-next.1",
|
|
4
4
|
"description": "Evolu for React Native and Expo",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"evolu",
|
|
@@ -12,7 +12,10 @@
|
|
|
12
12
|
],
|
|
13
13
|
"author": "Daniel Steigerwald <daniel@steigerwald.cz>",
|
|
14
14
|
"license": "MIT",
|
|
15
|
-
"repository":
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/evoluhq/evolu.git"
|
|
18
|
+
},
|
|
16
19
|
"bugs": {
|
|
17
20
|
"url": "https://github.com/evoluhq/evolu/issues"
|
|
18
21
|
},
|
|
@@ -20,76 +23,99 @@
|
|
|
20
23
|
"type": "module",
|
|
21
24
|
"exports": {
|
|
22
25
|
".": {
|
|
23
|
-
"types": "./dist/index.d.ts",
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
+
"types": "./dist/src/index.d.ts",
|
|
27
|
+
"react-native": "./dist/src/index.js",
|
|
28
|
+
"default": "./dist/src/index.js"
|
|
29
|
+
},
|
|
30
|
+
"./polyfills": {
|
|
31
|
+
"types": "./dist/src/Polyfills.d.ts",
|
|
32
|
+
"react-native": "./dist/src/Polyfills.js",
|
|
33
|
+
"default": "./dist/src/Polyfills.js"
|
|
26
34
|
},
|
|
27
35
|
"./expo-sqlite": {
|
|
28
|
-
"types": "./dist/exports/expo-sqlite.d.ts",
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
36
|
+
"types": "./dist/src/exports/expo-sqlite.d.ts",
|
|
37
|
+
"react-native": "./dist/src/exports/expo-sqlite.js",
|
|
38
|
+
"browser": "./dist/src/web.js",
|
|
39
|
+
"default": "./dist/src/exports/expo-sqlite.js"
|
|
32
40
|
},
|
|
33
41
|
"./expo-op-sqlite": {
|
|
34
|
-
"types": "./dist/exports/expo-op-sqlite.d.ts",
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
42
|
+
"types": "./dist/src/exports/expo-op-sqlite.d.ts",
|
|
43
|
+
"react-native": "./dist/src/exports/expo-op-sqlite.js",
|
|
44
|
+
"browser": "./dist/src/web.js",
|
|
45
|
+
"default": "./dist/src/exports/expo-op-sqlite.js"
|
|
38
46
|
},
|
|
39
47
|
"./bare-op-sqlite": {
|
|
40
|
-
"types": "./dist/exports/bare-op-sqlite.d.ts",
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
48
|
+
"types": "./dist/src/exports/bare-op-sqlite.d.ts",
|
|
49
|
+
"react-native": "./dist/src/exports/bare-op-sqlite.js",
|
|
50
|
+
"browser": "./dist/src/web.js",
|
|
51
|
+
"default": "./dist/src/exports/bare-op-sqlite.js"
|
|
44
52
|
}
|
|
45
53
|
},
|
|
46
54
|
"typesVersions": {
|
|
47
55
|
"*": {
|
|
48
56
|
".": [
|
|
49
|
-
"./dist/index.d.ts"
|
|
57
|
+
"./dist/src/index.d.ts"
|
|
58
|
+
],
|
|
59
|
+
"polyfills": [
|
|
60
|
+
"./dist/src/Polyfills.d.ts"
|
|
50
61
|
],
|
|
51
62
|
"expo-sqlite": [
|
|
52
|
-
"./dist/exports/expo-sqlite.d.ts"
|
|
63
|
+
"./dist/src/exports/expo-sqlite.d.ts"
|
|
53
64
|
],
|
|
54
65
|
"expo-op-sqlite": [
|
|
55
|
-
"./dist/exports/expo-op-sqlite.d.ts"
|
|
66
|
+
"./dist/src/exports/expo-op-sqlite.d.ts"
|
|
56
67
|
],
|
|
57
68
|
"bare-op-sqlite": [
|
|
58
|
-
"./dist/exports/bare-op-sqlite.d.ts"
|
|
69
|
+
"./dist/src/exports/bare-op-sqlite.d.ts"
|
|
59
70
|
]
|
|
60
71
|
}
|
|
61
72
|
},
|
|
62
73
|
"files": [
|
|
63
|
-
"dist/**",
|
|
74
|
+
"dist/src/**",
|
|
64
75
|
"src/**",
|
|
65
76
|
"README.md"
|
|
66
77
|
],
|
|
78
|
+
"dependencies": {
|
|
79
|
+
"array-from-async": "^3.0.0",
|
|
80
|
+
"array.prototype.tosorted": "^1.1.4",
|
|
81
|
+
"promise.try": "^2.0.1",
|
|
82
|
+
"promise.withresolvers": "^1.0.4",
|
|
83
|
+
"set.prototype.difference": "^1.1.7",
|
|
84
|
+
"set.prototype.intersection": "^1.1.8",
|
|
85
|
+
"set.prototype.isdisjointfrom": "^1.1.5",
|
|
86
|
+
"set.prototype.issubsetof": "^1.1.4",
|
|
87
|
+
"set.prototype.issupersetof": "^1.1.3",
|
|
88
|
+
"set.prototype.symmetricdifference": "^1.1.3",
|
|
89
|
+
"set.prototype.union": "^1.1.3"
|
|
90
|
+
},
|
|
67
91
|
"devDependencies": {
|
|
68
|
-
"@op-engineering/op-sqlite": "^15.
|
|
69
|
-
"
|
|
70
|
-
"expo
|
|
71
|
-
"expo-
|
|
72
|
-
"
|
|
73
|
-
"react
|
|
74
|
-
"react-native
|
|
75
|
-
"react-native-
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"@evolu/
|
|
80
|
-
"@evolu/
|
|
92
|
+
"@op-engineering/op-sqlite": "^15.2.2",
|
|
93
|
+
"@types/react": "^19.2.14",
|
|
94
|
+
"expo": "^55.0.4",
|
|
95
|
+
"expo-secure-store": "~55.0.8",
|
|
96
|
+
"expo-sqlite": "~55.0.10",
|
|
97
|
+
"react": "^19.2.4",
|
|
98
|
+
"react-native": "0.83.6",
|
|
99
|
+
"react-native-nitro-modules": "0.34.1",
|
|
100
|
+
"react-native-sensitive-info": "6.0.0-rc.11",
|
|
101
|
+
"react-native-svg": "15.15.3",
|
|
102
|
+
"typescript": "^6",
|
|
103
|
+
"@evolu/common": "8.0.0-next.4",
|
|
104
|
+
"@evolu/react": "11.0.0-next.0",
|
|
105
|
+
"@evolu/typescript-config": "0.0.2"
|
|
81
106
|
},
|
|
82
107
|
"peerDependencies": {
|
|
83
|
-
"@evolu/common": "^
|
|
84
|
-
"@evolu/react": "^
|
|
108
|
+
"@evolu/common": "^8.0.0-next.0",
|
|
109
|
+
"@evolu/react": "^11.0.0-next.0",
|
|
85
110
|
"@op-engineering/op-sqlite": ">=12",
|
|
86
|
-
"expo": ">=
|
|
87
|
-
"expo-secure-store": ">=
|
|
88
|
-
"expo-sqlite": ">=
|
|
89
|
-
"react
|
|
90
|
-
"react-native
|
|
111
|
+
"expo": ">=55",
|
|
112
|
+
"expo-secure-store": ">=55",
|
|
113
|
+
"expo-sqlite": ">=55",
|
|
114
|
+
"react": ">=19",
|
|
115
|
+
"react-native": ">=0.83",
|
|
116
|
+
"react-native-nitro-modules": ">=0.34",
|
|
91
117
|
"react-native-sensitive-info": ">=6",
|
|
92
|
-
"react-native-svg": ">=15"
|
|
118
|
+
"react-native-svg": ">=15.15"
|
|
93
119
|
},
|
|
94
120
|
"peerDependenciesMeta": {
|
|
95
121
|
"@op-engineering/op-sqlite": {
|
|
@@ -118,13 +144,11 @@
|
|
|
118
144
|
"access": "public"
|
|
119
145
|
},
|
|
120
146
|
"engines": {
|
|
121
|
-
"node": ">=
|
|
147
|
+
"node": ">=24.0.0"
|
|
122
148
|
},
|
|
123
|
-
"sideEffects":
|
|
149
|
+
"sideEffects": false,
|
|
124
150
|
"scripts": {
|
|
125
|
-
"
|
|
126
|
-
"build": "rimraf dist && tsc",
|
|
127
|
-
"clean": "rimraf .turbo node_modules dist",
|
|
151
|
+
"build": "tsc --build tsconfig.build.json",
|
|
128
152
|
"format": "prettier --write \"src/*.{ts,tsx,md}\""
|
|
129
153
|
}
|
|
130
154
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React Native global error handling utilities.
|
|
3
|
+
*
|
|
4
|
+
* ErrorUtils is a React Native global that provides error handling
|
|
5
|
+
* capabilities.
|
|
6
|
+
*/
|
|
7
|
+
interface ErrorUtils {
|
|
8
|
+
getGlobalHandler: () => ((error: unknown, isFatal?: boolean) => void) | null;
|
|
9
|
+
setGlobalHandler: (
|
|
10
|
+
handler: (error: unknown, isFatal?: boolean) => void,
|
|
11
|
+
) => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
declare global {
|
|
15
|
+
// eslint-disable-next-line no-var
|
|
16
|
+
var ErrorUtils: ErrorUtils | undefined;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React Native implementation of {@link LockManager}.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* React Native `LockManager` ponyfill.
|
|
9
|
+
*
|
|
10
|
+
* This is a temporary in-memory ponyfill until React Native ships native
|
|
11
|
+
* `LockManager` support.
|
|
12
|
+
*
|
|
13
|
+
* The ponyfill follows Web Locks request and query semantics within the current
|
|
14
|
+
* JavaScript process.
|
|
15
|
+
*
|
|
16
|
+
* ### Example
|
|
17
|
+
*
|
|
18
|
+
* ```ts
|
|
19
|
+
* await lockManager.request("db", async () => {
|
|
20
|
+
* // critical section
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
const createLockManagerPonyfill = ({
|
|
25
|
+
clientId = "in-memory-main-thread",
|
|
26
|
+
}: {
|
|
27
|
+
readonly clientId?: string;
|
|
28
|
+
} = {}): LockManager => {
|
|
29
|
+
const heldLocksByName = new Map<string, Array<HeldLock>>();
|
|
30
|
+
const pendingRequestsByName = new Map<string, Array<PendingRequest<any>>>();
|
|
31
|
+
|
|
32
|
+
const processPendingRequests = (name: string): void => {
|
|
33
|
+
const pendingRequests = pendingRequestsByName.get(name);
|
|
34
|
+
if (pendingRequests == null || pendingRequests.length === 0) return;
|
|
35
|
+
|
|
36
|
+
const heldLocks = heldLocksByName.get(name) ?? [];
|
|
37
|
+
const hasExclusiveLock = heldLocks.some(
|
|
38
|
+
(lock) => lock.mode === "exclusive",
|
|
39
|
+
);
|
|
40
|
+
if (hasExclusiveLock) return;
|
|
41
|
+
|
|
42
|
+
if (heldLocks.length === 0) {
|
|
43
|
+
const nextRequest = pendingRequests[0];
|
|
44
|
+
if (nextRequest.mode === "exclusive") {
|
|
45
|
+
grantPendingRequest(name, pendingRequests.shift()!);
|
|
46
|
+
} else {
|
|
47
|
+
while (pendingRequests[0]?.mode === "shared") {
|
|
48
|
+
grantPendingRequest(name, pendingRequests.shift()!);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
} else {
|
|
52
|
+
while (pendingRequests[0]?.mode === "shared") {
|
|
53
|
+
grantPendingRequest(name, pendingRequests.shift()!);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
cleanupNameState(name);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const grantPendingRequest = <T>(
|
|
61
|
+
name: string,
|
|
62
|
+
pendingRequest: PendingRequest<T>,
|
|
63
|
+
): void => {
|
|
64
|
+
const heldLocks = heldLocksByName.get(name) ?? [];
|
|
65
|
+
const heldLock = {
|
|
66
|
+
clientId,
|
|
67
|
+
mode: pendingRequest.mode,
|
|
68
|
+
name,
|
|
69
|
+
reject: pendingRequest.reject,
|
|
70
|
+
} satisfies HeldLock;
|
|
71
|
+
|
|
72
|
+
heldLocks.push(heldLock);
|
|
73
|
+
heldLocksByName.set(name, heldLocks);
|
|
74
|
+
pendingRequest.phase = "granted";
|
|
75
|
+
|
|
76
|
+
void Promise.resolve()
|
|
77
|
+
.then(() => {
|
|
78
|
+
if (pendingRequest.signal?.aborted) {
|
|
79
|
+
pendingRequest.phase = "settled";
|
|
80
|
+
pendingRequest.signal.removeEventListener(
|
|
81
|
+
"abort",
|
|
82
|
+
pendingRequest.abort,
|
|
83
|
+
);
|
|
84
|
+
releaseHeldLock(name, heldLock);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
pendingRequest.signal?.removeEventListener(
|
|
89
|
+
"abort",
|
|
90
|
+
pendingRequest.abort,
|
|
91
|
+
);
|
|
92
|
+
pendingRequest.phase = "running";
|
|
93
|
+
|
|
94
|
+
return Promise.resolve(
|
|
95
|
+
pendingRequest.callback({ mode: pendingRequest.mode, name }),
|
|
96
|
+
);
|
|
97
|
+
})
|
|
98
|
+
.then(
|
|
99
|
+
(value) => {
|
|
100
|
+
if (pendingRequest.phase === "settled") return;
|
|
101
|
+
|
|
102
|
+
pendingRequest.phase = "settled";
|
|
103
|
+
releaseHeldLock(name, heldLock);
|
|
104
|
+
pendingRequest.resolve(value!);
|
|
105
|
+
},
|
|
106
|
+
(error: unknown) => {
|
|
107
|
+
pendingRequest.phase = "settled";
|
|
108
|
+
releaseHeldLock(name, heldLock);
|
|
109
|
+
pendingRequest.reject(error);
|
|
110
|
+
},
|
|
111
|
+
);
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const releaseHeldLock = (name: string, heldLock: HeldLock): void => {
|
|
115
|
+
const currentHeldLocks = heldLocksByName.get(name) ?? [];
|
|
116
|
+
heldLocksByName.set(
|
|
117
|
+
name,
|
|
118
|
+
currentHeldLocks.filter((lock) => lock !== heldLock),
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
cleanupNameState(name);
|
|
122
|
+
processPendingRequests(name);
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const stealLocks = (name: string): void => {
|
|
126
|
+
const heldLocks = heldLocksByName.get(name) ?? [];
|
|
127
|
+
if (heldLocks.length === 0) return;
|
|
128
|
+
|
|
129
|
+
heldLocksByName.delete(name);
|
|
130
|
+
|
|
131
|
+
for (const heldLock of heldLocks) {
|
|
132
|
+
heldLock.reject(createAbortError());
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const cleanupNameState = (name: string): void => {
|
|
137
|
+
if (heldLocksByName.get(name)?.length === 0) {
|
|
138
|
+
heldLocksByName.delete(name);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (pendingRequestsByName.get(name)?.length === 0) {
|
|
142
|
+
pendingRequestsByName.delete(name);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const removePendingRequest = <T>(
|
|
147
|
+
name: string,
|
|
148
|
+
pendingRequest: PendingRequest<T>,
|
|
149
|
+
): void => {
|
|
150
|
+
const pendingRequests = pendingRequestsByName.get(name)!;
|
|
151
|
+
pendingRequestsByName.set(
|
|
152
|
+
name,
|
|
153
|
+
pendingRequests.filter((request) => request !== pendingRequest),
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
cleanupNameState(name);
|
|
157
|
+
processPendingRequests(name);
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const canGrantImmediately = (name: string, mode: LockMode): boolean => {
|
|
161
|
+
const pendingRequests = pendingRequestsByName.get(name);
|
|
162
|
+
if (pendingRequests != null && pendingRequests.length > 0) {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const heldLocks = heldLocksByName.get(name) ?? [];
|
|
167
|
+
|
|
168
|
+
if (mode === "exclusive") {
|
|
169
|
+
return heldLocks.length === 0;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return heldLocks.every((lock) => lock.mode === "shared");
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
return {
|
|
176
|
+
request: <T>(
|
|
177
|
+
name: string,
|
|
178
|
+
optionsOrCallback: RequestOptions | LockGrantedCallback<T>,
|
|
179
|
+
maybeCallback?: LockGrantedCallback<T>,
|
|
180
|
+
): Promise<Awaited<T>> => {
|
|
181
|
+
const [options, callback] = normalizeRequestArguments(
|
|
182
|
+
optionsOrCallback,
|
|
183
|
+
maybeCallback,
|
|
184
|
+
);
|
|
185
|
+
const mode = options.mode ?? "exclusive";
|
|
186
|
+
|
|
187
|
+
if (name.startsWith("-")) {
|
|
188
|
+
return Promise.reject(createNotSupportedError());
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (options.ifAvailable && options.steal) {
|
|
192
|
+
return Promise.reject(createNotSupportedError());
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (options.steal && mode !== "exclusive") {
|
|
196
|
+
return Promise.reject(createNotSupportedError());
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (options.signal != null && (options.ifAvailable || options.steal)) {
|
|
200
|
+
return Promise.reject(createNotSupportedError());
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (options.signal?.aborted) {
|
|
204
|
+
return Promise.reject(options.signal.reason as Error);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (options.ifAvailable && !canGrantImmediately(name, mode)) {
|
|
208
|
+
return Promise.resolve().then(() => Promise.resolve(callback(null)));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return new Promise<Awaited<T>>((resolve, reject) => {
|
|
212
|
+
const pendingRequest: PendingRequest<T> = {
|
|
213
|
+
abort: () => {
|
|
214
|
+
if (pendingRequest.phase === "queued") {
|
|
215
|
+
pendingRequest.phase = "settled";
|
|
216
|
+
removePendingRequest(name, pendingRequest);
|
|
217
|
+
reject(options.signal!.reason as Error);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
pendingRequest.phase = "settled";
|
|
222
|
+
reject(options.signal!.reason as Error);
|
|
223
|
+
},
|
|
224
|
+
callback,
|
|
225
|
+
mode,
|
|
226
|
+
name,
|
|
227
|
+
phase: "queued",
|
|
228
|
+
reject,
|
|
229
|
+
resolve,
|
|
230
|
+
...(options.signal == null ? {} : { signal: options.signal }),
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
if (options.signal != null) {
|
|
234
|
+
options.signal.addEventListener("abort", pendingRequest.abort, {
|
|
235
|
+
once: true,
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const pendingRequests = pendingRequestsByName.get(name) ?? [];
|
|
240
|
+
|
|
241
|
+
if (options.steal) {
|
|
242
|
+
stealLocks(name);
|
|
243
|
+
pendingRequests.unshift(pendingRequest);
|
|
244
|
+
} else {
|
|
245
|
+
pendingRequests.push(pendingRequest);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
pendingRequestsByName.set(name, pendingRequests);
|
|
249
|
+
processPendingRequests(name);
|
|
250
|
+
});
|
|
251
|
+
},
|
|
252
|
+
|
|
253
|
+
query: () => {
|
|
254
|
+
const held = Array.from(heldLocksByName.values())
|
|
255
|
+
.flat()
|
|
256
|
+
.map(({ clientId, mode, name }) => ({ clientId, mode, name }));
|
|
257
|
+
const pending = Array.from(pendingRequestsByName.values())
|
|
258
|
+
.flat()
|
|
259
|
+
.map(({ mode, name }) => ({
|
|
260
|
+
clientId,
|
|
261
|
+
mode,
|
|
262
|
+
name,
|
|
263
|
+
}));
|
|
264
|
+
|
|
265
|
+
return Promise.resolve({ held, pending });
|
|
266
|
+
},
|
|
267
|
+
};
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* React Native {@link LockManager}.
|
|
272
|
+
*
|
|
273
|
+
* Uses an in-memory lock manager scoped to the main JavaScript thread while
|
|
274
|
+
* following Web Locks request and query semantics.
|
|
275
|
+
*/
|
|
276
|
+
export const lockManager: LockManager = /*#__PURE__*/ createLockManagerPonyfill(
|
|
277
|
+
{
|
|
278
|
+
clientId: "react-native-main-thread",
|
|
279
|
+
},
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
const normalizeRequestArguments = <T>(
|
|
283
|
+
optionsOrCallback: RequestOptions | LockGrantedCallback<T>,
|
|
284
|
+
maybeCallback?: LockGrantedCallback<T>,
|
|
285
|
+
): [RequestOptions, LockGrantedCallback<T>] =>
|
|
286
|
+
typeof optionsOrCallback === "function"
|
|
287
|
+
? [{}, optionsOrCallback]
|
|
288
|
+
: [optionsOrCallback, maybeCallback!];
|
|
289
|
+
|
|
290
|
+
const createAbortError = (): Error =>
|
|
291
|
+
createNamedError("AbortError", "The request was aborted.");
|
|
292
|
+
|
|
293
|
+
const createNotSupportedError = (): Error =>
|
|
294
|
+
createNamedError("NotSupportedError", "The operation is not supported.");
|
|
295
|
+
|
|
296
|
+
const createNamedError = (name: string, message: string): Error => {
|
|
297
|
+
const error = new Error(message) as Error & { name: string };
|
|
298
|
+
error.name = name;
|
|
299
|
+
return error;
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
interface HeldLock extends LockInfo {
|
|
303
|
+
readonly clientId: string;
|
|
304
|
+
readonly mode: LockMode;
|
|
305
|
+
readonly name: string;
|
|
306
|
+
readonly reject: (reason?: unknown) => void;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
interface RequestOptions {
|
|
310
|
+
readonly ifAvailable?: boolean;
|
|
311
|
+
readonly mode?: LockMode;
|
|
312
|
+
readonly signal?: AbortSignal;
|
|
313
|
+
readonly steal?: boolean;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
interface PendingRequest<T> {
|
|
317
|
+
readonly abort: () => void;
|
|
318
|
+
readonly callback: LockGrantedCallback<T>;
|
|
319
|
+
readonly mode: LockMode;
|
|
320
|
+
readonly name: string;
|
|
321
|
+
phase: "queued" | "granted" | "running" | "settled";
|
|
322
|
+
readonly reject: (reason?: unknown) => void;
|
|
323
|
+
readonly resolve: (value: Awaited<T> | PromiseLike<Awaited<T>>) => void;
|
|
324
|
+
readonly signal?: AbortSignal;
|
|
325
|
+
}
|