@cogcoin/client 1.2.0 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/bitcoind/managed-bitcoind-service-status.js +6 -2
- package/dist/bitcoind/managed-runtime/bitcoind-policy.js +10 -0
- package/dist/bitcoind/managed-runtime/types.d.ts +1 -1
- package/dist/cli/output/rules/services.js +7 -0
- package/dist/wallet/lifecycle/repair-bitcoind.js +115 -74
- package/dist/wallet/lifecycle/repair-runtime.d.ts +1 -0
- package/dist/wallet/lifecycle/repair-runtime.js +19 -0
- package/dist/wallet/lifecycle/types.d.ts +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# `@cogcoin/client`
|
|
2
2
|
|
|
3
|
-
`@cogcoin/client@1.2.
|
|
3
|
+
`@cogcoin/client@1.2.2` is the reference Cogcoin client package for applications that want a local wallet, durable SQLite-backed state, and a managed Bitcoin Core integration around `@cogcoin/indexer`. It publishes the reusable client APIs, the SQLite adapter, the managed `bitcoind` integration, and the first-party `cogcoin` CLI in one package.
|
|
4
4
|
|
|
5
5
|
Use Node 22 or newer.
|
|
6
6
|
|
|
@@ -66,7 +66,9 @@ export async function probeManagedBitcoindStatusCandidate(status, options, runti
|
|
|
66
66
|
const rpc = createRpcClient(status.rpc);
|
|
67
67
|
try {
|
|
68
68
|
await waitForManagedBitcoindRpcReady(rpc, status.rpc.cookieFile, status.chain, options.startupTimeoutMs ?? DEFAULT_MANAGED_BITCOIND_STARTUP_TIMEOUT_MS);
|
|
69
|
-
await validateNodeConfigForTesting(rpc, status.chain, status.zmq.endpoint
|
|
69
|
+
await validateNodeConfigForTesting(rpc, status.chain, status.zmq.endpoint, {
|
|
70
|
+
requireRawTxZmq: true,
|
|
71
|
+
});
|
|
70
72
|
return {
|
|
71
73
|
compatibility: "compatible",
|
|
72
74
|
status,
|
|
@@ -96,7 +98,9 @@ export async function refreshManagedBitcoindStatus(status, paths, options) {
|
|
|
96
98
|
const targetWalletRootId = options.walletRootId ?? status.walletRootId;
|
|
97
99
|
try {
|
|
98
100
|
await waitForManagedBitcoindRpcReady(rpc, status.rpc.cookieFile, status.chain, options.startupTimeoutMs ?? DEFAULT_MANAGED_BITCOIND_STARTUP_TIMEOUT_MS);
|
|
99
|
-
await validateNodeConfigForTesting(rpc, status.chain, status.zmq.endpoint
|
|
101
|
+
await validateNodeConfigForTesting(rpc, status.chain, status.zmq.endpoint, {
|
|
102
|
+
requireRawTxZmq: true,
|
|
103
|
+
});
|
|
100
104
|
const walletReplica = await loadManagedWalletReplicaIfPresent(rpc, targetWalletRootId, status.dataDir);
|
|
101
105
|
const nextStatus = {
|
|
102
106
|
...status,
|
|
@@ -8,6 +8,9 @@ function isRuntimeMismatchError(error) {
|
|
|
8
8
|
return error.message.startsWith("bitcoind_chain_expected_")
|
|
9
9
|
|| error.message === "managed_bitcoind_runtime_mismatch";
|
|
10
10
|
}
|
|
11
|
+
function isMissingRawTxZmqError(error) {
|
|
12
|
+
return error instanceof Error && error.message === "bitcoind_zmq_rawtx_missing";
|
|
13
|
+
}
|
|
11
14
|
function isUnreachableManagedBitcoindError(error) {
|
|
12
15
|
if (error instanceof Error) {
|
|
13
16
|
if ("code" in error) {
|
|
@@ -47,6 +50,13 @@ export function mapManagedBitcoindValidationError(error, status) {
|
|
|
47
50
|
};
|
|
48
51
|
}
|
|
49
52
|
export function mapManagedBitcoindRuntimeProbeFailure(error, status) {
|
|
53
|
+
if (isMissingRawTxZmqError(error)) {
|
|
54
|
+
return {
|
|
55
|
+
compatibility: "rawtx-zmq-missing",
|
|
56
|
+
status,
|
|
57
|
+
error: "bitcoind_zmq_rawtx_missing",
|
|
58
|
+
};
|
|
59
|
+
}
|
|
50
60
|
if (isRuntimeMismatchError(error)) {
|
|
51
61
|
return {
|
|
52
62
|
compatibility: "runtime-mismatch",
|
|
@@ -2,7 +2,7 @@ import type { ClientTip } from "../../types.js";
|
|
|
2
2
|
import type { ManagedServicePaths } from "../service-paths.js";
|
|
3
3
|
import type { ManagedBitcoindObservedStatus, ManagedIndexerDaemonObservedStatus, ManagedIndexerTruthSource } from "../types.js";
|
|
4
4
|
import type { WalletBitcoindStatus, WalletIndexerStatus, WalletNodeStatus, WalletServiceHealth, WalletSnapshotView } from "../../wallet/read/types.js";
|
|
5
|
-
export type ManagedBitcoindServiceCompatibility = "compatible" | "service-version-mismatch" | "wallet-root-mismatch" | "runtime-mismatch" | "unreachable" | "protocol-error";
|
|
5
|
+
export type ManagedBitcoindServiceCompatibility = "compatible" | "service-version-mismatch" | "wallet-root-mismatch" | "runtime-mismatch" | "rawtx-zmq-missing" | "unreachable" | "protocol-error";
|
|
6
6
|
export interface ManagedBitcoindServiceProbeResult {
|
|
7
7
|
compatibility: ManagedBitcoindServiceCompatibility;
|
|
8
8
|
status: ManagedBitcoindObservedStatus | null;
|
|
@@ -108,6 +108,13 @@ export const serviceErrorRules = [
|
|
|
108
108
|
next: "Run `cogcoin repair` so the wallet can clear the conflicting runtime and restart a compatible managed bitcoind service.",
|
|
109
109
|
};
|
|
110
110
|
}
|
|
111
|
+
if (errorCode === "bitcoind_zmq_rawtx_missing" || errorCode.includes("rawtx_zmq_missing")) {
|
|
112
|
+
return {
|
|
113
|
+
what: "The live managed bitcoind service is missing raw transaction ZMQ.",
|
|
114
|
+
why: "This usually means an older managed bitcoind runtime is still running without the v1.2.0 `zmqpubrawtx` setting.",
|
|
115
|
+
next: "Run `cogcoin repair` so the wallet can stop the stale managed bitcoind service and restart it with the current ZMQ configuration.",
|
|
116
|
+
};
|
|
117
|
+
}
|
|
111
118
|
if (errorCode.includes("bitcoind_replica_missing")) {
|
|
112
119
|
return {
|
|
113
120
|
what: "The managed Core wallet replica is missing.",
|
|
@@ -4,7 +4,7 @@ import { persistWalletCoinControlStateIfNeeded } from "../coin-control.js";
|
|
|
4
4
|
import { createWalletSecretReference } from "../state/provider.js";
|
|
5
5
|
import { recreateManagedCoreWalletReplica, verifyManagedCoreWalletReplica } from "./managed-core.js";
|
|
6
6
|
import { pathExists } from "./context.js";
|
|
7
|
-
import { clearManagedBitcoindArtifacts, mapBitcoindCompatibilityToRepairIssue, mapBitcoindRepairHealth, waitForProcessExit, } from "./repair-runtime.js";
|
|
7
|
+
import { clearManagedBitcoindArtifacts, isManagedBitcoindRpcUnavailableError, mapBitcoindCompatibilityToRepairIssue, mapBitcoindRepairHealth, waitForProcessExit, } from "./repair-runtime.js";
|
|
8
8
|
export async function repairManagedBitcoindStage(options) {
|
|
9
9
|
let state = options.state;
|
|
10
10
|
let repairStateNeedsPersist = options.repairStateNeedsPersist;
|
|
@@ -33,28 +33,38 @@ export async function repairManagedBitcoindStage(options) {
|
|
|
33
33
|
bitcoindCompatibilityIssue = mapBitcoindCompatibilityToRepairIssue(initialBitcoindProbe.compatibility);
|
|
34
34
|
if (initialBitcoindProbe.compatibility === "service-version-mismatch"
|
|
35
35
|
|| initialBitcoindProbe.compatibility === "wallet-root-mismatch"
|
|
36
|
-
|| initialBitcoindProbe.compatibility === "runtime-mismatch"
|
|
36
|
+
|| initialBitcoindProbe.compatibility === "runtime-mismatch"
|
|
37
|
+
|| initialBitcoindProbe.compatibility === "rawtx-zmq-missing") {
|
|
37
38
|
const processId = initialBitcoindProbe.status?.processId ?? null;
|
|
38
39
|
if (processId === null) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
if (initialBitcoindProbe.compatibility !== "rawtx-zmq-missing") {
|
|
41
|
+
throw new Error("managed_bitcoind_process_id_unavailable");
|
|
42
|
+
}
|
|
43
|
+
await clearManagedBitcoindArtifacts(options.servicePaths);
|
|
44
|
+
bitcoindServiceAction = "restarted-missing-rawtx-zmq";
|
|
43
45
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
else {
|
|
47
|
+
try {
|
|
48
|
+
process.kill(processId, "SIGTERM");
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
if (!(error instanceof Error) || !("code" in error) || error.code !== "ESRCH") {
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
47
54
|
}
|
|
55
|
+
await waitForProcessExit(processId, 15_000, "managed_bitcoind_stop_timeout");
|
|
56
|
+
await clearManagedBitcoindArtifacts(options.servicePaths);
|
|
57
|
+
bitcoindServiceAction = initialBitcoindProbe.compatibility === "rawtx-zmq-missing"
|
|
58
|
+
? "restarted-missing-rawtx-zmq"
|
|
59
|
+
: "stopped-incompatible-service";
|
|
48
60
|
}
|
|
49
|
-
await waitForProcessExit(processId, 15_000, "managed_bitcoind_stop_timeout");
|
|
50
|
-
await clearManagedBitcoindArtifacts(options.servicePaths);
|
|
51
|
-
bitcoindServiceAction = "stopped-incompatible-service";
|
|
52
61
|
}
|
|
53
62
|
else if (initialBitcoindProbe.compatibility === "unreachable") {
|
|
54
63
|
const hasStaleArtifacts = await Promise.all([
|
|
55
64
|
options.servicePaths.bitcoindStatusPath,
|
|
56
65
|
options.servicePaths.bitcoindPidPath,
|
|
57
66
|
options.servicePaths.bitcoindReadyPath,
|
|
67
|
+
options.servicePaths.bitcoindRuntimeConfigPath,
|
|
58
68
|
options.servicePaths.bitcoindWalletStatusPath,
|
|
59
69
|
].map(pathExists));
|
|
60
70
|
if (hasStaleArtifacts.some(Boolean)) {
|
|
@@ -69,74 +79,105 @@ export async function repairManagedBitcoindStage(options) {
|
|
|
69
79
|
finally {
|
|
70
80
|
await bitcoindLock.release();
|
|
71
81
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
repairStateNeedsPersist = false;
|
|
99
|
-
}
|
|
100
|
-
let replica = await verifyManagedCoreWalletReplica(state, options.context.dataDir, {
|
|
101
|
-
nodeHandle: bitcoindHandle,
|
|
102
|
-
attachService: options.context.attachService,
|
|
103
|
-
rpcFactory: options.context.rpcFactory,
|
|
104
|
-
});
|
|
105
|
-
if (replica.proofStatus !== "ready") {
|
|
106
|
-
state = await recreateManagedCoreWalletReplica(state, options.context.provider, options.context.paths, options.context.dataDir, options.context.nowUnixMs, {
|
|
107
|
-
attachService: options.context.attachService,
|
|
108
|
-
rpcFactory: options.context.rpcFactory,
|
|
82
|
+
for (let attachAttempt = 0; attachAttempt < 2; attachAttempt += 1) {
|
|
83
|
+
let bitcoindHandle = null;
|
|
84
|
+
let handleClosed = false;
|
|
85
|
+
try {
|
|
86
|
+
bitcoindHandle = await options.context.attachService({
|
|
87
|
+
dataDir: options.context.dataDir,
|
|
88
|
+
chain: "main",
|
|
89
|
+
startHeight: 0,
|
|
90
|
+
walletRootId: state.walletRootId,
|
|
91
|
+
});
|
|
92
|
+
const rpc = options.context.rpcFactory(bitcoindHandle.rpc);
|
|
93
|
+
const normalizedDescriptorState = await normalizeWalletDescriptorState(state, rpc);
|
|
94
|
+
if (normalizedDescriptorState.changed) {
|
|
95
|
+
state = normalizedDescriptorState.state;
|
|
96
|
+
repairStateNeedsPersist = true;
|
|
97
|
+
}
|
|
98
|
+
const reconciledCoinControl = await persistWalletCoinControlStateIfNeeded({
|
|
99
|
+
state,
|
|
100
|
+
access: {
|
|
101
|
+
provider: options.context.provider,
|
|
102
|
+
secretReference: createWalletSecretReference(state.walletRootId),
|
|
103
|
+
},
|
|
104
|
+
paths: options.context.paths,
|
|
105
|
+
nowUnixMs: options.context.nowUnixMs,
|
|
106
|
+
replacePrimary: options.recoveredFromBackup && !repairStateNeedsPersist,
|
|
107
|
+
rpc,
|
|
109
108
|
});
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
109
|
+
state = reconciledCoinControl.state;
|
|
110
|
+
if (reconciledCoinControl.changed) {
|
|
111
|
+
repairStateNeedsPersist = false;
|
|
112
|
+
}
|
|
113
|
+
let replica = await verifyManagedCoreWalletReplica(state, options.context.dataDir, {
|
|
114
114
|
nodeHandle: bitcoindHandle,
|
|
115
115
|
attachService: options.context.attachService,
|
|
116
116
|
rpcFactory: options.context.rpcFactory,
|
|
117
117
|
});
|
|
118
|
+
if (replica.proofStatus !== "ready") {
|
|
119
|
+
state = await recreateManagedCoreWalletReplica(state, options.context.provider, options.context.paths, options.context.dataDir, options.context.nowUnixMs, {
|
|
120
|
+
attachService: options.context.attachService,
|
|
121
|
+
rpcFactory: options.context.rpcFactory,
|
|
122
|
+
});
|
|
123
|
+
recreatedManagedCoreWallet = true;
|
|
124
|
+
managedCoreReplicaAction = "recreated";
|
|
125
|
+
repairStateNeedsPersist = false;
|
|
126
|
+
replica = await verifyManagedCoreWalletReplica(state, options.context.dataDir, {
|
|
127
|
+
nodeHandle: bitcoindHandle,
|
|
128
|
+
attachService: options.context.attachService,
|
|
129
|
+
rpcFactory: options.context.rpcFactory,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
const finalBitcoindStatus = await bitcoindHandle.refreshServiceStatus?.() ?? null;
|
|
133
|
+
const chainInfo = await rpc.getBlockchainInfo();
|
|
134
|
+
bitcoindPostRepairHealth = mapBitcoindRepairHealth({
|
|
135
|
+
serviceState: finalBitcoindStatus?.state ?? null,
|
|
136
|
+
catchingUp: chainInfo.blocks < chainInfo.headers,
|
|
137
|
+
replica,
|
|
138
|
+
});
|
|
139
|
+
if (bitcoindServiceAction === "none" && initialBitcoindProbe.compatibility === "unreachable") {
|
|
140
|
+
bitcoindServiceAction = "restarted-compatible-service";
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
state,
|
|
144
|
+
repairStateNeedsPersist,
|
|
145
|
+
recreatedManagedCoreWallet,
|
|
146
|
+
bitcoindServiceAction,
|
|
147
|
+
bitcoindCompatibilityIssue,
|
|
148
|
+
managedCoreReplicaAction,
|
|
149
|
+
bitcoindPostRepairHealth,
|
|
150
|
+
};
|
|
118
151
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
152
|
+
catch (error) {
|
|
153
|
+
if (bitcoindHandle !== null) {
|
|
154
|
+
await bitcoindHandle.stop?.().catch(() => undefined);
|
|
155
|
+
handleClosed = true;
|
|
156
|
+
}
|
|
157
|
+
if (attachAttempt === 0 && isManagedBitcoindRpcUnavailableError(error)) {
|
|
158
|
+
const retryLock = await acquireFileLock(options.servicePaths.bitcoindLockPath, {
|
|
159
|
+
purpose: "managed-bitcoind-repair-stale-rpc",
|
|
160
|
+
walletRootId: state.walletRootId,
|
|
161
|
+
dataDir: options.context.dataDir,
|
|
162
|
+
});
|
|
163
|
+
try {
|
|
164
|
+
await clearManagedBitcoindArtifacts(options.servicePaths);
|
|
165
|
+
}
|
|
166
|
+
finally {
|
|
167
|
+
await retryLock.release();
|
|
168
|
+
}
|
|
169
|
+
if (bitcoindServiceAction === "none") {
|
|
170
|
+
bitcoindServiceAction = "restarted-compatible-service";
|
|
171
|
+
}
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
throw error;
|
|
175
|
+
}
|
|
176
|
+
finally {
|
|
177
|
+
if (!handleClosed) {
|
|
178
|
+
await bitcoindHandle?.stop?.().catch(() => undefined);
|
|
179
|
+
}
|
|
128
180
|
}
|
|
129
181
|
}
|
|
130
|
-
|
|
131
|
-
await bitcoindHandle.stop?.().catch(() => undefined);
|
|
132
|
-
}
|
|
133
|
-
return {
|
|
134
|
-
state,
|
|
135
|
-
repairStateNeedsPersist,
|
|
136
|
-
recreatedManagedCoreWallet,
|
|
137
|
-
bitcoindServiceAction,
|
|
138
|
-
bitcoindCompatibilityIssue,
|
|
139
|
-
managedCoreReplicaAction,
|
|
140
|
-
bitcoindPostRepairHealth,
|
|
141
|
-
};
|
|
182
|
+
throw new Error("managed_bitcoind_repair_retry_exhausted");
|
|
142
183
|
}
|
|
@@ -29,6 +29,7 @@ export declare function verifyIndexerPostRepairHealth(options: {
|
|
|
29
29
|
daemonInstanceId: string;
|
|
30
30
|
}>;
|
|
31
31
|
export declare function isProcessAlive(pid: number | null): Promise<boolean>;
|
|
32
|
+
export declare function isManagedBitcoindRpcUnavailableError(error: unknown): boolean;
|
|
32
33
|
export declare function waitForProcessExit(pid: number, timeoutMs?: number, errorCode?: string): Promise<void>;
|
|
33
34
|
export declare function clearIndexerDaemonArtifacts(servicePaths: ReturnType<typeof resolveManagedServicePaths>): Promise<void>;
|
|
34
35
|
export declare function clearManagedBitcoindArtifacts(servicePaths: ReturnType<typeof resolveManagedServicePaths>): Promise<void>;
|
|
@@ -69,6 +69,8 @@ export function mapBitcoindCompatibilityToRepairIssue(compatibility) {
|
|
|
69
69
|
return "wallet-root-mismatch";
|
|
70
70
|
case "runtime-mismatch":
|
|
71
71
|
return "runtime-mismatch";
|
|
72
|
+
case "rawtx-zmq-missing":
|
|
73
|
+
return "rawtx-zmq-missing";
|
|
72
74
|
default:
|
|
73
75
|
return "none";
|
|
74
76
|
}
|
|
@@ -151,6 +153,22 @@ export async function isProcessAlive(pid) {
|
|
|
151
153
|
return true;
|
|
152
154
|
}
|
|
153
155
|
}
|
|
156
|
+
export function isManagedBitcoindRpcUnavailableError(error) {
|
|
157
|
+
if (error instanceof Error && "code" in error) {
|
|
158
|
+
const code = error.code;
|
|
159
|
+
if (code === "ENOENT" || code === "ECONNREFUSED" || code === "ECONNRESET" || code === "EPIPE") {
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (!(error instanceof Error)) {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
return error.message === "bitcoind_cookie_timeout"
|
|
167
|
+
|| error.message.includes("cookie file is unavailable")
|
|
168
|
+
|| error.message.includes("ECONNREFUSED")
|
|
169
|
+
|| error.message.includes("ECONNRESET")
|
|
170
|
+
|| error.message.includes("socket hang up");
|
|
171
|
+
}
|
|
154
172
|
export async function waitForProcessExit(pid, timeoutMs = 15_000, errorCode = "indexer_daemon_stop_timeout") {
|
|
155
173
|
const deadline = Date.now() + timeoutMs;
|
|
156
174
|
while (Date.now() < deadline) {
|
|
@@ -169,6 +187,7 @@ export async function clearManagedBitcoindArtifacts(servicePaths) {
|
|
|
169
187
|
await rm(servicePaths.bitcoindStatusPath, { force: true }).catch(() => undefined);
|
|
170
188
|
await rm(servicePaths.bitcoindPidPath, { force: true }).catch(() => undefined);
|
|
171
189
|
await rm(servicePaths.bitcoindReadyPath, { force: true }).catch(() => undefined);
|
|
190
|
+
await rm(servicePaths.bitcoindRuntimeConfigPath, { force: true }).catch(() => undefined);
|
|
172
191
|
await rm(servicePaths.bitcoindWalletStatusPath, { force: true }).catch(() => undefined);
|
|
173
192
|
}
|
|
174
193
|
export async function stopRecordedManagedProcess(pid, errorCode) {
|
|
@@ -36,8 +36,8 @@ export interface WalletRepairResult {
|
|
|
36
36
|
recoveredFromBackup: boolean;
|
|
37
37
|
recreatedManagedCoreWallet: boolean;
|
|
38
38
|
resetIndexerDatabase: boolean;
|
|
39
|
-
bitcoindServiceAction: "none" | "cleared-stale-artifacts" | "stopped-incompatible-service" | "restarted-compatible-service";
|
|
40
|
-
bitcoindCompatibilityIssue: "none" | "service-version-mismatch" | "wallet-root-mismatch" | "runtime-mismatch";
|
|
39
|
+
bitcoindServiceAction: "none" | "cleared-stale-artifacts" | "stopped-incompatible-service" | "restarted-compatible-service" | "restarted-missing-rawtx-zmq";
|
|
40
|
+
bitcoindCompatibilityIssue: "none" | "service-version-mismatch" | "wallet-root-mismatch" | "runtime-mismatch" | "rawtx-zmq-missing";
|
|
41
41
|
managedCoreReplicaAction: "none" | "recreated";
|
|
42
42
|
bitcoindPostRepairHealth: "ready" | "catching-up" | "starting" | "failed" | "unavailable";
|
|
43
43
|
indexerDaemonAction: "none" | "cleared-stale-artifacts" | "stopped-incompatible-daemon" | "restarted-compatible-daemon";
|
package/package.json
CHANGED