@cogcoin/client 0.5.7 → 0.5.9
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/client/factory.js +9 -1
- package/dist/bitcoind/client/managed-client.d.ts +1 -1
- package/dist/bitcoind/client/managed-client.js +21 -2
- package/dist/bitcoind/service.js +1 -2
- package/dist/bitcoind/testing.d.ts +1 -0
- package/dist/bitcoind/testing.js +1 -0
- package/dist/cli/output.js +13 -0
- package/dist/cli/runner.js +17 -0
- package/dist/cli/signals.js +1 -1
- package/dist/wallet/lifecycle.d.ts +3 -0
- package/dist/wallet/lifecycle.js +25 -0
- package/dist/wallet/state/seed-index.js +1 -1
- package/dist/wallet/tx/anchor.js +26 -40
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# `@cogcoin/client`
|
|
2
2
|
|
|
3
|
-
`@cogcoin/client@0.5.
|
|
3
|
+
`@cogcoin/client@0.5.9` is the store-backed 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
|
|
|
@@ -97,7 +97,15 @@ async function createManagedBitcoindClient(options) {
|
|
|
97
97
|
// The persistent service may already exist from a non-processing attach path
|
|
98
98
|
// that used startHeight 0. Cogcoin replay still begins at the requested
|
|
99
99
|
// processing boundary for this managed client.
|
|
100
|
-
|
|
100
|
+
const databasePath = options.databasePath ?? null;
|
|
101
|
+
return new DefaultManagedBitcoindClient(client, options.store, node, rpc, progress, bootstrap, indexerDaemon, databasePath
|
|
102
|
+
? async () => attachOrStartIndexerDaemon({
|
|
103
|
+
dataDir,
|
|
104
|
+
databasePath,
|
|
105
|
+
walletRootId: options.walletRootId,
|
|
106
|
+
startupTimeoutMs: options.startupTimeoutMs,
|
|
107
|
+
})
|
|
108
|
+
: null, options.startHeight, options.syncDebounceMs ?? DEFAULT_SYNC_DEBOUNCE_MS);
|
|
101
109
|
}
|
|
102
110
|
catch (error) {
|
|
103
111
|
if (progressStarted) {
|
|
@@ -7,7 +7,7 @@ import type { BitcoinRpcClient } from "../rpc.js";
|
|
|
7
7
|
import type { ManagedBitcoindClient, ManagedBitcoindNodeHandle, ManagedBitcoindStatus, SyncResult } from "../types.js";
|
|
8
8
|
export declare class DefaultManagedBitcoindClient implements ManagedBitcoindClient {
|
|
9
9
|
#private;
|
|
10
|
-
constructor(client: Client, store: ClientStoreAdapter, node: ManagedBitcoindNodeHandle, rpc: BitcoinRpcClient, progress: ManagedProgressController, bootstrap: AssumeUtxoBootstrapController, indexerDaemon: IndexerDaemonClient | null, startHeight: number, syncDebounceMs: number);
|
|
10
|
+
constructor(client: Client, store: ClientStoreAdapter, node: ManagedBitcoindNodeHandle, rpc: BitcoinRpcClient, progress: ManagedProgressController, bootstrap: AssumeUtxoBootstrapController, indexerDaemon: IndexerDaemonClient | null, reattachIndexerDaemon: (() => Promise<IndexerDaemonClient | null>) | null, startHeight: number, syncDebounceMs: number);
|
|
11
11
|
getTip(): Promise<import("../../types.js").ClientTip | null>;
|
|
12
12
|
getState(): Promise<import("@cogcoin/indexer/types").IndexerState>;
|
|
13
13
|
applyBlock(block: BitcoinBlock): Promise<import("../../types.js").ApplyBlockResult>;
|
|
@@ -10,6 +10,7 @@ export class DefaultManagedBitcoindClient {
|
|
|
10
10
|
#progress;
|
|
11
11
|
#bootstrap;
|
|
12
12
|
#indexerDaemon;
|
|
13
|
+
#reattachIndexerDaemon;
|
|
13
14
|
#startHeight;
|
|
14
15
|
#syncDebounceMs;
|
|
15
16
|
#following = false;
|
|
@@ -22,7 +23,7 @@ export class DefaultManagedBitcoindClient {
|
|
|
22
23
|
#syncPromise = Promise.resolve(createInitialSyncResult());
|
|
23
24
|
#debounceTimer = null;
|
|
24
25
|
#syncAbortControllers = new Set();
|
|
25
|
-
constructor(client, store, node, rpc, progress, bootstrap, indexerDaemon, startHeight, syncDebounceMs) {
|
|
26
|
+
constructor(client, store, node, rpc, progress, bootstrap, indexerDaemon, reattachIndexerDaemon, startHeight, syncDebounceMs) {
|
|
26
27
|
this.#client = client;
|
|
27
28
|
this.#store = store;
|
|
28
29
|
this.#node = node;
|
|
@@ -30,6 +31,7 @@ export class DefaultManagedBitcoindClient {
|
|
|
30
31
|
this.#progress = progress;
|
|
31
32
|
this.#bootstrap = bootstrap;
|
|
32
33
|
this.#indexerDaemon = indexerDaemon;
|
|
34
|
+
this.#reattachIndexerDaemon = reattachIndexerDaemon;
|
|
33
35
|
this.#startHeight = startHeight;
|
|
34
36
|
this.#syncDebounceMs = syncDebounceMs;
|
|
35
37
|
}
|
|
@@ -177,7 +179,7 @@ export class DefaultManagedBitcoindClient {
|
|
|
177
179
|
await this.#progress.close();
|
|
178
180
|
await this.#node.stop();
|
|
179
181
|
await this.#client.close();
|
|
180
|
-
await this.#
|
|
182
|
+
await this.#resumeIndexerBackgroundFollow();
|
|
181
183
|
await this.#indexerDaemon?.close();
|
|
182
184
|
}
|
|
183
185
|
async playSyncCompletionScene() {
|
|
@@ -209,4 +211,21 @@ export class DefaultManagedBitcoindClient {
|
|
|
209
211
|
throw new Error("managed_bitcoind_client_closed");
|
|
210
212
|
}
|
|
211
213
|
}
|
|
214
|
+
async #resumeIndexerBackgroundFollow() {
|
|
215
|
+
if (this.#indexerDaemon === null) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
try {
|
|
219
|
+
await this.#indexerDaemon.resumeBackgroundFollow();
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
if (this.#reattachIndexerDaemon === null) {
|
|
224
|
+
throw error;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
const replacementDaemon = await this.#reattachIndexerDaemon();
|
|
228
|
+
this.#indexerDaemon = replacementDaemon;
|
|
229
|
+
await replacementDaemon?.resumeBackgroundFollow();
|
|
230
|
+
}
|
|
212
231
|
}
|
package/dist/bitcoind/service.js
CHANGED
|
@@ -226,8 +226,7 @@ async function waitForRpcReady(rpc, cookieFile, expectedChain, timeoutMs) {
|
|
|
226
226
|
throw lastError instanceof Error ? lastError : new Error("bitcoind_rpc_timeout");
|
|
227
227
|
}
|
|
228
228
|
function validateManagedBitcoindStatus(status, options, runtimeRoot) {
|
|
229
|
-
const
|
|
230
|
-
const legacyRuntimeRoot = join(resolveManagedServicePaths(options.dataDir ?? "", walletRootId).runtimeRoot, walletRootId);
|
|
229
|
+
const legacyRuntimeRoot = join(resolveManagedServicePaths(options.dataDir ?? "", options.walletRootId ?? UNINITIALIZED_WALLET_ROOT_ID).runtimeRoot, status.walletRootId);
|
|
231
230
|
if (status.serviceApiVersion !== MANAGED_BITCOIND_SERVICE_API_VERSION_VALUE) {
|
|
232
231
|
throw new Error("managed_bitcoind_service_version_mismatch");
|
|
233
232
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { openManagedBitcoindClientInternal } from "./client.js";
|
|
2
|
+
export { DefaultManagedBitcoindClient } from "./client/managed-client.js";
|
|
2
3
|
export { attachOrStartIndexerDaemon, readIndexerDaemonStatusForTesting, stopIndexerDaemonService, shutdownIndexerDaemonForTesting, } from "./indexer-daemon.js";
|
|
3
4
|
export { normalizeRpcBlock } from "./normalize.js";
|
|
4
5
|
export { BitcoinRpcClient } from "./rpc.js";
|
package/dist/bitcoind/testing.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { openManagedBitcoindClientInternal } from "./client.js";
|
|
2
|
+
export { DefaultManagedBitcoindClient } from "./client/managed-client.js";
|
|
2
3
|
export { attachOrStartIndexerDaemon, readIndexerDaemonStatusForTesting, stopIndexerDaemonService, shutdownIndexerDaemonForTesting, } from "./indexer-daemon.js";
|
|
3
4
|
export { normalizeRpcBlock } from "./normalize.js";
|
|
4
5
|
export { BitcoinRpcClient } from "./rpc.js";
|
package/dist/cli/output.js
CHANGED
|
@@ -169,6 +169,12 @@ export function classifyCliError(error) {
|
|
|
169
169
|
if (message === "wallet_import_archive_not_found") {
|
|
170
170
|
return { exitCode: 3, errorCode: message, message };
|
|
171
171
|
}
|
|
172
|
+
if (message === "wallet_seed_not_found") {
|
|
173
|
+
return { exitCode: 3, errorCode: message, message };
|
|
174
|
+
}
|
|
175
|
+
if (message === "wallet_seed_index_invalid") {
|
|
176
|
+
return { exitCode: 4, errorCode: message, message };
|
|
177
|
+
}
|
|
172
178
|
if (message === "reset_process_shutdown_failed"
|
|
173
179
|
|| message === "reset_data_root_delete_failed"
|
|
174
180
|
|| message === "reset_secret_cleanup_failed"
|
|
@@ -331,6 +337,13 @@ export function createCliErrorPresentation(errorCode, fallbackMessage) {
|
|
|
331
337
|
next: "Check `--seed <name>` and retry.",
|
|
332
338
|
};
|
|
333
339
|
}
|
|
340
|
+
if (errorCode === "wallet_seed_index_invalid") {
|
|
341
|
+
return {
|
|
342
|
+
what: "Wallet seed registry is invalid.",
|
|
343
|
+
why: "Cogcoin could not parse or trust the local seed registry file, so it cannot safely decide which named wallet seed to use.",
|
|
344
|
+
next: "Run `cogcoin repair`, then retry the command.",
|
|
345
|
+
};
|
|
346
|
+
}
|
|
334
347
|
if (errorCode === "wallet_delete_main_not_supported") {
|
|
335
348
|
return {
|
|
336
349
|
what: "The main wallet cannot be deleted with `wallet delete`.",
|
package/dist/cli/runner.js
CHANGED
|
@@ -12,6 +12,14 @@ import { runSyncCommand } from "./commands/sync.js";
|
|
|
12
12
|
import { runWalletAdminCommand } from "./commands/wallet-admin.js";
|
|
13
13
|
import { runWalletMutationCommand } from "./commands/wallet-mutation.js";
|
|
14
14
|
import { runWalletReadCommand } from "./commands/wallet-read.js";
|
|
15
|
+
import { findWalletSeedRecord, loadWalletSeedIndex } from "../wallet/state/seed-index.js";
|
|
16
|
+
function commandUsesExistingWalletSeed(parsed) {
|
|
17
|
+
return parsed.seedName !== null
|
|
18
|
+
&& parsed.seedName !== "main"
|
|
19
|
+
&& parsed.command !== "restore"
|
|
20
|
+
&& parsed.command !== "wallet-delete"
|
|
21
|
+
&& parsed.command !== "wallet-restore";
|
|
22
|
+
}
|
|
15
23
|
export async function runCli(argv, contextOverrides = {}) {
|
|
16
24
|
const context = createDefaultContext(contextOverrides);
|
|
17
25
|
let parsed;
|
|
@@ -41,6 +49,15 @@ export async function runCli(argv, contextOverrides = {}) {
|
|
|
41
49
|
return parsed.help ? 0 : 2;
|
|
42
50
|
}
|
|
43
51
|
try {
|
|
52
|
+
if (commandUsesExistingWalletSeed(parsed)) {
|
|
53
|
+
const mainPaths = context.resolveWalletRuntimePaths("main");
|
|
54
|
+
const seedIndex = await loadWalletSeedIndex({
|
|
55
|
+
paths: mainPaths,
|
|
56
|
+
});
|
|
57
|
+
if (seedIndex.seeds.length > 0 && findWalletSeedRecord(seedIndex, parsed.seedName) === null) {
|
|
58
|
+
throw new Error("wallet_seed_not_found");
|
|
59
|
+
}
|
|
60
|
+
}
|
|
44
61
|
if (parsed.command === "sync") {
|
|
45
62
|
return runSyncCommand(parsed, context);
|
|
46
63
|
}
|
package/dist/cli/signals.js
CHANGED
|
@@ -19,7 +19,7 @@ export function createStopSignalWatcher(signalSource, stderr, client, forceExit)
|
|
|
19
19
|
};
|
|
20
20
|
const onFirstSignal = () => {
|
|
21
21
|
closing = true;
|
|
22
|
-
writeLine(stderr, "
|
|
22
|
+
writeLine(stderr, "Detaching from managed Cogcoin client...");
|
|
23
23
|
void client.close().then(() => {
|
|
24
24
|
settle(0);
|
|
25
25
|
}, () => {
|
|
@@ -227,6 +227,9 @@ export declare function deleteImportedWalletSeed(options: {
|
|
|
227
227
|
assumeYes?: boolean;
|
|
228
228
|
nowUnixMs?: number;
|
|
229
229
|
paths?: WalletRuntimePaths;
|
|
230
|
+
attachService?: typeof attachOrStartManagedBitcoindService;
|
|
231
|
+
probeBitcoindService?: typeof probeManagedBitcoindService;
|
|
232
|
+
rpcFactory?: (config: Parameters<typeof createRpcClient>[0]) => WalletLifecycleRpcClient;
|
|
230
233
|
}): Promise<WalletDeleteResult>;
|
|
231
234
|
export declare function repairWallet(options: {
|
|
232
235
|
dataDir: string;
|
package/dist/wallet/lifecycle.js
CHANGED
|
@@ -1623,6 +1623,31 @@ export async function deleteImportedWalletSeed(options) {
|
|
|
1623
1623
|
if (!options.assumeYes) {
|
|
1624
1624
|
await confirmYesNo(options.prompter, `Delete imported seed "${seedName}" and release its local wallet artifacts? Type yes to continue: `);
|
|
1625
1625
|
}
|
|
1626
|
+
const probeManagedBitcoind = options.probeBitcoindService ?? probeManagedBitcoindService;
|
|
1627
|
+
const managedBitcoindProbe = await probeManagedBitcoind({
|
|
1628
|
+
dataDir: options.dataDir,
|
|
1629
|
+
chain: "main",
|
|
1630
|
+
startHeight: 0,
|
|
1631
|
+
}).catch(() => ({
|
|
1632
|
+
compatibility: "unreachable",
|
|
1633
|
+
status: null,
|
|
1634
|
+
error: null,
|
|
1635
|
+
}));
|
|
1636
|
+
if (managedBitcoindProbe.compatibility !== "compatible" && managedBitcoindProbe.compatibility !== "unreachable") {
|
|
1637
|
+
throw new Error(managedBitcoindProbe.error ?? "managed_bitcoind_protocol_error");
|
|
1638
|
+
}
|
|
1639
|
+
if (managedBitcoindProbe.compatibility === "compatible") {
|
|
1640
|
+
const node = await (options.attachService ?? attachOrStartManagedBitcoindService)({
|
|
1641
|
+
dataDir: options.dataDir,
|
|
1642
|
+
chain: "main",
|
|
1643
|
+
startHeight: 0,
|
|
1644
|
+
});
|
|
1645
|
+
const rpc = (options.rpcFactory ?? createRpcClient)(node.rpc);
|
|
1646
|
+
const walletName = sanitizeWalletName(seedRecord.walletRootId);
|
|
1647
|
+
if (rpc.unloadWallet != null) {
|
|
1648
|
+
await rpc.unloadWallet(walletName, false).catch(() => undefined);
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1626
1651
|
await clearUnlockSession(paths.walletUnlockSessionPath).catch(() => undefined);
|
|
1627
1652
|
await clearWalletExplicitLock(paths.walletExplicitLockPath).catch(() => undefined);
|
|
1628
1653
|
await clearPendingInitialization(paths, provider).catch(() => undefined);
|
|
@@ -28,7 +28,7 @@ async function readSeedIndexFile(path) {
|
|
|
28
28
|
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
29
29
|
return null;
|
|
30
30
|
}
|
|
31
|
-
throw
|
|
31
|
+
throw new Error("wallet_seed_index_invalid");
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
export function normalizeWalletSeedName(name) {
|
package/dist/wallet/tx/anchor.js
CHANGED
|
@@ -319,7 +319,18 @@ function releaseClearedAnchorReservationState(options) {
|
|
|
319
319
|
}
|
|
320
320
|
return upsertProactiveFamily(nextState, {
|
|
321
321
|
...family,
|
|
322
|
+
status: "canceled",
|
|
322
323
|
lastUpdatedAtUnixMs: options.nowUnixMs,
|
|
324
|
+
tx1: family.tx1 == null ? family.tx1 : {
|
|
325
|
+
...family.tx1,
|
|
326
|
+
status: "canceled",
|
|
327
|
+
temporaryBuilderLockedOutpoints: [],
|
|
328
|
+
},
|
|
329
|
+
tx2: family.tx2 == null ? family.tx2 : {
|
|
330
|
+
...family.tx2,
|
|
331
|
+
status: "canceled",
|
|
332
|
+
temporaryBuilderLockedOutpoints: [],
|
|
333
|
+
},
|
|
323
334
|
});
|
|
324
335
|
}
|
|
325
336
|
function createFamilyTransactionRecord() {
|
|
@@ -1320,12 +1331,15 @@ export async function clearPendingAnchor(options) {
|
|
|
1320
1331
|
});
|
|
1321
1332
|
try {
|
|
1322
1333
|
assertWalletMutationContextReady(readContext, "wallet_anchor_clear");
|
|
1334
|
+
const family = findActiveAnchorFamilyByDomain(readContext.localState.state, normalizedDomainName);
|
|
1323
1335
|
const domain = readContext.localState.state.domains.find((entry) => entry.name === normalizedDomainName) ?? null;
|
|
1324
|
-
if (domain === null) {
|
|
1336
|
+
if (domain === null && family === null) {
|
|
1325
1337
|
throw new Error("wallet_anchor_clear_domain_not_found");
|
|
1326
1338
|
}
|
|
1327
|
-
const family = findActiveAnchorFamilyByDomain(readContext.localState.state, normalizedDomainName);
|
|
1328
1339
|
if (family === null) {
|
|
1340
|
+
if (domain === null) {
|
|
1341
|
+
throw new Error("wallet_anchor_clear_domain_not_found");
|
|
1342
|
+
}
|
|
1329
1343
|
if (domain.localAnchorIntent !== "none") {
|
|
1330
1344
|
throw new Error("wallet_anchor_clear_inconsistent_state");
|
|
1331
1345
|
}
|
|
@@ -1343,47 +1357,19 @@ export async function clearPendingAnchor(options) {
|
|
|
1343
1357
|
if (family.status !== "draft" || family.currentStep !== "reserved") {
|
|
1344
1358
|
throw new Error(`wallet_anchor_clear_not_clearable_${family.status}`);
|
|
1345
1359
|
}
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|| family.reservedDedicatedIndex === null
|
|
1349
|
-
|| domain.dedicatedIndex !== family.reservedDedicatedIndex
|
|
1360
|
+
const reservedDedicatedIndex = family.reservedDedicatedIndex ?? null;
|
|
1361
|
+
if (reservedDedicatedIndex === null
|
|
1350
1362
|
|| family.tx1?.attemptedTxid !== null
|
|
1351
|
-
|| family.tx2?.attemptedTxid !== null
|
|
1363
|
+
|| family.tx2?.attemptedTxid !== null
|
|
1364
|
+
|| (domain !== null
|
|
1365
|
+
&& (domain.localAnchorIntent !== "reserved"
|
|
1366
|
+
|| domain.dedicatedIndex === null
|
|
1367
|
+
|| domain.dedicatedIndex !== reservedDedicatedIndex))) {
|
|
1352
1368
|
throw new Error("wallet_anchor_clear_inconsistent_state");
|
|
1353
1369
|
}
|
|
1354
|
-
await confirmAnchorClear(options.prompter, normalizedDomainName,
|
|
1355
|
-
const operation = resolveAnchorOperation(readContext, normalizedDomainName, family.foundingMessageText ?? null, family.foundingMessagePayloadHex ?? null);
|
|
1356
|
-
const targetIdentity = deriveAnchorTargetIdentityForIndex(readContext.localState.state, family.reservedDedicatedIndex);
|
|
1357
|
-
const node = await (options.attachService ?? attachOrStartManagedBitcoindService)({
|
|
1358
|
-
dataDir: options.dataDir,
|
|
1359
|
-
chain: "main",
|
|
1360
|
-
startHeight: 0,
|
|
1361
|
-
walletRootId: readContext.localState.state.walletRootId,
|
|
1362
|
-
});
|
|
1363
|
-
const rpc = (options.rpcFactory ?? createRpcClient)(node.rpc);
|
|
1364
|
-
const walletName = readContext.localState.state.managedCoreWallet.walletName;
|
|
1365
|
-
const reconciled = await reconcileAnchorFamily({
|
|
1366
|
-
state: readContext.localState.state,
|
|
1367
|
-
family,
|
|
1368
|
-
operation: {
|
|
1369
|
-
...operation,
|
|
1370
|
-
targetIdentity,
|
|
1371
|
-
},
|
|
1372
|
-
provider,
|
|
1373
|
-
nowUnixMs,
|
|
1374
|
-
paths,
|
|
1375
|
-
unlockUntilUnixMs: readContext.localState.unlockUntilUnixMs,
|
|
1376
|
-
rpc,
|
|
1377
|
-
walletName,
|
|
1378
|
-
});
|
|
1379
|
-
if (reconciled.resolution !== "not-seen") {
|
|
1380
|
-
throw new Error(reconciled.resolution === "repair-required"
|
|
1381
|
-
? "wallet_anchor_clear_not_clearable_repair_required"
|
|
1382
|
-
: `wallet_anchor_clear_not_clearable_${reconciled.resolution}`);
|
|
1383
|
-
}
|
|
1384
|
-
const releasedDedicatedIndex = family.reservedDedicatedIndex;
|
|
1370
|
+
await confirmAnchorClear(options.prompter, normalizedDomainName, reservedDedicatedIndex, options.assumeYes ?? false);
|
|
1385
1371
|
const releasedState = releaseClearedAnchorReservationState({
|
|
1386
|
-
state:
|
|
1372
|
+
state: readContext.localState.state,
|
|
1387
1373
|
familyId: family.familyId,
|
|
1388
1374
|
domainName: normalizedDomainName,
|
|
1389
1375
|
nowUnixMs,
|
|
@@ -1404,7 +1390,7 @@ export async function clearPendingAnchor(options) {
|
|
|
1404
1390
|
cleared: true,
|
|
1405
1391
|
previousFamilyStatus: family.status,
|
|
1406
1392
|
previousFamilyStep: family.currentStep ?? null,
|
|
1407
|
-
releasedDedicatedIndex,
|
|
1393
|
+
releasedDedicatedIndex: reservedDedicatedIndex,
|
|
1408
1394
|
};
|
|
1409
1395
|
}
|
|
1410
1396
|
finally {
|
package/package.json
CHANGED