@unicitylabs/sphere-sdk 0.6.2 → 0.6.3
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 +1351 -52
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +342 -3
- package/dist/core/index.d.ts +342 -3
- package/dist/core/index.js +1357 -48
- package/dist/core/index.js.map +1 -1
- package/dist/impl/browser/index.cjs +109 -11
- package/dist/impl/browser/index.cjs.map +1 -1
- package/dist/impl/browser/index.js +109 -11
- 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 +105 -11
- package/dist/impl/nodejs/index.cjs.map +1 -1
- package/dist/impl/nodejs/index.d.cts +43 -0
- package/dist/impl/nodejs/index.d.ts +43 -0
- package/dist/impl/nodejs/index.js +105 -11
- package/dist/impl/nodejs/index.js.map +1 -1
- package/dist/index.cjs +1334 -61
- 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 +1333 -50
- 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
|
@@ -195,6 +195,16 @@ interface TransportProvider extends BaseProvider {
|
|
|
195
195
|
* @returns Unsubscribe function
|
|
196
196
|
*/
|
|
197
197
|
onInstantSplitReceived?(handler: InstantSplitBundleHandler): () => void;
|
|
198
|
+
/**
|
|
199
|
+
* Set fallback 'since' timestamp for event subscriptions.
|
|
200
|
+
* Used when switching to an address that has never subscribed before.
|
|
201
|
+
* The transport uses this instead of 'now' as the initial since filter,
|
|
202
|
+
* ensuring events sent while the address was inactive are not missed.
|
|
203
|
+
* Consumed once by the next subscription setup, then cleared.
|
|
204
|
+
*
|
|
205
|
+
* @param sinceSeconds - Unix timestamp in seconds
|
|
206
|
+
*/
|
|
207
|
+
setFallbackSince?(sinceSeconds: number): void;
|
|
198
208
|
/**
|
|
199
209
|
* Fetch pending events from transport (one-shot query).
|
|
200
210
|
* Creates a temporary subscription, processes events through normal handlers,
|
|
@@ -476,6 +486,8 @@ declare class NostrTransportProvider implements TransportProvider {
|
|
|
476
486
|
private storage;
|
|
477
487
|
/** In-memory max event timestamp to avoid read-before-write races in updateLastEventTimestamp. */
|
|
478
488
|
private lastEventTs;
|
|
489
|
+
/** Fallback 'since' timestamp for first-time address subscriptions (consumed once). */
|
|
490
|
+
private fallbackSince;
|
|
479
491
|
private identity;
|
|
480
492
|
private keyManager;
|
|
481
493
|
private status;
|
|
@@ -493,6 +505,25 @@ declare class NostrTransportProvider implements TransportProvider {
|
|
|
493
505
|
private broadcastHandlers;
|
|
494
506
|
private eventCallbacks;
|
|
495
507
|
constructor(config: NostrTransportProviderConfig);
|
|
508
|
+
/**
|
|
509
|
+
* Get the WebSocket factory (used by MultiAddressTransportMux to share the same factory).
|
|
510
|
+
*/
|
|
511
|
+
getWebSocketFactory(): WebSocketFactory;
|
|
512
|
+
/**
|
|
513
|
+
* Get the configured relay URLs.
|
|
514
|
+
*/
|
|
515
|
+
getConfiguredRelays(): string[];
|
|
516
|
+
/**
|
|
517
|
+
* Get the storage adapter.
|
|
518
|
+
*/
|
|
519
|
+
getStorageAdapter(): TransportStorageAdapter | null;
|
|
520
|
+
/**
|
|
521
|
+
* Suppress event subscriptions — unsubscribe wallet/chat filters
|
|
522
|
+
* but keep the connection alive for resolve/identity-binding operations.
|
|
523
|
+
* Used when MultiAddressTransportMux takes over event handling.
|
|
524
|
+
*/
|
|
525
|
+
suppressSubscriptions(): void;
|
|
526
|
+
private _subscriptionsSuppressed;
|
|
496
527
|
connect(): Promise<void>;
|
|
497
528
|
disconnect(): Promise<void>;
|
|
498
529
|
isConnected(): boolean;
|
|
@@ -526,6 +557,7 @@ declare class NostrTransportProvider implements TransportProvider {
|
|
|
526
557
|
*/
|
|
527
558
|
isRelayConnected(relayUrl: string): boolean;
|
|
528
559
|
setIdentity(identity: FullIdentity): Promise<void>;
|
|
560
|
+
setFallbackSince(sinceSeconds: number): void;
|
|
529
561
|
/**
|
|
530
562
|
* Get the Nostr-format public key (32 bytes / 64 hex chars)
|
|
531
563
|
* This is the x-coordinate only, without the 02/03 prefix.
|
|
@@ -1133,6 +1165,13 @@ interface TokenStorageProvider<TData = unknown> extends BaseProvider {
|
|
|
1133
1165
|
* Clear all data
|
|
1134
1166
|
*/
|
|
1135
1167
|
clear?(): Promise<boolean>;
|
|
1168
|
+
/**
|
|
1169
|
+
* Create a new independent instance of this provider for a different address.
|
|
1170
|
+
* Used by per-address module architecture — each address gets its own
|
|
1171
|
+
* TokenStorageProvider instance to avoid cross-address data contamination.
|
|
1172
|
+
* If not implemented, the provider cannot be used in multi-address mode.
|
|
1173
|
+
*/
|
|
1174
|
+
createForAddress?(): TokenStorageProvider<TData>;
|
|
1136
1175
|
/**
|
|
1137
1176
|
* Subscribe to storage events
|
|
1138
1177
|
*/
|
|
@@ -1282,6 +1321,10 @@ declare class FileTokenStorageProvider implements TokenStorageProvider<TxfStorag
|
|
|
1282
1321
|
hasHistoryEntry(dedupKey: string): Promise<boolean>;
|
|
1283
1322
|
clearHistory(): Promise<void>;
|
|
1284
1323
|
importHistoryEntries(entries: HistoryRecord[]): Promise<number>;
|
|
1324
|
+
/**
|
|
1325
|
+
* Create an independent instance for a different address.
|
|
1326
|
+
*/
|
|
1327
|
+
createForAddress(): FileTokenStorageProvider;
|
|
1285
1328
|
}
|
|
1286
1329
|
declare function createFileTokenStorageProvider(config: FileTokenStorageConfig | string): FileTokenStorageProvider;
|
|
1287
1330
|
|
|
@@ -195,6 +195,16 @@ interface TransportProvider extends BaseProvider {
|
|
|
195
195
|
* @returns Unsubscribe function
|
|
196
196
|
*/
|
|
197
197
|
onInstantSplitReceived?(handler: InstantSplitBundleHandler): () => void;
|
|
198
|
+
/**
|
|
199
|
+
* Set fallback 'since' timestamp for event subscriptions.
|
|
200
|
+
* Used when switching to an address that has never subscribed before.
|
|
201
|
+
* The transport uses this instead of 'now' as the initial since filter,
|
|
202
|
+
* ensuring events sent while the address was inactive are not missed.
|
|
203
|
+
* Consumed once by the next subscription setup, then cleared.
|
|
204
|
+
*
|
|
205
|
+
* @param sinceSeconds - Unix timestamp in seconds
|
|
206
|
+
*/
|
|
207
|
+
setFallbackSince?(sinceSeconds: number): void;
|
|
198
208
|
/**
|
|
199
209
|
* Fetch pending events from transport (one-shot query).
|
|
200
210
|
* Creates a temporary subscription, processes events through normal handlers,
|
|
@@ -476,6 +486,8 @@ declare class NostrTransportProvider implements TransportProvider {
|
|
|
476
486
|
private storage;
|
|
477
487
|
/** In-memory max event timestamp to avoid read-before-write races in updateLastEventTimestamp. */
|
|
478
488
|
private lastEventTs;
|
|
489
|
+
/** Fallback 'since' timestamp for first-time address subscriptions (consumed once). */
|
|
490
|
+
private fallbackSince;
|
|
479
491
|
private identity;
|
|
480
492
|
private keyManager;
|
|
481
493
|
private status;
|
|
@@ -493,6 +505,25 @@ declare class NostrTransportProvider implements TransportProvider {
|
|
|
493
505
|
private broadcastHandlers;
|
|
494
506
|
private eventCallbacks;
|
|
495
507
|
constructor(config: NostrTransportProviderConfig);
|
|
508
|
+
/**
|
|
509
|
+
* Get the WebSocket factory (used by MultiAddressTransportMux to share the same factory).
|
|
510
|
+
*/
|
|
511
|
+
getWebSocketFactory(): WebSocketFactory;
|
|
512
|
+
/**
|
|
513
|
+
* Get the configured relay URLs.
|
|
514
|
+
*/
|
|
515
|
+
getConfiguredRelays(): string[];
|
|
516
|
+
/**
|
|
517
|
+
* Get the storage adapter.
|
|
518
|
+
*/
|
|
519
|
+
getStorageAdapter(): TransportStorageAdapter | null;
|
|
520
|
+
/**
|
|
521
|
+
* Suppress event subscriptions — unsubscribe wallet/chat filters
|
|
522
|
+
* but keep the connection alive for resolve/identity-binding operations.
|
|
523
|
+
* Used when MultiAddressTransportMux takes over event handling.
|
|
524
|
+
*/
|
|
525
|
+
suppressSubscriptions(): void;
|
|
526
|
+
private _subscriptionsSuppressed;
|
|
496
527
|
connect(): Promise<void>;
|
|
497
528
|
disconnect(): Promise<void>;
|
|
498
529
|
isConnected(): boolean;
|
|
@@ -526,6 +557,7 @@ declare class NostrTransportProvider implements TransportProvider {
|
|
|
526
557
|
*/
|
|
527
558
|
isRelayConnected(relayUrl: string): boolean;
|
|
528
559
|
setIdentity(identity: FullIdentity): Promise<void>;
|
|
560
|
+
setFallbackSince(sinceSeconds: number): void;
|
|
529
561
|
/**
|
|
530
562
|
* Get the Nostr-format public key (32 bytes / 64 hex chars)
|
|
531
563
|
* This is the x-coordinate only, without the 02/03 prefix.
|
|
@@ -1133,6 +1165,13 @@ interface TokenStorageProvider<TData = unknown> extends BaseProvider {
|
|
|
1133
1165
|
* Clear all data
|
|
1134
1166
|
*/
|
|
1135
1167
|
clear?(): Promise<boolean>;
|
|
1168
|
+
/**
|
|
1169
|
+
* Create a new independent instance of this provider for a different address.
|
|
1170
|
+
* Used by per-address module architecture — each address gets its own
|
|
1171
|
+
* TokenStorageProvider instance to avoid cross-address data contamination.
|
|
1172
|
+
* If not implemented, the provider cannot be used in multi-address mode.
|
|
1173
|
+
*/
|
|
1174
|
+
createForAddress?(): TokenStorageProvider<TData>;
|
|
1136
1175
|
/**
|
|
1137
1176
|
* Subscribe to storage events
|
|
1138
1177
|
*/
|
|
@@ -1282,6 +1321,10 @@ declare class FileTokenStorageProvider implements TokenStorageProvider<TxfStorag
|
|
|
1282
1321
|
hasHistoryEntry(dedupKey: string): Promise<boolean>;
|
|
1283
1322
|
clearHistory(): Promise<void>;
|
|
1284
1323
|
importHistoryEntries(entries: HistoryRecord[]): Promise<number>;
|
|
1324
|
+
/**
|
|
1325
|
+
* Create an independent instance for a different address.
|
|
1326
|
+
*/
|
|
1327
|
+
createForAddress(): FileTokenStorageProvider;
|
|
1285
1328
|
}
|
|
1286
1329
|
declare function createFileTokenStorageProvider(config: FileTokenStorageConfig | string): FileTokenStorageProvider;
|
|
1287
1330
|
|
|
@@ -319,7 +319,7 @@ import * as path2 from "path";
|
|
|
319
319
|
var META_FILE = "_meta.json";
|
|
320
320
|
var TOMBSTONES_FILE = "_tombstones.json";
|
|
321
321
|
var HISTORY_FILE = "_history.json";
|
|
322
|
-
var FileTokenStorageProvider = class {
|
|
322
|
+
var FileTokenStorageProvider = class _FileTokenStorageProvider {
|
|
323
323
|
id = "file-token-storage";
|
|
324
324
|
name = "File Token Storage";
|
|
325
325
|
type = "local";
|
|
@@ -546,6 +546,12 @@ var FileTokenStorageProvider = class {
|
|
|
546
546
|
}
|
|
547
547
|
return imported;
|
|
548
548
|
}
|
|
549
|
+
/**
|
|
550
|
+
* Create an independent instance for a different address.
|
|
551
|
+
*/
|
|
552
|
+
createForAddress() {
|
|
553
|
+
return new _FileTokenStorageProvider({ tokensDir: this.baseTokensDir });
|
|
554
|
+
}
|
|
549
555
|
};
|
|
550
556
|
function createFileTokenStorageProvider(config) {
|
|
551
557
|
return new FileTokenStorageProvider(config);
|
|
@@ -1081,6 +1087,8 @@ var NostrTransportProvider = class {
|
|
|
1081
1087
|
storage = null;
|
|
1082
1088
|
/** In-memory max event timestamp to avoid read-before-write races in updateLastEventTimestamp. */
|
|
1083
1089
|
lastEventTs = 0;
|
|
1090
|
+
/** Fallback 'since' timestamp for first-time address subscriptions (consumed once). */
|
|
1091
|
+
fallbackSince = null;
|
|
1084
1092
|
identity = null;
|
|
1085
1093
|
keyManager = null;
|
|
1086
1094
|
status = "disconnected";
|
|
@@ -1113,6 +1121,48 @@ var NostrTransportProvider = class {
|
|
|
1113
1121
|
};
|
|
1114
1122
|
this.storage = config.storage ?? null;
|
|
1115
1123
|
}
|
|
1124
|
+
/**
|
|
1125
|
+
* Get the WebSocket factory (used by MultiAddressTransportMux to share the same factory).
|
|
1126
|
+
*/
|
|
1127
|
+
getWebSocketFactory() {
|
|
1128
|
+
return this.config.createWebSocket;
|
|
1129
|
+
}
|
|
1130
|
+
/**
|
|
1131
|
+
* Get the configured relay URLs.
|
|
1132
|
+
*/
|
|
1133
|
+
getConfiguredRelays() {
|
|
1134
|
+
return [...this.config.relays];
|
|
1135
|
+
}
|
|
1136
|
+
/**
|
|
1137
|
+
* Get the storage adapter.
|
|
1138
|
+
*/
|
|
1139
|
+
getStorageAdapter() {
|
|
1140
|
+
return this.storage;
|
|
1141
|
+
}
|
|
1142
|
+
/**
|
|
1143
|
+
* Suppress event subscriptions — unsubscribe wallet/chat filters
|
|
1144
|
+
* but keep the connection alive for resolve/identity-binding operations.
|
|
1145
|
+
* Used when MultiAddressTransportMux takes over event handling.
|
|
1146
|
+
*/
|
|
1147
|
+
suppressSubscriptions() {
|
|
1148
|
+
if (!this.nostrClient) return;
|
|
1149
|
+
if (this.walletSubscriptionId) {
|
|
1150
|
+
this.nostrClient.unsubscribe(this.walletSubscriptionId);
|
|
1151
|
+
this.walletSubscriptionId = null;
|
|
1152
|
+
}
|
|
1153
|
+
if (this.chatSubscriptionId) {
|
|
1154
|
+
this.nostrClient.unsubscribe(this.chatSubscriptionId);
|
|
1155
|
+
this.chatSubscriptionId = null;
|
|
1156
|
+
}
|
|
1157
|
+
if (this.mainSubscriptionId) {
|
|
1158
|
+
this.nostrClient.unsubscribe(this.mainSubscriptionId);
|
|
1159
|
+
this.mainSubscriptionId = null;
|
|
1160
|
+
}
|
|
1161
|
+
this._subscriptionsSuppressed = true;
|
|
1162
|
+
logger.debug("Nostr", "Subscriptions suppressed \u2014 mux handles event routing");
|
|
1163
|
+
}
|
|
1164
|
+
// Flag to prevent re-subscription after suppressSubscriptions()
|
|
1165
|
+
_subscriptionsSuppressed = false;
|
|
1116
1166
|
// ===========================================================================
|
|
1117
1167
|
// BaseProvider Implementation
|
|
1118
1168
|
// ===========================================================================
|
|
@@ -1291,6 +1341,8 @@ var NostrTransportProvider = class {
|
|
|
1291
1341
|
// ===========================================================================
|
|
1292
1342
|
async setIdentity(identity) {
|
|
1293
1343
|
this.identity = identity;
|
|
1344
|
+
this.processedEventIds.clear();
|
|
1345
|
+
this.lastEventTs = 0;
|
|
1294
1346
|
const secretKey = Buffer2.from(identity.privateKey, "hex");
|
|
1295
1347
|
this.keyManager = NostrKeyManager.fromPrivateKey(secretKey);
|
|
1296
1348
|
const nostrPubkey = this.keyManager.getPublicKeyHex();
|
|
@@ -1333,6 +1385,9 @@ var NostrTransportProvider = class {
|
|
|
1333
1385
|
await this.subscribeToEvents();
|
|
1334
1386
|
}
|
|
1335
1387
|
}
|
|
1388
|
+
setFallbackSince(sinceSeconds) {
|
|
1389
|
+
this.fallbackSince = sinceSeconds;
|
|
1390
|
+
}
|
|
1336
1391
|
/**
|
|
1337
1392
|
* Get the Nostr-format public key (32 bytes / 64 hex chars)
|
|
1338
1393
|
* This is the x-coordinate only, without the 02/03 prefix.
|
|
@@ -2240,6 +2295,10 @@ var NostrTransportProvider = class {
|
|
|
2240
2295
|
chatEoseFired = false;
|
|
2241
2296
|
async subscribeToEvents() {
|
|
2242
2297
|
logger.debug("Nostr", "subscribeToEvents called, identity:", !!this.identity, "keyManager:", !!this.keyManager, "nostrClient:", !!this.nostrClient);
|
|
2298
|
+
if (this._subscriptionsSuppressed) {
|
|
2299
|
+
logger.debug("Nostr", "subscribeToEvents: suppressed \u2014 mux handles event routing");
|
|
2300
|
+
return;
|
|
2301
|
+
}
|
|
2243
2302
|
if (!this.identity || !this.keyManager || !this.nostrClient) {
|
|
2244
2303
|
logger.debug("Nostr", "subscribeToEvents: skipped - no identity, keyManager, or nostrClient");
|
|
2245
2304
|
return;
|
|
@@ -2266,7 +2325,13 @@ var NostrTransportProvider = class {
|
|
|
2266
2325
|
if (stored) {
|
|
2267
2326
|
since = parseInt(stored, 10);
|
|
2268
2327
|
this.lastEventTs = since;
|
|
2328
|
+
this.fallbackSince = null;
|
|
2269
2329
|
logger.debug("Nostr", "Resuming from stored event timestamp:", since);
|
|
2330
|
+
} else if (this.fallbackSince !== null) {
|
|
2331
|
+
since = this.fallbackSince;
|
|
2332
|
+
this.lastEventTs = since;
|
|
2333
|
+
this.fallbackSince = null;
|
|
2334
|
+
logger.debug("Nostr", "Using fallback since timestamp:", since);
|
|
2270
2335
|
} else {
|
|
2271
2336
|
since = Math.floor(Date.now() / 1e3);
|
|
2272
2337
|
logger.debug("Nostr", "No stored timestamp, starting from now:", since);
|
|
@@ -2274,6 +2339,7 @@ var NostrTransportProvider = class {
|
|
|
2274
2339
|
} catch (err) {
|
|
2275
2340
|
logger.debug("Nostr", "Failed to read last event timestamp, falling back to now:", err);
|
|
2276
2341
|
since = Math.floor(Date.now() / 1e3);
|
|
2342
|
+
this.fallbackSince = null;
|
|
2277
2343
|
}
|
|
2278
2344
|
} else {
|
|
2279
2345
|
since = Math.floor(Date.now() / 1e3) - 86400;
|
|
@@ -4241,11 +4307,17 @@ var AsyncSerialQueue = class {
|
|
|
4241
4307
|
var WriteBuffer = class {
|
|
4242
4308
|
/** Full TXF data from save() calls — latest wins */
|
|
4243
4309
|
txfData = null;
|
|
4310
|
+
/** IPNS context captured at save() time — ensures flush writes to the correct
|
|
4311
|
+
* IPNS record even if identity changes between save() and flush(). */
|
|
4312
|
+
capturedIpnsKeyPair = null;
|
|
4313
|
+
capturedIpnsName = null;
|
|
4244
4314
|
get isEmpty() {
|
|
4245
4315
|
return this.txfData === null;
|
|
4246
4316
|
}
|
|
4247
4317
|
clear() {
|
|
4248
4318
|
this.txfData = null;
|
|
4319
|
+
this.capturedIpnsKeyPair = null;
|
|
4320
|
+
this.capturedIpnsName = null;
|
|
4249
4321
|
}
|
|
4250
4322
|
/**
|
|
4251
4323
|
* Merge another buffer's contents into this one (for rollback).
|
|
@@ -4254,12 +4326,14 @@ var WriteBuffer = class {
|
|
|
4254
4326
|
mergeFrom(other) {
|
|
4255
4327
|
if (other.txfData && !this.txfData) {
|
|
4256
4328
|
this.txfData = other.txfData;
|
|
4329
|
+
this.capturedIpnsKeyPair = other.capturedIpnsKeyPair;
|
|
4330
|
+
this.capturedIpnsName = other.capturedIpnsName;
|
|
4257
4331
|
}
|
|
4258
4332
|
}
|
|
4259
4333
|
};
|
|
4260
4334
|
|
|
4261
4335
|
// impl/shared/ipfs/ipfs-storage-provider.ts
|
|
4262
|
-
var IpfsStorageProvider = class {
|
|
4336
|
+
var IpfsStorageProvider = class _IpfsStorageProvider {
|
|
4263
4337
|
id = "ipfs";
|
|
4264
4338
|
name = "IPFS Storage";
|
|
4265
4339
|
type = "p2p";
|
|
@@ -4304,7 +4378,12 @@ var IpfsStorageProvider = class {
|
|
|
4304
4378
|
flushDebounceMs;
|
|
4305
4379
|
/** Set to true during shutdown to prevent new flushes */
|
|
4306
4380
|
isShuttingDown = false;
|
|
4381
|
+
/** Stored config for createForAddress() cloning */
|
|
4382
|
+
_config;
|
|
4383
|
+
_statePersistenceCtor;
|
|
4307
4384
|
constructor(config, statePersistence) {
|
|
4385
|
+
this._config = config;
|
|
4386
|
+
this._statePersistenceCtor = statePersistence;
|
|
4308
4387
|
const gateways = config?.gateways ?? getIpfsGatewayUrls();
|
|
4309
4388
|
this.debug = config?.debug ?? false;
|
|
4310
4389
|
this.ipnsLifetimeMs = config?.ipnsLifetimeMs ?? 99 * 365 * 24 * 60 * 60 * 1e3;
|
|
@@ -4424,6 +4503,7 @@ var IpfsStorageProvider = class {
|
|
|
4424
4503
|
}
|
|
4425
4504
|
async shutdown() {
|
|
4426
4505
|
this.isShuttingDown = true;
|
|
4506
|
+
logger.debug("IPFS-Storage", `shutdown: ipnsName=${this.ipnsName?.slice(0, 20)}..., pendingEmpty=${this.pendingBuffer.isEmpty}, capturedIpns=${this.pendingBuffer.capturedIpnsName?.slice(0, 20) ?? "none"}`);
|
|
4427
4507
|
if (this.flushTimer) {
|
|
4428
4508
|
clearTimeout(this.flushTimer);
|
|
4429
4509
|
this.flushTimer = null;
|
|
@@ -4456,6 +4536,8 @@ var IpfsStorageProvider = class {
|
|
|
4456
4536
|
return { success: false, error: "Not initialized", timestamp: Date.now() };
|
|
4457
4537
|
}
|
|
4458
4538
|
this.pendingBuffer.txfData = data;
|
|
4539
|
+
this.pendingBuffer.capturedIpnsKeyPair = this.ipnsKeyPair;
|
|
4540
|
+
this.pendingBuffer.capturedIpnsName = this.ipnsName;
|
|
4459
4541
|
this.scheduleFlush();
|
|
4460
4542
|
return { success: true, timestamp: Date.now() };
|
|
4461
4543
|
}
|
|
@@ -4466,8 +4548,12 @@ var IpfsStorageProvider = class {
|
|
|
4466
4548
|
* Perform the actual upload + IPNS publish synchronously.
|
|
4467
4549
|
* Called by executeFlush() and sync() — never by public save().
|
|
4468
4550
|
*/
|
|
4469
|
-
async _doSave(data) {
|
|
4470
|
-
|
|
4551
|
+
async _doSave(data, overrideIpns) {
|
|
4552
|
+
const ipnsKeyPair = overrideIpns?.keyPair ?? this.ipnsKeyPair;
|
|
4553
|
+
const ipnsName = overrideIpns?.name ?? this.ipnsName;
|
|
4554
|
+
const metaAddr = data?._meta?.address;
|
|
4555
|
+
logger.debug("IPFS-Storage", `_doSave: ipnsName=${ipnsName?.slice(0, 20)}..., override=${!!overrideIpns}, meta.address=${metaAddr?.slice(0, 20) ?? "none"}`);
|
|
4556
|
+
if (!ipnsKeyPair || !ipnsName) {
|
|
4471
4557
|
return { success: false, error: "Not initialized", timestamp: Date.now() };
|
|
4472
4558
|
}
|
|
4473
4559
|
this.emitEvent({ type: "storage:saving", timestamp: Date.now() });
|
|
@@ -4476,7 +4562,7 @@ var IpfsStorageProvider = class {
|
|
|
4476
4562
|
const metaUpdate = {
|
|
4477
4563
|
...data._meta,
|
|
4478
4564
|
version: this.dataVersion,
|
|
4479
|
-
ipnsName
|
|
4565
|
+
ipnsName,
|
|
4480
4566
|
updatedAt: Date.now()
|
|
4481
4567
|
};
|
|
4482
4568
|
if (this.remoteCid) {
|
|
@@ -4488,13 +4574,13 @@ var IpfsStorageProvider = class {
|
|
|
4488
4574
|
const baseSeq = this.ipnsSequenceNumber > this.lastKnownRemoteSequence ? this.ipnsSequenceNumber : this.lastKnownRemoteSequence;
|
|
4489
4575
|
const newSeq = baseSeq + 1n;
|
|
4490
4576
|
const marshalledRecord = await createSignedRecord(
|
|
4491
|
-
|
|
4577
|
+
ipnsKeyPair,
|
|
4492
4578
|
cid,
|
|
4493
4579
|
newSeq,
|
|
4494
4580
|
this.ipnsLifetimeMs
|
|
4495
4581
|
);
|
|
4496
4582
|
const publishResult = await this.httpClient.publishIpns(
|
|
4497
|
-
|
|
4583
|
+
ipnsName,
|
|
4498
4584
|
marshalledRecord
|
|
4499
4585
|
);
|
|
4500
4586
|
if (!publishResult.success) {
|
|
@@ -4509,14 +4595,14 @@ var IpfsStorageProvider = class {
|
|
|
4509
4595
|
this.ipnsSequenceNumber = newSeq;
|
|
4510
4596
|
this.lastCid = cid;
|
|
4511
4597
|
this.remoteCid = cid;
|
|
4512
|
-
this.cache.setIpnsRecord(
|
|
4598
|
+
this.cache.setIpnsRecord(ipnsName, {
|
|
4513
4599
|
cid,
|
|
4514
4600
|
sequence: newSeq,
|
|
4515
4601
|
gateway: "local"
|
|
4516
4602
|
});
|
|
4517
4603
|
this.cache.setContent(cid, updatedData);
|
|
4518
|
-
this.cache.markIpnsFresh(
|
|
4519
|
-
await this.statePersistence.save(
|
|
4604
|
+
this.cache.markIpnsFresh(ipnsName);
|
|
4605
|
+
await this.statePersistence.save(ipnsName, {
|
|
4520
4606
|
sequenceNumber: newSeq.toString(),
|
|
4521
4607
|
lastCid: cid,
|
|
4522
4608
|
version: this.dataVersion
|
|
@@ -4568,7 +4654,8 @@ var IpfsStorageProvider = class {
|
|
|
4568
4654
|
const baseData = active.txfData ?? {
|
|
4569
4655
|
_meta: { version: 0, address: this.identity?.directAddress ?? "", formatVersion: "2.0", updatedAt: 0 }
|
|
4570
4656
|
};
|
|
4571
|
-
const
|
|
4657
|
+
const overrideIpns = active.capturedIpnsKeyPair && active.capturedIpnsName ? { keyPair: active.capturedIpnsKeyPair, name: active.capturedIpnsName } : void 0;
|
|
4658
|
+
const result = await this._doSave(baseData, overrideIpns);
|
|
4572
4659
|
if (!result.success) {
|
|
4573
4660
|
throw new SphereError(result.error ?? "Save failed", "STORAGE_ERROR");
|
|
4574
4661
|
}
|
|
@@ -4871,6 +4958,13 @@ var IpfsStorageProvider = class {
|
|
|
4871
4958
|
log(message) {
|
|
4872
4959
|
logger.debug("IPFS-Storage", message);
|
|
4873
4960
|
}
|
|
4961
|
+
/**
|
|
4962
|
+
* Create an independent instance for a different address.
|
|
4963
|
+
* Shares the same gateway/timeout config but has fresh IPNS state.
|
|
4964
|
+
*/
|
|
4965
|
+
createForAddress() {
|
|
4966
|
+
return new _IpfsStorageProvider(this._config, this._statePersistenceCtor);
|
|
4967
|
+
}
|
|
4874
4968
|
};
|
|
4875
4969
|
|
|
4876
4970
|
// impl/nodejs/ipfs/nodejs-ipfs-state-persistence.ts
|