@totemsdk/omnia-host 0.11.0 → 0.13.0
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/api/methods.js +106 -32
- package/dist/lifecycle.d.ts +3 -0
- package/dist/lifecycle.js +24 -8
- package/dist/stores/persistent-map.d.ts +31 -0
- package/dist/stores/persistent-map.js +172 -0
- package/package.json +7 -7
package/dist/api/methods.js
CHANGED
|
@@ -1697,21 +1697,7 @@ function createHostMethods(context) {
|
|
|
1697
1697
|
});
|
|
1698
1698
|
if (!route)
|
|
1699
1699
|
return { success: false, error: 'No route found', errorCode: 'ROUTE_NOT_FOUND' };
|
|
1700
|
-
return {
|
|
1701
|
-
success: true,
|
|
1702
|
-
route: {
|
|
1703
|
-
...route,
|
|
1704
|
-
totalFees: route.totalFees.toString(),
|
|
1705
|
-
hops: route.hops.map((hop) => ({
|
|
1706
|
-
...hop,
|
|
1707
|
-
amount: hop.amount.toString(),
|
|
1708
|
-
...('isSwap' in hop && hop.isSwap ? {
|
|
1709
|
-
amountIn: hop.amountIn.toString(),
|
|
1710
|
-
amountOut: hop.amountOut.toString(),
|
|
1711
|
-
} : {}),
|
|
1712
|
-
})),
|
|
1713
|
-
},
|
|
1714
|
-
};
|
|
1700
|
+
return { success: true, route: serializeWireRoute(route) };
|
|
1715
1701
|
};
|
|
1716
1702
|
register('totem_omniaGetRoute', getRoute, 'omnia/getRoute');
|
|
1717
1703
|
const getSwapRate = () => ({ success: true, announcements: [] });
|
|
@@ -2529,28 +2515,115 @@ function createHostMethods(context) {
|
|
|
2529
2515
|
};
|
|
2530
2516
|
register('totem_omniaSpliceIn', splice('in'), 'omnia/spliceIn');
|
|
2531
2517
|
register('totem_omniaSpliceOut', splice('out'), 'omnia/spliceOut');
|
|
2518
|
+
function parseWireRoute(value) {
|
|
2519
|
+
if (!value || typeof value !== 'object')
|
|
2520
|
+
throw new Error('route must be an object');
|
|
2521
|
+
const raw = value;
|
|
2522
|
+
if (!Array.isArray(raw.hops) || raw.hops.length === 0)
|
|
2523
|
+
throw new Error('route.hops must be a non-empty array');
|
|
2524
|
+
const hops = raw.hops.map((entry, index) => {
|
|
2525
|
+
if (!entry || typeof entry !== 'object')
|
|
2526
|
+
throw new Error(`route.hops[${index}] must be an object`);
|
|
2527
|
+
const hop = entry;
|
|
2528
|
+
const base = {
|
|
2529
|
+
channelId: String(hop.channelId ?? ''),
|
|
2530
|
+
from: String(hop.from ?? ''),
|
|
2531
|
+
to: String(hop.to ?? ''),
|
|
2532
|
+
amount: typeof hop.amount === 'bigint' ? hop.amount : BigInt(String(hop.amount ?? '0')),
|
|
2533
|
+
tokenId: String(hop.tokenId ?? ''),
|
|
2534
|
+
...(typeof hop.htlcId === 'string' ? { htlcId: hop.htlcId } : {}),
|
|
2535
|
+
};
|
|
2536
|
+
if (hop.isSwap === true) {
|
|
2537
|
+
return {
|
|
2538
|
+
...base,
|
|
2539
|
+
isSwap: true,
|
|
2540
|
+
tokenIn: String(hop.tokenIn ?? ''),
|
|
2541
|
+
tokenOut: String(hop.tokenOut ?? ''),
|
|
2542
|
+
amountIn: typeof hop.amountIn === 'bigint' ? hop.amountIn : BigInt(String(hop.amountIn ?? '0')),
|
|
2543
|
+
amountOut: typeof hop.amountOut === 'bigint' ? hop.amountOut : BigInt(String(hop.amountOut ?? '0')),
|
|
2544
|
+
rate: String(hop.rate ?? ''),
|
|
2545
|
+
inboundChannelId: String(hop.inboundChannelId ?? ''),
|
|
2546
|
+
outboundChannelId: String(hop.outboundChannelId ?? ''),
|
|
2547
|
+
};
|
|
2548
|
+
}
|
|
2549
|
+
return base;
|
|
2550
|
+
});
|
|
2551
|
+
const route = {
|
|
2552
|
+
hops,
|
|
2553
|
+
totalFees: typeof raw.totalFees === 'bigint' ? raw.totalFees : BigInt(String(raw.totalFees ?? '0')),
|
|
2554
|
+
tokenIn: String(raw.tokenIn ?? ''),
|
|
2555
|
+
tokenOut: String(raw.tokenOut ?? ''),
|
|
2556
|
+
estimatedBlocks: Number(raw.estimatedBlocks ?? 0),
|
|
2557
|
+
};
|
|
2558
|
+
if (hops.some((hop) => hop.isSwap)) {
|
|
2559
|
+
route.swapHops = hops.filter((hop) => hop.isSwap);
|
|
2560
|
+
}
|
|
2561
|
+
return route;
|
|
2562
|
+
}
|
|
2563
|
+
function serializeWireRoute(route) {
|
|
2564
|
+
return {
|
|
2565
|
+
tokenIn: route.tokenIn,
|
|
2566
|
+
tokenOut: route.tokenOut,
|
|
2567
|
+
totalFees: route.totalFees.toString(),
|
|
2568
|
+
estimatedBlocks: route.estimatedBlocks,
|
|
2569
|
+
hops: route.hops.map((hop) => {
|
|
2570
|
+
const base = {
|
|
2571
|
+
channelId: hop.channelId,
|
|
2572
|
+
from: hop.from,
|
|
2573
|
+
to: hop.to,
|
|
2574
|
+
amount: hop.amount.toString(),
|
|
2575
|
+
tokenId: hop.tokenId,
|
|
2576
|
+
...(hop.htlcId ? { htlcId: hop.htlcId } : {}),
|
|
2577
|
+
};
|
|
2578
|
+
if ('isSwap' in hop && hop.isSwap) {
|
|
2579
|
+
return {
|
|
2580
|
+
...base,
|
|
2581
|
+
isSwap: true,
|
|
2582
|
+
tokenIn: hop.tokenIn,
|
|
2583
|
+
tokenOut: hop.tokenOut,
|
|
2584
|
+
amountIn: hop.amountIn.toString(),
|
|
2585
|
+
amountOut: hop.amountOut.toString(),
|
|
2586
|
+
rate: hop.rate,
|
|
2587
|
+
inboundChannelId: hop.inboundChannelId,
|
|
2588
|
+
outboundChannelId: hop.outboundChannelId,
|
|
2589
|
+
};
|
|
2590
|
+
}
|
|
2591
|
+
return base;
|
|
2592
|
+
}),
|
|
2593
|
+
};
|
|
2594
|
+
}
|
|
2532
2595
|
const payMultiHop = async (raw) => {
|
|
2533
2596
|
const params = paramsObject(raw);
|
|
2534
2597
|
requireMutationContext(context);
|
|
2535
|
-
const
|
|
2536
|
-
if (!
|
|
2537
|
-
throw new Error('
|
|
2538
|
-
|
|
2539
|
-
const
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2598
|
+
const from = context.localParticipant?.publicKeyDigest;
|
|
2599
|
+
if (!from)
|
|
2600
|
+
throw new Error('Local participant is not configured');
|
|
2601
|
+
const amount = requiredBigInt(params, 'amount');
|
|
2602
|
+
const tokenId = requiredString(params, 'tokenId');
|
|
2603
|
+
const targetTokenId = typeof params.targetTokenId === 'string' ? params.targetTokenId : undefined;
|
|
2604
|
+
const parsedRoute = params.route
|
|
2605
|
+
? parseWireRoute(params.route)
|
|
2606
|
+
: await context.routing.getRoute({
|
|
2607
|
+
from,
|
|
2608
|
+
to: normalizeRouteNode(requiredString(params, 'toPartyId')),
|
|
2609
|
+
amount,
|
|
2610
|
+
tokenId,
|
|
2611
|
+
...(targetTokenId ? { targetTokenId } : {}),
|
|
2612
|
+
...(typeof params.maxHops === 'number' ? { maxHops: params.maxHops } : {}),
|
|
2613
|
+
});
|
|
2614
|
+
if (!parsedRoute)
|
|
2615
|
+
throw new Error('No route found');
|
|
2616
|
+
const isCrossToken = parsedRoute.hops.some((hop) => 'isSwap' in hop && hop.isSwap === true);
|
|
2544
2617
|
const parsedRequest = {
|
|
2545
|
-
hashlock: requiredString(
|
|
2546
|
-
amount
|
|
2547
|
-
tokenId
|
|
2548
|
-
expiryBlock: requiredBigInt(
|
|
2549
|
-
|
|
2550
|
-
|
|
2618
|
+
hashlock: requiredString(params, 'hashlock'),
|
|
2619
|
+
amount,
|
|
2620
|
+
tokenId,
|
|
2621
|
+
expiryBlock: requiredBigInt(params, 'expiryBlock'),
|
|
2622
|
+
...(typeof params.preimage === 'string' ? { preimage: params.preimage } : {}),
|
|
2623
|
+
...(typeof params.description === 'string' ? { description: params.description } : {}),
|
|
2551
2624
|
};
|
|
2552
|
-
|
|
2553
|
-
|
|
2625
|
+
if (!parsedRequest.preimage)
|
|
2626
|
+
throw new Error('preimage is required');
|
|
2554
2627
|
const ops = {
|
|
2555
2628
|
addHTLC: (channel, htlcParams, leaseProvider) => (0, omnia_1.addHTLC)(channel, htlcParams, leaseProvider, context.signer),
|
|
2556
2629
|
fulfillHTLC: (channel, htlcId, preimage, leaseProvider) => (0, omnia_1.fulfillHTLC)(channel, htlcId, preimage, leaseProvider, context.signer),
|
|
@@ -2588,6 +2661,7 @@ function createHostMethods(context) {
|
|
|
2588
2661
|
success: true,
|
|
2589
2662
|
preimage: result.preimage,
|
|
2590
2663
|
settledHops: result.settledHops,
|
|
2664
|
+
route: serializeWireRoute(parsedRoute),
|
|
2591
2665
|
};
|
|
2592
2666
|
});
|
|
2593
2667
|
};
|
package/dist/lifecycle.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { OmniaHostConfig } from './config.js';
|
|
2
2
|
import { ObservationBus } from './observe/bus.js';
|
|
3
|
+
import { SyncSqliteStore } from '@totemsdk/storage/sqlite-sync';
|
|
3
4
|
import type { ObservationStore } from './observe/types.js';
|
|
4
5
|
import type { OmniaSwarm, ChannelSigner, WotsLeaseProviderLike, MinimalChainProvider } from '@totemsdk/omnia';
|
|
5
6
|
import { createOmniaSwarm } from '@totemsdk/omnia';
|
|
@@ -55,6 +56,8 @@ export interface OmniaHostDependencies {
|
|
|
55
56
|
/** Observation feed: inject a store/bus (tests/embedding) or disable it. */
|
|
56
57
|
observationStore?: ObservationStore;
|
|
57
58
|
observationBus?: ObservationBus;
|
|
59
|
+
/** Synchronous storage adapter for durable factories/splices/VTXOs/pools. */
|
|
60
|
+
hostStateStore?: SyncSqliteStore;
|
|
58
61
|
observe?: boolean;
|
|
59
62
|
networkId?: string;
|
|
60
63
|
sourceNodeId?: string;
|
package/dist/lifecycle.js
CHANGED
|
@@ -9,6 +9,8 @@ const bus_js_1 = require("./observe/bus.js");
|
|
|
9
9
|
const emitter_js_1 = require("./observe/emitter.js");
|
|
10
10
|
const store_js_1 = require("./observe/store.js");
|
|
11
11
|
const snapshot_js_1 = require("./observe/snapshot.js");
|
|
12
|
+
const sqlite_sync_1 = require("@totemsdk/storage/sqlite-sync");
|
|
13
|
+
const persistent_map_js_1 = require("./stores/persistent-map.js");
|
|
12
14
|
const omnia_1 = require("@totemsdk/omnia");
|
|
13
15
|
const sqlite_store_js_1 = require("./stores/sqlite-store.js");
|
|
14
16
|
const operations_js_1 = require("./stores/operations.js");
|
|
@@ -37,6 +39,8 @@ function createOmniaHost(config, dependencies = {}) {
|
|
|
37
39
|
let ownedOperationStore;
|
|
38
40
|
let observationStore = dependencies.observationStore;
|
|
39
41
|
let ownedObservationStore;
|
|
42
|
+
let hostStateStore = dependencies.hostStateStore;
|
|
43
|
+
let ownedHostStateStore;
|
|
40
44
|
const observationBus = dependencies.observationBus ?? new bus_js_1.ObservationBus();
|
|
41
45
|
let observation;
|
|
42
46
|
let controlServer = dependencies.controlServer;
|
|
@@ -90,6 +94,16 @@ function createOmniaHost(config, dependencies = {}) {
|
|
|
90
94
|
sourceNodeId: config.sourceNodeId ?? dependencies.sourceNodeId ?? config.localPartyId ?? 'omnia-host',
|
|
91
95
|
});
|
|
92
96
|
}
|
|
97
|
+
if (!hostStateStore) {
|
|
98
|
+
try {
|
|
99
|
+
ownedHostStateStore = new sqlite_sync_1.SyncSqliteStore(config.dbPath);
|
|
100
|
+
hostStateStore = ownedHostStateStore;
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
console.error('[omnia-host] host-state store disabled:', err instanceof Error ? err.message : String(err));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const hostMap = (namespace, injected) => injected ?? (hostStateStore ? new persistent_map_js_1.PersistentMap(hostStateStore, namespace) : new Map());
|
|
93
107
|
if (!swarm) {
|
|
94
108
|
const relay = config.relay
|
|
95
109
|
? { mode: 'self-hosted', relayUrl: config.relay }
|
|
@@ -156,7 +170,7 @@ function createOmniaHost(config, dependencies = {}) {
|
|
|
156
170
|
},
|
|
157
171
|
}
|
|
158
172
|
: undefined);
|
|
159
|
-
const factories = dependencies.factories ?? (factoryBundles ?
|
|
173
|
+
const factories = dependencies.factories ?? (factoryBundles ? hostMap('omnia:factory:') : undefined);
|
|
160
174
|
const localBundle = localParticipant
|
|
161
175
|
? factoryBundles?.[localParticipant.partyId]
|
|
162
176
|
: undefined;
|
|
@@ -169,8 +183,8 @@ function createOmniaHost(config, dependencies = {}) {
|
|
|
169
183
|
: {}),
|
|
170
184
|
}
|
|
171
185
|
: undefined);
|
|
172
|
-
const spliceProposals = dependencies.spliceProposals
|
|
173
|
-
const spliceAcceptances = dependencies.spliceAcceptances
|
|
186
|
+
const spliceProposals = hostMap('omnia:splice:proposal:', dependencies.spliceProposals);
|
|
187
|
+
const spliceAcceptances = hostMap('omnia:splice:acceptance:', dependencies.spliceAcceptances);
|
|
174
188
|
const onSpliceMessage = async (peer, msg) => {
|
|
175
189
|
if (!spliceLeaseProvider || !channelStore)
|
|
176
190
|
return;
|
|
@@ -449,12 +463,12 @@ function createOmniaHost(config, dependencies = {}) {
|
|
|
449
463
|
const preparedOpen = new Map();
|
|
450
464
|
const preparedSplice = new Map();
|
|
451
465
|
const preparedFactory = new Map();
|
|
452
|
-
const vtxoPools =
|
|
453
|
-
const vtxos =
|
|
454
|
-
const vtxoReceipts =
|
|
466
|
+
const vtxoPools = hostMap('omnia:vtxo:pool:');
|
|
467
|
+
const vtxos = hostMap('omnia:vtxo:');
|
|
468
|
+
const vtxoReceipts = hostMap('omnia:vtxo:receipt:');
|
|
455
469
|
const preparedVtxoReceipts = new Map();
|
|
456
|
-
const pools =
|
|
457
|
-
const poolPositions =
|
|
470
|
+
const pools = hostMap('omnia:pool:');
|
|
471
|
+
const poolPositions = hostMap('omnia:pool:position:');
|
|
458
472
|
if (!controlServer) {
|
|
459
473
|
const readOnly = !dependencies.signer || !dependencies.leaseProvider;
|
|
460
474
|
if (readOnly) {
|
|
@@ -567,6 +581,8 @@ function createOmniaHost(config, dependencies = {}) {
|
|
|
567
581
|
if (ownedObservationStore)
|
|
568
582
|
await ownedObservationStore.close();
|
|
569
583
|
ownedObservationStore = undefined;
|
|
584
|
+
ownedHostStateStore?.close();
|
|
585
|
+
ownedHostStateStore = undefined;
|
|
570
586
|
ownedStore?.close();
|
|
571
587
|
ownedStore = undefined;
|
|
572
588
|
started = false;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { SyncSqliteStore } from '@totemsdk/storage/sqlite-sync';
|
|
2
|
+
/**
|
|
3
|
+
* Durable Map facade for host state (factories, virtual channels, splices,
|
|
4
|
+
* VTXOs, pools). Backed by `@totemsdk/storage/sqlite-sync` (same `totemsdk_kv`
|
|
5
|
+
* table + versioned codec as the channel/operation stores).
|
|
6
|
+
*
|
|
7
|
+
* Values are plain objects/arrays/bigints/Uint8Arrays. Runtime-only handles
|
|
8
|
+
* (`localSigner`, signer/lease/swarm objects) are stripped; Map/Set/Date are
|
|
9
|
+
* explicitly tagged so they round-trip. A function anywhere else is dropped
|
|
10
|
+
* rather than persisted (never serialise authority material by accident).
|
|
11
|
+
*/
|
|
12
|
+
export declare const HOST_STATE_FORMAT_KEY = "omnia:store:host-state:format";
|
|
13
|
+
export declare const HOST_STATE_FORMAT = 1;
|
|
14
|
+
export declare class PersistentMap<V> extends Map<string, V> {
|
|
15
|
+
private readonly kv;
|
|
16
|
+
private readonly namespace;
|
|
17
|
+
constructor(kv: SyncSqliteStore, namespace: string);
|
|
18
|
+
private key;
|
|
19
|
+
private keysInNamespace;
|
|
20
|
+
get(id: string): V | undefined;
|
|
21
|
+
set(id: string, value: V): this;
|
|
22
|
+
has(id: string): boolean;
|
|
23
|
+
delete(id: string): boolean;
|
|
24
|
+
clear(): void;
|
|
25
|
+
get size(): number;
|
|
26
|
+
keys(): MapIterator<string>;
|
|
27
|
+
values(): MapIterator<V>;
|
|
28
|
+
entries(): MapIterator<[string, V]>;
|
|
29
|
+
[Symbol.iterator](): MapIterator<[string, V]>;
|
|
30
|
+
forEach(callbackfn: (value: V, key: string, map: Map<string, V>) => void): void;
|
|
31
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PersistentMap = exports.HOST_STATE_FORMAT = exports.HOST_STATE_FORMAT_KEY = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Durable Map facade for host state (factories, virtual channels, splices,
|
|
6
|
+
* VTXOs, pools). Backed by `@totemsdk/storage/sqlite-sync` (same `totemsdk_kv`
|
|
7
|
+
* table + versioned codec as the channel/operation stores).
|
|
8
|
+
*
|
|
9
|
+
* Values are plain objects/arrays/bigints/Uint8Arrays. Runtime-only handles
|
|
10
|
+
* (`localSigner`, signer/lease/swarm objects) are stripped; Map/Set/Date are
|
|
11
|
+
* explicitly tagged so they round-trip. A function anywhere else is dropped
|
|
12
|
+
* rather than persisted (never serialise authority material by accident).
|
|
13
|
+
*/
|
|
14
|
+
exports.HOST_STATE_FORMAT_KEY = 'omnia:store:host-state:format';
|
|
15
|
+
exports.HOST_STATE_FORMAT = 1;
|
|
16
|
+
const EPHEMERAL_KEYS = new Set([
|
|
17
|
+
'localSigner',
|
|
18
|
+
'signer',
|
|
19
|
+
'leaseProvider',
|
|
20
|
+
'signerPort',
|
|
21
|
+
'swarm',
|
|
22
|
+
'routing',
|
|
23
|
+
]);
|
|
24
|
+
function encode(value, seen = new WeakSet()) {
|
|
25
|
+
if (value === null || value === undefined)
|
|
26
|
+
return null;
|
|
27
|
+
if (typeof value === 'bigint')
|
|
28
|
+
return value;
|
|
29
|
+
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
if (typeof value === 'function')
|
|
33
|
+
return null;
|
|
34
|
+
if (value instanceof Uint8Array)
|
|
35
|
+
return value;
|
|
36
|
+
if (value instanceof Date)
|
|
37
|
+
return { $date: value.toISOString() };
|
|
38
|
+
if (Array.isArray(value)) {
|
|
39
|
+
return value.map((item) => encode(item, seen));
|
|
40
|
+
}
|
|
41
|
+
if (value instanceof Map) {
|
|
42
|
+
const entries = [];
|
|
43
|
+
for (const [key, item] of value.entries())
|
|
44
|
+
entries.push([String(key), encode(item, seen)]);
|
|
45
|
+
return { $map: entries };
|
|
46
|
+
}
|
|
47
|
+
if (value instanceof Set) {
|
|
48
|
+
return { $set: Array.from(value.values(), (item) => encode(item, seen)) };
|
|
49
|
+
}
|
|
50
|
+
if (typeof value === 'object') {
|
|
51
|
+
if (seen.has(value))
|
|
52
|
+
throw new Error('cannot persist cyclic host state');
|
|
53
|
+
seen.add(value);
|
|
54
|
+
const out = {};
|
|
55
|
+
for (const [key, item] of Object.entries(value)) {
|
|
56
|
+
if (EPHEMERAL_KEYS.has(key) || item === undefined || typeof item === 'function')
|
|
57
|
+
continue;
|
|
58
|
+
out[key] = encode(item, seen);
|
|
59
|
+
}
|
|
60
|
+
seen.delete(value);
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
function decode(value) {
|
|
66
|
+
if (value === null)
|
|
67
|
+
return null;
|
|
68
|
+
if (typeof value === 'bigint' ||
|
|
69
|
+
typeof value === 'string' ||
|
|
70
|
+
typeof value === 'number' ||
|
|
71
|
+
typeof value === 'boolean') {
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
74
|
+
if (value instanceof Uint8Array)
|
|
75
|
+
return value;
|
|
76
|
+
if (Array.isArray(value))
|
|
77
|
+
return value.map(decode);
|
|
78
|
+
if (typeof value === 'object') {
|
|
79
|
+
const record = value;
|
|
80
|
+
if (Array.isArray(record['$map'])) {
|
|
81
|
+
return new Map(record['$map'].map(([key, item]) => [key, decode(item)]));
|
|
82
|
+
}
|
|
83
|
+
if (Array.isArray(record['$set'])) {
|
|
84
|
+
return new Set(record['$set'].map(decode));
|
|
85
|
+
}
|
|
86
|
+
if (typeof record['$date'] === 'string')
|
|
87
|
+
return new Date(record['$date']);
|
|
88
|
+
const out = {};
|
|
89
|
+
for (const [key, item] of Object.entries(record))
|
|
90
|
+
out[key] = decode(item);
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
93
|
+
return value;
|
|
94
|
+
}
|
|
95
|
+
function iterator(values) {
|
|
96
|
+
let index = 0;
|
|
97
|
+
return {
|
|
98
|
+
next() {
|
|
99
|
+
if (index >= values.length)
|
|
100
|
+
return { done: true, value: undefined };
|
|
101
|
+
return { done: false, value: values[index++] };
|
|
102
|
+
},
|
|
103
|
+
[Symbol.iterator]() {
|
|
104
|
+
return this;
|
|
105
|
+
},
|
|
106
|
+
[Symbol.dispose]() {
|
|
107
|
+
index = values.length;
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
class PersistentMap extends Map {
|
|
112
|
+
kv;
|
|
113
|
+
namespace;
|
|
114
|
+
constructor(kv, namespace) {
|
|
115
|
+
super();
|
|
116
|
+
this.kv = kv;
|
|
117
|
+
this.namespace = namespace;
|
|
118
|
+
const format = kv.get(exports.HOST_STATE_FORMAT_KEY);
|
|
119
|
+
if (format !== null && format !== exports.HOST_STATE_FORMAT) {
|
|
120
|
+
throw new Error(`Unsupported omnia-host state format ${format} (this build supports ${exports.HOST_STATE_FORMAT}) — refusing to open`);
|
|
121
|
+
}
|
|
122
|
+
if (format === null)
|
|
123
|
+
kv.set(exports.HOST_STATE_FORMAT_KEY, exports.HOST_STATE_FORMAT);
|
|
124
|
+
}
|
|
125
|
+
key(id) {
|
|
126
|
+
return this.namespace + id;
|
|
127
|
+
}
|
|
128
|
+
keysInNamespace() {
|
|
129
|
+
return this.kv.keys().filter((key) => key.startsWith(this.namespace));
|
|
130
|
+
}
|
|
131
|
+
get(id) {
|
|
132
|
+
const raw = this.kv.get(this.key(id));
|
|
133
|
+
return raw === null ? undefined : decode(raw);
|
|
134
|
+
}
|
|
135
|
+
set(id, value) {
|
|
136
|
+
this.kv.set(this.key(id), encode(value));
|
|
137
|
+
return this;
|
|
138
|
+
}
|
|
139
|
+
has(id) {
|
|
140
|
+
return this.kv.has(this.key(id));
|
|
141
|
+
}
|
|
142
|
+
delete(id) {
|
|
143
|
+
return this.kv.remove(this.key(id));
|
|
144
|
+
}
|
|
145
|
+
clear() {
|
|
146
|
+
for (const key of this.keysInNamespace())
|
|
147
|
+
this.kv.remove(key);
|
|
148
|
+
}
|
|
149
|
+
get size() {
|
|
150
|
+
return this.keysInNamespace().length;
|
|
151
|
+
}
|
|
152
|
+
keys() {
|
|
153
|
+
return iterator(this.keysInNamespace().map((key) => key.slice(this.namespace.length)));
|
|
154
|
+
}
|
|
155
|
+
values() {
|
|
156
|
+
return iterator(Array.from(this.entries(), ([, value]) => value));
|
|
157
|
+
}
|
|
158
|
+
entries() {
|
|
159
|
+
return iterator(this.keysInNamespace().map((key) => [
|
|
160
|
+
key.slice(this.namespace.length),
|
|
161
|
+
decode(this.kv.get(key)),
|
|
162
|
+
]));
|
|
163
|
+
}
|
|
164
|
+
[Symbol.iterator]() {
|
|
165
|
+
return this.entries();
|
|
166
|
+
}
|
|
167
|
+
forEach(callbackfn) {
|
|
168
|
+
for (const [key, value] of this.entries())
|
|
169
|
+
callbackfn(value, key, this);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
exports.PersistentMap = PersistentMap;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@totemsdk/omnia-host",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Durable Omnia node daemon for channel lifecycle, routing, and control APIs",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -22,21 +22,21 @@
|
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"ws": "^8.21.1",
|
|
25
|
+
"@totemsdk/chain-provider": "^0.3.0",
|
|
25
26
|
"@totemsdk/core": "^1.4.0",
|
|
26
27
|
"@totemsdk/identity": "^1.0.2",
|
|
27
|
-
"@totemsdk/chain-provider": "^0.3.0",
|
|
28
28
|
"@totemsdk/liquidity-bond": "^0.3.1",
|
|
29
|
-
"@totemsdk/manifest": "^2.0.
|
|
29
|
+
"@totemsdk/manifest": "^2.0.2",
|
|
30
30
|
"@totemsdk/minima-rpc": "^0.4.0",
|
|
31
31
|
"@totemsdk/omnia": "^2.3.1",
|
|
32
|
+
"@totemsdk/omnia-pool": "^0.5.3",
|
|
32
33
|
"@totemsdk/omnia-factory": "^0.7.0",
|
|
33
34
|
"@totemsdk/omnia-router": "^0.4.0",
|
|
34
|
-
"@totemsdk/omnia-pool": "^0.5.3",
|
|
35
35
|
"@totemsdk/omnia-splice": "^0.3.0",
|
|
36
|
-
"@totemsdk/p2p-hub": "^0.1.0",
|
|
37
36
|
"@totemsdk/omnia-vtxo": "^0.6.1",
|
|
38
|
-
"@totemsdk/
|
|
39
|
-
"@totemsdk/
|
|
37
|
+
"@totemsdk/wots-lease": "^1.0.1",
|
|
38
|
+
"@totemsdk/storage": "^0.2.1",
|
|
39
|
+
"@totemsdk/p2p-hub": "^0.1.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/jest": "^30.0.0",
|