@unicitylabs/sphere-sdk 0.6.2 → 0.6.4
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/core/index.cjs +4317 -1470
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +350 -3
- package/dist/core/index.d.ts +350 -3
- package/dist/core/index.js +4321 -1452
- package/dist/core/index.js.map +1 -1
- package/dist/impl/browser/index.cjs +154 -21
- package/dist/impl/browser/index.cjs.map +1 -1
- package/dist/impl/browser/index.js +154 -21
- package/dist/impl/browser/index.js.map +1 -1
- package/dist/impl/browser/ipfs.cjs +38 -10
- package/dist/impl/browser/ipfs.cjs.map +1 -1
- package/dist/impl/browser/ipfs.js +38 -10
- package/dist/impl/browser/ipfs.js.map +1 -1
- package/dist/impl/nodejs/index.cjs +150 -21
- package/dist/impl/nodejs/index.cjs.map +1 -1
- package/dist/impl/nodejs/index.d.cts +55 -0
- package/dist/impl/nodejs/index.d.ts +55 -0
- package/dist/impl/nodejs/index.js +150 -21
- package/dist/impl/nodejs/index.js.map +1 -1
- package/dist/index.cjs +4301 -1480
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +43 -2
- package/dist/index.d.ts +43 -2
- package/dist/index.js +4314 -1471
- package/dist/index.js.map +1 -1
- package/dist/l1/index.d.cts +717 -0
- package/dist/l1/index.d.ts +717 -0
- package/package.json +1 -1
|
@@ -368,7 +368,7 @@ var path2 = __toESM(require("path"), 1);
|
|
|
368
368
|
var META_FILE = "_meta.json";
|
|
369
369
|
var TOMBSTONES_FILE = "_tombstones.json";
|
|
370
370
|
var HISTORY_FILE = "_history.json";
|
|
371
|
-
var FileTokenStorageProvider = class {
|
|
371
|
+
var FileTokenStorageProvider = class _FileTokenStorageProvider {
|
|
372
372
|
id = "file-token-storage";
|
|
373
373
|
name = "File Token Storage";
|
|
374
374
|
type = "local";
|
|
@@ -595,6 +595,12 @@ var FileTokenStorageProvider = class {
|
|
|
595
595
|
}
|
|
596
596
|
return imported;
|
|
597
597
|
}
|
|
598
|
+
/**
|
|
599
|
+
* Create an independent instance for a different address.
|
|
600
|
+
*/
|
|
601
|
+
createForAddress() {
|
|
602
|
+
return new _FileTokenStorageProvider({ tokensDir: this.baseTokensDir });
|
|
603
|
+
}
|
|
598
604
|
};
|
|
599
605
|
function createFileTokenStorageProvider(config) {
|
|
600
606
|
return new FileTokenStorageProvider(config);
|
|
@@ -1109,7 +1115,7 @@ function defaultUUIDGenerator() {
|
|
|
1109
1115
|
var COMPOSING_INDICATOR_KIND = 25050;
|
|
1110
1116
|
var TIMESTAMP_RANDOMIZATION = 2 * 24 * 60 * 60;
|
|
1111
1117
|
var EVENT_KINDS = NOSTR_EVENT_KINDS;
|
|
1112
|
-
var NostrTransportProvider = class {
|
|
1118
|
+
var NostrTransportProvider = class _NostrTransportProvider {
|
|
1113
1119
|
id = "nostr";
|
|
1114
1120
|
name = "Nostr Transport";
|
|
1115
1121
|
type = "p2p";
|
|
@@ -1118,6 +1124,8 @@ var NostrTransportProvider = class {
|
|
|
1118
1124
|
storage = null;
|
|
1119
1125
|
/** In-memory max event timestamp to avoid read-before-write races in updateLastEventTimestamp. */
|
|
1120
1126
|
lastEventTs = 0;
|
|
1127
|
+
/** Fallback 'since' timestamp for first-time address subscriptions (consumed once). */
|
|
1128
|
+
fallbackSince = null;
|
|
1121
1129
|
identity = null;
|
|
1122
1130
|
keyManager = null;
|
|
1123
1131
|
status = "disconnected";
|
|
@@ -1150,6 +1158,48 @@ var NostrTransportProvider = class {
|
|
|
1150
1158
|
};
|
|
1151
1159
|
this.storage = config.storage ?? null;
|
|
1152
1160
|
}
|
|
1161
|
+
/**
|
|
1162
|
+
* Get the WebSocket factory (used by MultiAddressTransportMux to share the same factory).
|
|
1163
|
+
*/
|
|
1164
|
+
getWebSocketFactory() {
|
|
1165
|
+
return this.config.createWebSocket;
|
|
1166
|
+
}
|
|
1167
|
+
/**
|
|
1168
|
+
* Get the configured relay URLs.
|
|
1169
|
+
*/
|
|
1170
|
+
getConfiguredRelays() {
|
|
1171
|
+
return [...this.config.relays];
|
|
1172
|
+
}
|
|
1173
|
+
/**
|
|
1174
|
+
* Get the storage adapter.
|
|
1175
|
+
*/
|
|
1176
|
+
getStorageAdapter() {
|
|
1177
|
+
return this.storage;
|
|
1178
|
+
}
|
|
1179
|
+
/**
|
|
1180
|
+
* Suppress event subscriptions — unsubscribe wallet/chat filters
|
|
1181
|
+
* but keep the connection alive for resolve/identity-binding operations.
|
|
1182
|
+
* Used when MultiAddressTransportMux takes over event handling.
|
|
1183
|
+
*/
|
|
1184
|
+
suppressSubscriptions() {
|
|
1185
|
+
if (!this.nostrClient) return;
|
|
1186
|
+
if (this.walletSubscriptionId) {
|
|
1187
|
+
this.nostrClient.unsubscribe(this.walletSubscriptionId);
|
|
1188
|
+
this.walletSubscriptionId = null;
|
|
1189
|
+
}
|
|
1190
|
+
if (this.chatSubscriptionId) {
|
|
1191
|
+
this.nostrClient.unsubscribe(this.chatSubscriptionId);
|
|
1192
|
+
this.chatSubscriptionId = null;
|
|
1193
|
+
}
|
|
1194
|
+
if (this.mainSubscriptionId) {
|
|
1195
|
+
this.nostrClient.unsubscribe(this.mainSubscriptionId);
|
|
1196
|
+
this.mainSubscriptionId = null;
|
|
1197
|
+
}
|
|
1198
|
+
this._subscriptionsSuppressed = true;
|
|
1199
|
+
logger.debug("Nostr", "Subscriptions suppressed \u2014 mux handles event routing");
|
|
1200
|
+
}
|
|
1201
|
+
// Flag to prevent re-subscription after suppressSubscriptions()
|
|
1202
|
+
_subscriptionsSuppressed = false;
|
|
1153
1203
|
// ===========================================================================
|
|
1154
1204
|
// BaseProvider Implementation
|
|
1155
1205
|
// ===========================================================================
|
|
@@ -1328,6 +1378,8 @@ var NostrTransportProvider = class {
|
|
|
1328
1378
|
// ===========================================================================
|
|
1329
1379
|
async setIdentity(identity) {
|
|
1330
1380
|
this.identity = identity;
|
|
1381
|
+
this.processedEventIds.clear();
|
|
1382
|
+
this.lastEventTs = 0;
|
|
1331
1383
|
const secretKey = import_buffer.Buffer.from(identity.privateKey, "hex");
|
|
1332
1384
|
this.keyManager = import_nostr_js_sdk.NostrKeyManager.fromPrivateKey(secretKey);
|
|
1333
1385
|
const nostrPubkey = this.keyManager.getPublicKeyHex();
|
|
@@ -1370,6 +1422,9 @@ var NostrTransportProvider = class {
|
|
|
1370
1422
|
await this.subscribeToEvents();
|
|
1371
1423
|
}
|
|
1372
1424
|
}
|
|
1425
|
+
setFallbackSince(sinceSeconds) {
|
|
1426
|
+
this.fallbackSince = sinceSeconds;
|
|
1427
|
+
}
|
|
1373
1428
|
/**
|
|
1374
1429
|
* Get the Nostr-format public key (32 bytes / 64 hex chars)
|
|
1375
1430
|
* This is the x-coordinate only, without the 02/03 prefix.
|
|
@@ -1591,11 +1646,11 @@ var NostrTransportProvider = class {
|
|
|
1591
1646
|
return this.resolveNametagInfo(identifier);
|
|
1592
1647
|
}
|
|
1593
1648
|
async resolveNametag(nametag) {
|
|
1594
|
-
this.
|
|
1649
|
+
await this.ensureConnectedForResolve();
|
|
1595
1650
|
return this.nostrClient.queryPubkeyByNametag(nametag);
|
|
1596
1651
|
}
|
|
1597
1652
|
async resolveNametagInfo(nametag) {
|
|
1598
|
-
this.
|
|
1653
|
+
await this.ensureConnectedForResolve();
|
|
1599
1654
|
const binding = await this.nostrClient.queryBindingByNametag(nametag);
|
|
1600
1655
|
if (!binding) {
|
|
1601
1656
|
logger.debug("Nostr", `resolveNametagInfo: no binding events found for Unicity ID "${nametag}"`);
|
|
@@ -1608,7 +1663,7 @@ var NostrTransportProvider = class {
|
|
|
1608
1663
|
* Performs reverse lookup via nostr-js-sdk with first-seen-wins anti-hijacking.
|
|
1609
1664
|
*/
|
|
1610
1665
|
async resolveAddressInfo(address) {
|
|
1611
|
-
this.
|
|
1666
|
+
await this.ensureConnectedForResolve();
|
|
1612
1667
|
const binding = await this.nostrClient.queryBindingByAddress(address);
|
|
1613
1668
|
if (!binding) return null;
|
|
1614
1669
|
return this.bindingInfoToPeerInfo(binding);
|
|
@@ -1643,7 +1698,7 @@ var NostrTransportProvider = class {
|
|
|
1643
1698
|
* Queries binding events authored by the given pubkey.
|
|
1644
1699
|
*/
|
|
1645
1700
|
async resolveTransportPubkeyInfo(transportPubkey) {
|
|
1646
|
-
this.
|
|
1701
|
+
await this.ensureConnectedForResolve();
|
|
1647
1702
|
const events = await this.queryEvents({
|
|
1648
1703
|
kinds: [EVENT_KINDS.NAMETAG_BINDING],
|
|
1649
1704
|
authors: [transportPubkey],
|
|
@@ -1678,7 +1733,7 @@ var NostrTransportProvider = class {
|
|
|
1678
1733
|
* Used for HD address discovery — single relay query with multi-author filter.
|
|
1679
1734
|
*/
|
|
1680
1735
|
async discoverAddresses(transportPubkeys) {
|
|
1681
|
-
this.
|
|
1736
|
+
await this.ensureConnectedForResolve();
|
|
1682
1737
|
if (transportPubkeys.length === 0) return [];
|
|
1683
1738
|
const events = await this.queryEvents({
|
|
1684
1739
|
kinds: [EVENT_KINDS.NAMETAG_BINDING],
|
|
@@ -1717,7 +1772,10 @@ var NostrTransportProvider = class {
|
|
|
1717
1772
|
* @returns Decrypted nametag or null if none found
|
|
1718
1773
|
*/
|
|
1719
1774
|
async recoverNametag() {
|
|
1720
|
-
this.
|
|
1775
|
+
await this.ensureConnectedForResolve();
|
|
1776
|
+
if (!this.identity) {
|
|
1777
|
+
throw new SphereError("Identity not set", "NOT_INITIALIZED");
|
|
1778
|
+
}
|
|
1721
1779
|
if (!this.identity || !this.keyManager) {
|
|
1722
1780
|
throw new SphereError("Identity not set", "NOT_INITIALIZED");
|
|
1723
1781
|
}
|
|
@@ -2277,6 +2335,10 @@ var NostrTransportProvider = class {
|
|
|
2277
2335
|
chatEoseFired = false;
|
|
2278
2336
|
async subscribeToEvents() {
|
|
2279
2337
|
logger.debug("Nostr", "subscribeToEvents called, identity:", !!this.identity, "keyManager:", !!this.keyManager, "nostrClient:", !!this.nostrClient);
|
|
2338
|
+
if (this._subscriptionsSuppressed) {
|
|
2339
|
+
logger.debug("Nostr", "subscribeToEvents: suppressed \u2014 mux handles event routing");
|
|
2340
|
+
return;
|
|
2341
|
+
}
|
|
2280
2342
|
if (!this.identity || !this.keyManager || !this.nostrClient) {
|
|
2281
2343
|
logger.debug("Nostr", "subscribeToEvents: skipped - no identity, keyManager, or nostrClient");
|
|
2282
2344
|
return;
|
|
@@ -2303,7 +2365,13 @@ var NostrTransportProvider = class {
|
|
|
2303
2365
|
if (stored) {
|
|
2304
2366
|
since = parseInt(stored, 10);
|
|
2305
2367
|
this.lastEventTs = since;
|
|
2368
|
+
this.fallbackSince = null;
|
|
2306
2369
|
logger.debug("Nostr", "Resuming from stored event timestamp:", since);
|
|
2370
|
+
} else if (this.fallbackSince !== null) {
|
|
2371
|
+
since = this.fallbackSince;
|
|
2372
|
+
this.lastEventTs = since;
|
|
2373
|
+
this.fallbackSince = null;
|
|
2374
|
+
logger.debug("Nostr", "Using fallback since timestamp:", since);
|
|
2307
2375
|
} else {
|
|
2308
2376
|
since = Math.floor(Date.now() / 1e3);
|
|
2309
2377
|
logger.debug("Nostr", "No stored timestamp, starting from now:", since);
|
|
@@ -2311,6 +2379,7 @@ var NostrTransportProvider = class {
|
|
|
2311
2379
|
} catch (err) {
|
|
2312
2380
|
logger.debug("Nostr", "Failed to read last event timestamp, falling back to now:", err);
|
|
2313
2381
|
since = Math.floor(Date.now() / 1e3);
|
|
2382
|
+
this.fallbackSince = null;
|
|
2314
2383
|
}
|
|
2315
2384
|
} else {
|
|
2316
2385
|
since = Math.floor(Date.now() / 1e3) - 86400;
|
|
@@ -2442,6 +2511,31 @@ var NostrTransportProvider = class {
|
|
|
2442
2511
|
throw new SphereError("NostrTransportProvider not connected", "TRANSPORT_ERROR");
|
|
2443
2512
|
}
|
|
2444
2513
|
}
|
|
2514
|
+
/**
|
|
2515
|
+
* Async version of ensureConnected — reconnects if the original transport
|
|
2516
|
+
* lost its WebSocket while subscriptions are suppressed (mux handles events).
|
|
2517
|
+
* Used by resolve methods which are always async.
|
|
2518
|
+
*/
|
|
2519
|
+
async ensureConnectedForResolve() {
|
|
2520
|
+
if (this.isConnected()) return;
|
|
2521
|
+
if (this._subscriptionsSuppressed && this.nostrClient) {
|
|
2522
|
+
logger.debug("Nostr", "Suppressed transport disconnected \u2014 reconnecting for resolve");
|
|
2523
|
+
try {
|
|
2524
|
+
await Promise.race([
|
|
2525
|
+
this.nostrClient.connect(...this.config.relays),
|
|
2526
|
+
new Promise(
|
|
2527
|
+
(_, reject) => setTimeout(() => reject(new Error("reconnect timeout")), 5e3)
|
|
2528
|
+
)
|
|
2529
|
+
]);
|
|
2530
|
+
if (this.nostrClient.isConnected()) {
|
|
2531
|
+
this.status = "connected";
|
|
2532
|
+
return;
|
|
2533
|
+
}
|
|
2534
|
+
} catch {
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
throw new SphereError("NostrTransportProvider not connected", "TRANSPORT_ERROR");
|
|
2538
|
+
}
|
|
2445
2539
|
ensureReady() {
|
|
2446
2540
|
this.ensureConnected();
|
|
2447
2541
|
if (!this.identity) {
|
|
@@ -2463,16 +2557,23 @@ var NostrTransportProvider = class {
|
|
|
2463
2557
|
* because NIP17.createGiftWrap hardcodes kind 14 for the inner rumor.
|
|
2464
2558
|
*/
|
|
2465
2559
|
createCustomKindGiftWrap(recipientPubkeyHex, content, rumorKind) {
|
|
2466
|
-
|
|
2560
|
+
return _NostrTransportProvider.createCustomKindGiftWrap(this.keyManager, recipientPubkeyHex, content, rumorKind);
|
|
2561
|
+
}
|
|
2562
|
+
/**
|
|
2563
|
+
* Create a NIP-17 gift wrap with a custom rumor kind.
|
|
2564
|
+
* Shared between NostrTransportProvider and MultiAddressTransportMux.
|
|
2565
|
+
*/
|
|
2566
|
+
static createCustomKindGiftWrap(keyManager, recipientPubkeyHex, content, rumorKind) {
|
|
2567
|
+
const senderPubkey = keyManager.getPublicKeyHex();
|
|
2467
2568
|
const now = Math.floor(Date.now() / 1e3);
|
|
2468
2569
|
const rumorTags = [["p", recipientPubkeyHex]];
|
|
2469
2570
|
const rumorSerialized = JSON.stringify([0, senderPubkey, now, rumorKind, rumorTags, content]);
|
|
2470
2571
|
const rumorId = bytesToHex(sha256(new TextEncoder().encode(rumorSerialized)));
|
|
2471
2572
|
const rumor = { id: rumorId, pubkey: senderPubkey, created_at: now, kind: rumorKind, tags: rumorTags, content };
|
|
2472
2573
|
const recipientPubkeyBytes = hexToBytes(recipientPubkeyHex);
|
|
2473
|
-
const encryptedRumor = import_nostr_js_sdk.NIP44.encrypt(JSON.stringify(rumor),
|
|
2574
|
+
const encryptedRumor = import_nostr_js_sdk.NIP44.encrypt(JSON.stringify(rumor), keyManager.getPrivateKey(), recipientPubkeyBytes);
|
|
2474
2575
|
const sealTimestamp = now + Math.floor(Math.random() * 2 * TIMESTAMP_RANDOMIZATION) - TIMESTAMP_RANDOMIZATION;
|
|
2475
|
-
const seal = import_nostr_js_sdk.Event.create(
|
|
2576
|
+
const seal = import_nostr_js_sdk.Event.create(keyManager, {
|
|
2476
2577
|
kind: import_nostr_js_sdk.EventKinds.SEAL,
|
|
2477
2578
|
tags: [],
|
|
2478
2579
|
content: encryptedRumor,
|
|
@@ -4278,11 +4379,17 @@ var AsyncSerialQueue = class {
|
|
|
4278
4379
|
var WriteBuffer = class {
|
|
4279
4380
|
/** Full TXF data from save() calls — latest wins */
|
|
4280
4381
|
txfData = null;
|
|
4382
|
+
/** IPNS context captured at save() time — ensures flush writes to the correct
|
|
4383
|
+
* IPNS record even if identity changes between save() and flush(). */
|
|
4384
|
+
capturedIpnsKeyPair = null;
|
|
4385
|
+
capturedIpnsName = null;
|
|
4281
4386
|
get isEmpty() {
|
|
4282
4387
|
return this.txfData === null;
|
|
4283
4388
|
}
|
|
4284
4389
|
clear() {
|
|
4285
4390
|
this.txfData = null;
|
|
4391
|
+
this.capturedIpnsKeyPair = null;
|
|
4392
|
+
this.capturedIpnsName = null;
|
|
4286
4393
|
}
|
|
4287
4394
|
/**
|
|
4288
4395
|
* Merge another buffer's contents into this one (for rollback).
|
|
@@ -4291,12 +4398,14 @@ var WriteBuffer = class {
|
|
|
4291
4398
|
mergeFrom(other) {
|
|
4292
4399
|
if (other.txfData && !this.txfData) {
|
|
4293
4400
|
this.txfData = other.txfData;
|
|
4401
|
+
this.capturedIpnsKeyPair = other.capturedIpnsKeyPair;
|
|
4402
|
+
this.capturedIpnsName = other.capturedIpnsName;
|
|
4294
4403
|
}
|
|
4295
4404
|
}
|
|
4296
4405
|
};
|
|
4297
4406
|
|
|
4298
4407
|
// impl/shared/ipfs/ipfs-storage-provider.ts
|
|
4299
|
-
var IpfsStorageProvider = class {
|
|
4408
|
+
var IpfsStorageProvider = class _IpfsStorageProvider {
|
|
4300
4409
|
id = "ipfs";
|
|
4301
4410
|
name = "IPFS Storage";
|
|
4302
4411
|
type = "p2p";
|
|
@@ -4341,7 +4450,12 @@ var IpfsStorageProvider = class {
|
|
|
4341
4450
|
flushDebounceMs;
|
|
4342
4451
|
/** Set to true during shutdown to prevent new flushes */
|
|
4343
4452
|
isShuttingDown = false;
|
|
4453
|
+
/** Stored config for createForAddress() cloning */
|
|
4454
|
+
_config;
|
|
4455
|
+
_statePersistenceCtor;
|
|
4344
4456
|
constructor(config, statePersistence) {
|
|
4457
|
+
this._config = config;
|
|
4458
|
+
this._statePersistenceCtor = statePersistence;
|
|
4345
4459
|
const gateways = config?.gateways ?? getIpfsGatewayUrls();
|
|
4346
4460
|
this.debug = config?.debug ?? false;
|
|
4347
4461
|
this.ipnsLifetimeMs = config?.ipnsLifetimeMs ?? 99 * 365 * 24 * 60 * 60 * 1e3;
|
|
@@ -4461,6 +4575,7 @@ var IpfsStorageProvider = class {
|
|
|
4461
4575
|
}
|
|
4462
4576
|
async shutdown() {
|
|
4463
4577
|
this.isShuttingDown = true;
|
|
4578
|
+
logger.debug("IPFS-Storage", `shutdown: ipnsName=${this.ipnsName?.slice(0, 20)}..., pendingEmpty=${this.pendingBuffer.isEmpty}, capturedIpns=${this.pendingBuffer.capturedIpnsName?.slice(0, 20) ?? "none"}`);
|
|
4464
4579
|
if (this.flushTimer) {
|
|
4465
4580
|
clearTimeout(this.flushTimer);
|
|
4466
4581
|
this.flushTimer = null;
|
|
@@ -4493,6 +4608,8 @@ var IpfsStorageProvider = class {
|
|
|
4493
4608
|
return { success: false, error: "Not initialized", timestamp: Date.now() };
|
|
4494
4609
|
}
|
|
4495
4610
|
this.pendingBuffer.txfData = data;
|
|
4611
|
+
this.pendingBuffer.capturedIpnsKeyPair = this.ipnsKeyPair;
|
|
4612
|
+
this.pendingBuffer.capturedIpnsName = this.ipnsName;
|
|
4496
4613
|
this.scheduleFlush();
|
|
4497
4614
|
return { success: true, timestamp: Date.now() };
|
|
4498
4615
|
}
|
|
@@ -4503,8 +4620,12 @@ var IpfsStorageProvider = class {
|
|
|
4503
4620
|
* Perform the actual upload + IPNS publish synchronously.
|
|
4504
4621
|
* Called by executeFlush() and sync() — never by public save().
|
|
4505
4622
|
*/
|
|
4506
|
-
async _doSave(data) {
|
|
4507
|
-
|
|
4623
|
+
async _doSave(data, overrideIpns) {
|
|
4624
|
+
const ipnsKeyPair = overrideIpns?.keyPair ?? this.ipnsKeyPair;
|
|
4625
|
+
const ipnsName = overrideIpns?.name ?? this.ipnsName;
|
|
4626
|
+
const metaAddr = data?._meta?.address;
|
|
4627
|
+
logger.debug("IPFS-Storage", `_doSave: ipnsName=${ipnsName?.slice(0, 20)}..., override=${!!overrideIpns}, meta.address=${metaAddr?.slice(0, 20) ?? "none"}`);
|
|
4628
|
+
if (!ipnsKeyPair || !ipnsName) {
|
|
4508
4629
|
return { success: false, error: "Not initialized", timestamp: Date.now() };
|
|
4509
4630
|
}
|
|
4510
4631
|
this.emitEvent({ type: "storage:saving", timestamp: Date.now() });
|
|
@@ -4513,7 +4634,7 @@ var IpfsStorageProvider = class {
|
|
|
4513
4634
|
const metaUpdate = {
|
|
4514
4635
|
...data._meta,
|
|
4515
4636
|
version: this.dataVersion,
|
|
4516
|
-
ipnsName
|
|
4637
|
+
ipnsName,
|
|
4517
4638
|
updatedAt: Date.now()
|
|
4518
4639
|
};
|
|
4519
4640
|
if (this.remoteCid) {
|
|
@@ -4525,13 +4646,13 @@ var IpfsStorageProvider = class {
|
|
|
4525
4646
|
const baseSeq = this.ipnsSequenceNumber > this.lastKnownRemoteSequence ? this.ipnsSequenceNumber : this.lastKnownRemoteSequence;
|
|
4526
4647
|
const newSeq = baseSeq + 1n;
|
|
4527
4648
|
const marshalledRecord = await createSignedRecord(
|
|
4528
|
-
|
|
4649
|
+
ipnsKeyPair,
|
|
4529
4650
|
cid,
|
|
4530
4651
|
newSeq,
|
|
4531
4652
|
this.ipnsLifetimeMs
|
|
4532
4653
|
);
|
|
4533
4654
|
const publishResult = await this.httpClient.publishIpns(
|
|
4534
|
-
|
|
4655
|
+
ipnsName,
|
|
4535
4656
|
marshalledRecord
|
|
4536
4657
|
);
|
|
4537
4658
|
if (!publishResult.success) {
|
|
@@ -4546,14 +4667,14 @@ var IpfsStorageProvider = class {
|
|
|
4546
4667
|
this.ipnsSequenceNumber = newSeq;
|
|
4547
4668
|
this.lastCid = cid;
|
|
4548
4669
|
this.remoteCid = cid;
|
|
4549
|
-
this.cache.setIpnsRecord(
|
|
4670
|
+
this.cache.setIpnsRecord(ipnsName, {
|
|
4550
4671
|
cid,
|
|
4551
4672
|
sequence: newSeq,
|
|
4552
4673
|
gateway: "local"
|
|
4553
4674
|
});
|
|
4554
4675
|
this.cache.setContent(cid, updatedData);
|
|
4555
|
-
this.cache.markIpnsFresh(
|
|
4556
|
-
await this.statePersistence.save(
|
|
4676
|
+
this.cache.markIpnsFresh(ipnsName);
|
|
4677
|
+
await this.statePersistence.save(ipnsName, {
|
|
4557
4678
|
sequenceNumber: newSeq.toString(),
|
|
4558
4679
|
lastCid: cid,
|
|
4559
4680
|
version: this.dataVersion
|
|
@@ -4605,7 +4726,8 @@ var IpfsStorageProvider = class {
|
|
|
4605
4726
|
const baseData = active.txfData ?? {
|
|
4606
4727
|
_meta: { version: 0, address: this.identity?.directAddress ?? "", formatVersion: "2.0", updatedAt: 0 }
|
|
4607
4728
|
};
|
|
4608
|
-
const
|
|
4729
|
+
const overrideIpns = active.capturedIpnsKeyPair && active.capturedIpnsName ? { keyPair: active.capturedIpnsKeyPair, name: active.capturedIpnsName } : void 0;
|
|
4730
|
+
const result = await this._doSave(baseData, overrideIpns);
|
|
4609
4731
|
if (!result.success) {
|
|
4610
4732
|
throw new SphereError(result.error ?? "Save failed", "STORAGE_ERROR");
|
|
4611
4733
|
}
|
|
@@ -4908,6 +5030,13 @@ var IpfsStorageProvider = class {
|
|
|
4908
5030
|
log(message) {
|
|
4909
5031
|
logger.debug("IPFS-Storage", message);
|
|
4910
5032
|
}
|
|
5033
|
+
/**
|
|
5034
|
+
* Create an independent instance for a different address.
|
|
5035
|
+
* Shares the same gateway/timeout config but has fresh IPNS state.
|
|
5036
|
+
*/
|
|
5037
|
+
createForAddress() {
|
|
5038
|
+
return new _IpfsStorageProvider(this._config, this._statePersistenceCtor);
|
|
5039
|
+
}
|
|
4911
5040
|
};
|
|
4912
5041
|
|
|
4913
5042
|
// impl/nodejs/ipfs/nodejs-ipfs-state-persistence.ts
|