@arkade-os/sdk 0.4.21 → 0.4.22
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/cjs/contracts/contractWatcher.js +16 -18
- package/dist/cjs/wallet/delegator.js +27 -18
- package/dist/cjs/wallet/serviceWorker/wallet-message-handler.js +3 -1
- package/dist/cjs/wallet/vtxo-manager.js +7 -5
- package/dist/esm/contracts/contractWatcher.js +14 -16
- package/dist/esm/wallet/delegator.js +27 -18
- package/dist/esm/wallet/serviceWorker/wallet-message-handler.js +3 -1
- package/dist/esm/wallet/vtxo-manager.js +7 -5
- package/dist/types/contracts/types.d.ts +5 -5
- package/dist/types/wallet/delegator.d.ts +8 -3
- package/package.json +4 -4
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ContractWatcher = void 0;
|
|
4
|
-
const utils_1 = require("../
|
|
4
|
+
const utils_1 = require("../wallet/utils");
|
|
5
|
+
const utils_2 = require("../providers/utils");
|
|
5
6
|
/**
|
|
6
7
|
* Watches multiple contracts for virtual output state changes with resilient connection handling.
|
|
7
8
|
*
|
|
@@ -276,7 +277,7 @@ class ContractWatcher {
|
|
|
276
277
|
// indefinitely and block the caller.
|
|
277
278
|
// Error management must be implemented to ensure the connection
|
|
278
279
|
// is restored and events are fired.
|
|
279
|
-
if ((0,
|
|
280
|
+
if ((0, utils_2.isEventSourceError)(e)) {
|
|
280
281
|
console.debug("ContractWatcher subscription disconnected; reconnecting");
|
|
281
282
|
}
|
|
282
283
|
else {
|
|
@@ -553,18 +554,22 @@ class ContractWatcher {
|
|
|
553
554
|
const state = this.contracts.get(contractScript);
|
|
554
555
|
if (!state)
|
|
555
556
|
return;
|
|
557
|
+
const extended = [];
|
|
558
|
+
for (const v of vtxos) {
|
|
559
|
+
try {
|
|
560
|
+
const extendedVtxo = (0, utils_1.extendVirtualCoinForContract)(v, state.contract);
|
|
561
|
+
extended.push({ ...extendedVtxo, contractScript });
|
|
562
|
+
}
|
|
563
|
+
catch {
|
|
564
|
+
console.warn("failed to extend vtxo: ", v);
|
|
565
|
+
extended.push({ ...v, contractScript });
|
|
566
|
+
}
|
|
567
|
+
}
|
|
556
568
|
switch (eventType) {
|
|
557
569
|
case "vtxo_received":
|
|
558
570
|
this.eventCallback({
|
|
559
571
|
type: "vtxo_received",
|
|
560
|
-
vtxos:
|
|
561
|
-
...v,
|
|
562
|
-
contractScript,
|
|
563
|
-
// These fields may not be available from basic VirtualCoin
|
|
564
|
-
forfeitTapLeafScript: undefined,
|
|
565
|
-
intentTapLeafScript: undefined,
|
|
566
|
-
tapTree: undefined,
|
|
567
|
-
})),
|
|
572
|
+
vtxos: extended,
|
|
568
573
|
contractScript,
|
|
569
574
|
contract: state.contract,
|
|
570
575
|
timestamp,
|
|
@@ -573,14 +578,7 @@ class ContractWatcher {
|
|
|
573
578
|
case "vtxo_spent":
|
|
574
579
|
this.eventCallback({
|
|
575
580
|
type: "vtxo_spent",
|
|
576
|
-
vtxos:
|
|
577
|
-
...v,
|
|
578
|
-
contractScript,
|
|
579
|
-
// These fields may not be available from basic VirtualCoin
|
|
580
|
-
forfeitTapLeafScript: undefined,
|
|
581
|
-
intentTapLeafScript: undefined,
|
|
582
|
-
tapTree: undefined,
|
|
583
|
-
})),
|
|
581
|
+
vtxos: extended,
|
|
584
582
|
contractScript,
|
|
585
583
|
contract: state.contract,
|
|
586
584
|
timestamp,
|
|
@@ -29,20 +29,30 @@ class DelegatorManagerImpl {
|
|
|
29
29
|
// fetch server and delegator info once, shared across all groups
|
|
30
30
|
const arkInfo = await this.arkInfoProvider.getInfo();
|
|
31
31
|
const delegateInfo = await this.delegatorProvider.getDelegateInfo();
|
|
32
|
+
// keep only vtxos that can be signed by the delegate
|
|
33
|
+
const eligible = vtxos
|
|
34
|
+
.filter((v) => findDelegateTapLeaf(v, delegateInfo.pubkey) !== undefined)
|
|
35
|
+
.map((v) => v);
|
|
36
|
+
if (eligible.length === 0) {
|
|
37
|
+
return { delegated: [], failed: [] };
|
|
38
|
+
}
|
|
32
39
|
// if explicit delegateAt is provided, delegate all virtual outputs at once without sorting
|
|
33
40
|
if (delegateAt) {
|
|
34
41
|
try {
|
|
35
|
-
await delegate(this.identity, this.delegatorProvider, arkInfo, delegateInfo,
|
|
42
|
+
await delegate(this.identity, this.delegatorProvider, arkInfo, delegateInfo, eligible, destinationScript, delegateAt);
|
|
36
43
|
}
|
|
37
44
|
catch (error) {
|
|
38
|
-
return {
|
|
45
|
+
return {
|
|
46
|
+
delegated: [],
|
|
47
|
+
failed: [{ outpoints: eligible, error }],
|
|
48
|
+
};
|
|
39
49
|
}
|
|
40
|
-
return { delegated:
|
|
50
|
+
return { delegated: eligible, failed: [] };
|
|
41
51
|
}
|
|
42
52
|
// if no explicit delegateAt is provided, sort virtual outputs by expiry and delegate in groups of the same expiry day
|
|
43
53
|
const groupByExpiry = new Map();
|
|
44
54
|
let recoverableVtxos = [];
|
|
45
|
-
for (const vtxo of
|
|
55
|
+
for (const vtxo of eligible) {
|
|
46
56
|
if ((0, __1.isRecoverable)(vtxo)) {
|
|
47
57
|
recoverableVtxos.push(vtxo);
|
|
48
58
|
continue;
|
|
@@ -190,20 +200,7 @@ async function delegate(identity, delegatorProvider, arkInfo, delegateInfo, vtxo
|
|
|
190
200
|
await delegatorProvider.delegate(registerIntent, forfeits);
|
|
191
201
|
}
|
|
192
202
|
async function makeDelegateForfeitTx(input, connectorAmount, delegatePubkey, forfeitOutputScript, identity) {
|
|
193
|
-
|
|
194
|
-
delegatePubkey = delegatePubkey.slice(2);
|
|
195
|
-
}
|
|
196
|
-
const vtxoScript = __1.VtxoScript.decode(input.tapTree);
|
|
197
|
-
const delegateTapLeaf = vtxoScript.leaves.find((tapLeaf) => {
|
|
198
|
-
const arkTapscript = (0, __1.decodeTapscript)((0, base_2.scriptFromTapLeafScript)(tapLeaf));
|
|
199
|
-
if (!__1.MultisigTapscript.is(arkTapscript))
|
|
200
|
-
return false;
|
|
201
|
-
if (!arkTapscript.params.pubkeys
|
|
202
|
-
.map(base_1.hex.encode)
|
|
203
|
-
.includes(delegatePubkey))
|
|
204
|
-
return false;
|
|
205
|
-
return true;
|
|
206
|
-
});
|
|
203
|
+
const delegateTapLeaf = findDelegateTapLeaf(input, delegatePubkey);
|
|
207
204
|
if (!delegateTapLeaf) {
|
|
208
205
|
throw new Error(`delegate tap leaf not found for input: ${input.txid}:${input.vout}`);
|
|
209
206
|
}
|
|
@@ -291,3 +288,15 @@ function getDayTimestamp(timestamp) {
|
|
|
291
288
|
date.setUTCHours(0, 0, 0, 0);
|
|
292
289
|
return date.getTime();
|
|
293
290
|
}
|
|
291
|
+
function findDelegateTapLeaf(vtxo, delegatePubkey) {
|
|
292
|
+
if (!vtxo.tapTree)
|
|
293
|
+
return undefined;
|
|
294
|
+
const pk = delegatePubkey.length === 66 ? delegatePubkey.slice(2) : delegatePubkey;
|
|
295
|
+
const vtxoScript = __1.VtxoScript.decode(vtxo.tapTree);
|
|
296
|
+
return vtxoScript.leaves.find((tapLeaf) => {
|
|
297
|
+
const arkTapscript = (0, __1.decodeTapscript)((0, base_2.scriptFromTapLeafScript)(tapLeaf));
|
|
298
|
+
if (!__1.MultisigTapscript.is(arkTapscript))
|
|
299
|
+
return false;
|
|
300
|
+
return arkTapscript.params.pubkeys.map(base_1.hex.encode).includes(pk);
|
|
301
|
+
});
|
|
302
|
+
}
|
|
@@ -706,7 +706,9 @@ class WalletMessageHandler {
|
|
|
706
706
|
const { vtxoOutpoints, destination, delegateAt } = message.payload;
|
|
707
707
|
const allVtxos = await wallet.getVtxos();
|
|
708
708
|
const outpointSet = new Set(vtxoOutpoints.map((o) => `${o.txid}:${o.vout}`));
|
|
709
|
-
const filtered = allVtxos
|
|
709
|
+
const filtered = allVtxos
|
|
710
|
+
.filter((v) => outpointSet.has(`${v.txid}:${v.vout}`))
|
|
711
|
+
.map((v) => ({ ...v, contractScript: v.script }));
|
|
710
712
|
const result = await delegatorManager.delegate(filtered, destination, delegateAt !== undefined ? new Date(delegateAt) : undefined);
|
|
711
713
|
return {
|
|
712
714
|
tag: this.messageTag,
|
|
@@ -698,11 +698,13 @@ class VtxoManager {
|
|
|
698
698
|
console.error("Error renewing VTXOs:", e);
|
|
699
699
|
});
|
|
700
700
|
}
|
|
701
|
-
delegatorManager
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
701
|
+
if (delegatorManager) {
|
|
702
|
+
delegatorManager
|
|
703
|
+
.delegate(event.vtxos, destination)
|
|
704
|
+
.catch((e) => {
|
|
705
|
+
console.error("Error delegating VTXOs:", e);
|
|
706
|
+
});
|
|
707
|
+
}
|
|
706
708
|
});
|
|
707
709
|
return stopWatching;
|
|
708
710
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { extendVirtualCoinForContract } from '../wallet/utils.js';
|
|
1
2
|
import { isEventSourceError } from '../providers/utils.js';
|
|
2
3
|
/**
|
|
3
4
|
* Watches multiple contracts for virtual output state changes with resilient connection handling.
|
|
@@ -550,18 +551,22 @@ export class ContractWatcher {
|
|
|
550
551
|
const state = this.contracts.get(contractScript);
|
|
551
552
|
if (!state)
|
|
552
553
|
return;
|
|
554
|
+
const extended = [];
|
|
555
|
+
for (const v of vtxos) {
|
|
556
|
+
try {
|
|
557
|
+
const extendedVtxo = extendVirtualCoinForContract(v, state.contract);
|
|
558
|
+
extended.push({ ...extendedVtxo, contractScript });
|
|
559
|
+
}
|
|
560
|
+
catch {
|
|
561
|
+
console.warn("failed to extend vtxo: ", v);
|
|
562
|
+
extended.push({ ...v, contractScript });
|
|
563
|
+
}
|
|
564
|
+
}
|
|
553
565
|
switch (eventType) {
|
|
554
566
|
case "vtxo_received":
|
|
555
567
|
this.eventCallback({
|
|
556
568
|
type: "vtxo_received",
|
|
557
|
-
vtxos:
|
|
558
|
-
...v,
|
|
559
|
-
contractScript,
|
|
560
|
-
// These fields may not be available from basic VirtualCoin
|
|
561
|
-
forfeitTapLeafScript: undefined,
|
|
562
|
-
intentTapLeafScript: undefined,
|
|
563
|
-
tapTree: undefined,
|
|
564
|
-
})),
|
|
569
|
+
vtxos: extended,
|
|
565
570
|
contractScript,
|
|
566
571
|
contract: state.contract,
|
|
567
572
|
timestamp,
|
|
@@ -570,14 +575,7 @@ export class ContractWatcher {
|
|
|
570
575
|
case "vtxo_spent":
|
|
571
576
|
this.eventCallback({
|
|
572
577
|
type: "vtxo_spent",
|
|
573
|
-
vtxos:
|
|
574
|
-
...v,
|
|
575
|
-
contractScript,
|
|
576
|
-
// These fields may not be available from basic VirtualCoin
|
|
577
|
-
forfeitTapLeafScript: undefined,
|
|
578
|
-
intentTapLeafScript: undefined,
|
|
579
|
-
tapTree: undefined,
|
|
580
|
-
})),
|
|
578
|
+
vtxos: extended,
|
|
581
579
|
contractScript,
|
|
582
580
|
contract: state.contract,
|
|
583
581
|
timestamp,
|
|
@@ -25,20 +25,30 @@ export class DelegatorManagerImpl {
|
|
|
25
25
|
// fetch server and delegator info once, shared across all groups
|
|
26
26
|
const arkInfo = await this.arkInfoProvider.getInfo();
|
|
27
27
|
const delegateInfo = await this.delegatorProvider.getDelegateInfo();
|
|
28
|
+
// keep only vtxos that can be signed by the delegate
|
|
29
|
+
const eligible = vtxos
|
|
30
|
+
.filter((v) => findDelegateTapLeaf(v, delegateInfo.pubkey) !== undefined)
|
|
31
|
+
.map((v) => v);
|
|
32
|
+
if (eligible.length === 0) {
|
|
33
|
+
return { delegated: [], failed: [] };
|
|
34
|
+
}
|
|
28
35
|
// if explicit delegateAt is provided, delegate all virtual outputs at once without sorting
|
|
29
36
|
if (delegateAt) {
|
|
30
37
|
try {
|
|
31
|
-
await delegate(this.identity, this.delegatorProvider, arkInfo, delegateInfo,
|
|
38
|
+
await delegate(this.identity, this.delegatorProvider, arkInfo, delegateInfo, eligible, destinationScript, delegateAt);
|
|
32
39
|
}
|
|
33
40
|
catch (error) {
|
|
34
|
-
return {
|
|
41
|
+
return {
|
|
42
|
+
delegated: [],
|
|
43
|
+
failed: [{ outpoints: eligible, error }],
|
|
44
|
+
};
|
|
35
45
|
}
|
|
36
|
-
return { delegated:
|
|
46
|
+
return { delegated: eligible, failed: [] };
|
|
37
47
|
}
|
|
38
48
|
// if no explicit delegateAt is provided, sort virtual outputs by expiry and delegate in groups of the same expiry day
|
|
39
49
|
const groupByExpiry = new Map();
|
|
40
50
|
let recoverableVtxos = [];
|
|
41
|
-
for (const vtxo of
|
|
51
|
+
for (const vtxo of eligible) {
|
|
42
52
|
if (isRecoverable(vtxo)) {
|
|
43
53
|
recoverableVtxos.push(vtxo);
|
|
44
54
|
continue;
|
|
@@ -185,20 +195,7 @@ async function delegate(identity, delegatorProvider, arkInfo, delegateInfo, vtxo
|
|
|
185
195
|
await delegatorProvider.delegate(registerIntent, forfeits);
|
|
186
196
|
}
|
|
187
197
|
async function makeDelegateForfeitTx(input, connectorAmount, delegatePubkey, forfeitOutputScript, identity) {
|
|
188
|
-
|
|
189
|
-
delegatePubkey = delegatePubkey.slice(2);
|
|
190
|
-
}
|
|
191
|
-
const vtxoScript = VtxoScript.decode(input.tapTree);
|
|
192
|
-
const delegateTapLeaf = vtxoScript.leaves.find((tapLeaf) => {
|
|
193
|
-
const arkTapscript = decodeTapscript(scriptFromTapLeafScript(tapLeaf));
|
|
194
|
-
if (!MultisigTapscript.is(arkTapscript))
|
|
195
|
-
return false;
|
|
196
|
-
if (!arkTapscript.params.pubkeys
|
|
197
|
-
.map(hex.encode)
|
|
198
|
-
.includes(delegatePubkey))
|
|
199
|
-
return false;
|
|
200
|
-
return true;
|
|
201
|
-
});
|
|
198
|
+
const delegateTapLeaf = findDelegateTapLeaf(input, delegatePubkey);
|
|
202
199
|
if (!delegateTapLeaf) {
|
|
203
200
|
throw new Error(`delegate tap leaf not found for input: ${input.txid}:${input.vout}`);
|
|
204
201
|
}
|
|
@@ -286,3 +283,15 @@ function getDayTimestamp(timestamp) {
|
|
|
286
283
|
date.setUTCHours(0, 0, 0, 0);
|
|
287
284
|
return date.getTime();
|
|
288
285
|
}
|
|
286
|
+
function findDelegateTapLeaf(vtxo, delegatePubkey) {
|
|
287
|
+
if (!vtxo.tapTree)
|
|
288
|
+
return undefined;
|
|
289
|
+
const pk = delegatePubkey.length === 66 ? delegatePubkey.slice(2) : delegatePubkey;
|
|
290
|
+
const vtxoScript = VtxoScript.decode(vtxo.tapTree);
|
|
291
|
+
return vtxoScript.leaves.find((tapLeaf) => {
|
|
292
|
+
const arkTapscript = decodeTapscript(scriptFromTapLeafScript(tapLeaf));
|
|
293
|
+
if (!MultisigTapscript.is(arkTapscript))
|
|
294
|
+
return false;
|
|
295
|
+
return arkTapscript.params.pubkeys.map(hex.encode).includes(pk);
|
|
296
|
+
});
|
|
297
|
+
}
|
|
@@ -700,7 +700,9 @@ export class WalletMessageHandler {
|
|
|
700
700
|
const { vtxoOutpoints, destination, delegateAt } = message.payload;
|
|
701
701
|
const allVtxos = await wallet.getVtxos();
|
|
702
702
|
const outpointSet = new Set(vtxoOutpoints.map((o) => `${o.txid}:${o.vout}`));
|
|
703
|
-
const filtered = allVtxos
|
|
703
|
+
const filtered = allVtxos
|
|
704
|
+
.filter((v) => outpointSet.has(`${v.txid}:${v.vout}`))
|
|
705
|
+
.map((v) => ({ ...v, contractScript: v.script }));
|
|
704
706
|
const result = await delegatorManager.delegate(filtered, destination, delegateAt !== undefined ? new Date(delegateAt) : undefined);
|
|
705
707
|
return {
|
|
706
708
|
tag: this.messageTag,
|
|
@@ -693,11 +693,13 @@ export class VtxoManager {
|
|
|
693
693
|
console.error("Error renewing VTXOs:", e);
|
|
694
694
|
});
|
|
695
695
|
}
|
|
696
|
-
delegatorManager
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
696
|
+
if (delegatorManager) {
|
|
697
|
+
delegatorManager
|
|
698
|
+
.delegate(event.vtxos, destination)
|
|
699
|
+
.catch((e) => {
|
|
700
|
+
console.error("Error delegating VTXOs:", e);
|
|
701
|
+
});
|
|
702
|
+
}
|
|
701
703
|
});
|
|
702
704
|
return stopWatching;
|
|
703
705
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Bytes } from "@scure/btc-signer/utils.js";
|
|
2
|
-
import { TapLeafScript, VtxoScript } from "../script/base";
|
|
3
|
-
import { VirtualCoin,
|
|
2
|
+
import { EncodedVtxoScript, TapLeafScript, VtxoScript } from "../script/base";
|
|
3
|
+
import { VirtualCoin, TapLeaves } from "../wallet";
|
|
4
4
|
import { ContractFilter } from "../repositories";
|
|
5
5
|
/**
|
|
6
6
|
* Contract state indicating whether it should be actively monitored.
|
|
@@ -66,10 +66,10 @@ export interface Contract {
|
|
|
66
66
|
/**
|
|
67
67
|
* A virtual output that has been associated with a specific contract.
|
|
68
68
|
*/
|
|
69
|
-
export
|
|
70
|
-
|
|
69
|
+
export type ContractVtxo = VirtualCoin & Partial<TapLeaves & EncodedVtxoScript> & {
|
|
70
|
+
extraWitness?: Bytes[];
|
|
71
71
|
contractScript: string;
|
|
72
|
-
}
|
|
72
|
+
};
|
|
73
73
|
/**
|
|
74
74
|
* Result of path selection, including the tapleaf to use and any extra witness data.
|
|
75
75
|
*/
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import { TransactionOutput } from "@scure/btc-signer/psbt";
|
|
2
|
-
import { ArkProvider, DelegateInfo,
|
|
2
|
+
import { ArkProvider, DelegateInfo, Identity, Outpoint } from "..";
|
|
3
|
+
import { ContractVtxo } from "../contracts/types";
|
|
3
4
|
import { DelegatorProvider } from "../providers/delegator";
|
|
4
5
|
import { Bytes } from "@scure/btc-signer/utils";
|
|
5
6
|
export interface IDelegatorManager {
|
|
6
7
|
/**
|
|
7
8
|
* Delegate virtual outputs to the remote delegation service.
|
|
8
9
|
*
|
|
10
|
+
* Vtxos that are not locked to a delegate-type contract (no tap leaf
|
|
11
|
+
* matches the delegator's pubkey) are filtered out silently, since they
|
|
12
|
+
* cannot be co-signed by the delegator.
|
|
13
|
+
*
|
|
9
14
|
* @param vtxos - Virtual outputs to delegate
|
|
10
15
|
* @param destination - Arkade address that should receive renewed funds
|
|
11
16
|
* @param delegateAt - Optional timestamp to force a specific delegation time
|
|
12
17
|
* @returns Successfully delegated and failed outpoint groups
|
|
13
18
|
*/
|
|
14
|
-
delegate(vtxos:
|
|
19
|
+
delegate(vtxos: ContractVtxo[], destination: string, delegateAt?: Date): Promise<{
|
|
15
20
|
delegated: Outpoint[];
|
|
16
21
|
failed: {
|
|
17
22
|
outpoints: Outpoint[];
|
|
@@ -28,7 +33,7 @@ export declare class DelegatorManagerImpl implements IDelegatorManager {
|
|
|
28
33
|
/** Create a delegator manager from the configured provider, Arkade info source, and wallet identity. */
|
|
29
34
|
constructor(delegatorProvider: DelegatorProvider, arkInfoProvider: Pick<ArkProvider, "getInfo">, identity: Identity);
|
|
30
35
|
getDelegateInfo(): Promise<DelegateInfo>;
|
|
31
|
-
delegate(vtxos:
|
|
36
|
+
delegate(vtxos: ContractVtxo[], destination: string, delegateAt?: Date): Promise<{
|
|
32
37
|
delegated: Outpoint[];
|
|
33
38
|
failed: {
|
|
34
39
|
outpoints: Outpoint[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arkade-os/sdk",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.22",
|
|
4
4
|
"description": "TypeScript SDK for building Bitcoin wallets using the Arkade protocol",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|
|
@@ -109,9 +109,9 @@
|
|
|
109
109
|
"peerDependencies": {
|
|
110
110
|
"@react-native-async-storage/async-storage": ">=1.0.0",
|
|
111
111
|
"expo": ">=54.0.0",
|
|
112
|
-
"expo-background-task": "~1.0.10",
|
|
113
|
-
"expo-sqlite": "~16.0.10",
|
|
114
|
-
"expo-task-manager": "~14.0.9"
|
|
112
|
+
"expo-background-task": "~1.0.10 || >=55.0.0",
|
|
113
|
+
"expo-sqlite": "~16.0.10 || >=55.0.0",
|
|
114
|
+
"expo-task-manager": "~14.0.9 || >=55.0.0"
|
|
115
115
|
},
|
|
116
116
|
"peerDependenciesMeta": {
|
|
117
117
|
"expo": {
|