orbitdb-relay-pinner 0.7.0 → 0.8.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/.env.example CHANGED
@@ -9,16 +9,19 @@
9
9
  # METRICS_HTTPS_PORT=8443
10
10
  # RELAY_TCP_PORT=50001
11
11
  # RELAY_WS_PORT=6300
12
+ # RELAY_QUIC_PORT=50005
12
13
  # RELAY_WEBRTC_PORT=50003
13
- # VITE_APPEND_ANNOUNCE=/ip4/PUBLIC_IP/tcp/50001,/ip4/PUBLIC_IP/tcp/6300/ws,/ip4/PUBLIC_IP/udp/50003/webrtc-direct
14
+ # VITE_APPEND_ANNOUNCE=/ip4/PUBLIC_IP/tcp/50001,/ip4/PUBLIC_IP/tcp/6300/ws,/ip4/PUBLIC_IP/udp/50005/quic-v1,/ip4/PUBLIC_IP/udp/50003/webrtc-direct
14
15
 
15
16
  # --- Listeners & transports ---
16
17
  # RELAY_TCP_PORT=9091
17
18
  # RELAY_WS_PORT=9092
19
+ # RELAY_QUIC_PORT=9094
18
20
  # RELAY_WEBRTC_PORT=9093
19
21
  # RELAY_LISTEN_IPV4=0.0.0.0
20
22
  # RELAY_LISTEN_IPV6=::
21
23
  # RELAY_DISABLE_IPV6=false
24
+ # RELAY_DISABLE_QUIC=false
22
25
  # RELAY_DISABLE_WEBRTC=false
23
26
  # Public IPFS/libp2p bootstrap peers (Helia/Kubo list) are enabled by default. Set true for isolated networks.
24
27
  # RELAY_DISABLE_BOOTSTRAP=false
@@ -1 +1 @@
1
- {"version":3,"file":"libp2p.d.ts","sourceRoot":"","sources":["../../src/config/libp2p.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AA2DpD,KAAK,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,UAAU,EAAE,GAAG,KAAK,OAAO,CAAC,CAAA;AAEzE,eAAO,MAAM,kBAAkB,GAC7B,YAAY,UAAU,EACtB,WAAW,SAAS,EACpB,gBAAe,qBAA0B,KAkFpC,GACN,CAAA"}
1
+ {"version":3,"file":"libp2p.d.ts","sourceRoot":"","sources":["../../src/config/libp2p.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AA+DpD,KAAK,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,UAAU,EAAE,GAAG,KAAK,OAAO,CAAC,CAAA;AAEzE,eAAO,MAAM,kBAAkB,GAC7B,YAAY,UAAU,EACtB,WAAW,SAAS,EACpB,gBAAe,qBAA0B,KAqFpC,GACN,CAAA"}
@@ -1,4 +1,5 @@
1
1
  import { noise } from '@chainsafe/libp2p-noise';
2
+ import { quic } from '@chainsafe/libp2p-quic';
2
3
  import { yamux } from '@chainsafe/libp2p-yamux';
3
4
  import { circuitRelayTransport, circuitRelayServer } from '@libp2p/circuit-relay-v2';
4
5
  import { identify, identifyPush } from '@libp2p/identify';
@@ -28,10 +29,12 @@ function readRelayListenEnv() {
28
29
  const tcpPort = Number(process.env.RELAY_TCP_PORT || 9091);
29
30
  const wsPort = Number(process.env.RELAY_WS_PORT || 9092);
30
31
  const webrtcPort = Number(process.env.RELAY_WEBRTC_PORT || 9093);
32
+ const quicPort = Number(process.env.RELAY_QUIC_PORT || 9094);
31
33
  const listenIpv4 = process.env.RELAY_LISTEN_IPV4 || '0.0.0.0';
32
34
  const listenIpv6 = process.env.RELAY_LISTEN_IPV6 || '::';
33
35
  const disableIpv6 = process.env.RELAY_DISABLE_IPV6 === 'true' || process.env.RELAY_DISABLE_IPV6 === '1';
34
36
  const disableWebRtc = process.env.RELAY_DISABLE_WEBRTC === 'true' || process.env.RELAY_DISABLE_WEBRTC === '1';
37
+ const disableQuic = process.env.RELAY_DISABLE_QUIC === 'true' || process.env.RELAY_DISABLE_QUIC === '1';
35
38
  const disableBootstrap = process.env.RELAY_DISABLE_BOOTSTRAP === 'true' || process.env.RELAY_DISABLE_BOOTSTRAP === '1';
36
39
  const disableAutoNAT = process.env.RELAY_DISABLE_AUTONAT === 'true' || process.env.RELAY_DISABLE_AUTONAT === '1';
37
40
  const pubsubTopics = (process.env.PUBSUB_TOPICS ||
@@ -45,10 +48,12 @@ function readRelayListenEnv() {
45
48
  tcpPort,
46
49
  wsPort,
47
50
  webrtcPort,
51
+ quicPort,
48
52
  listenIpv4,
49
53
  listenIpv6,
50
54
  disableIpv6,
51
55
  disableWebRtc,
56
+ disableQuic,
52
57
  disableBootstrap,
53
58
  disableAutoNAT,
54
59
  pubsubTopics,
@@ -64,11 +69,13 @@ export const createLibp2pConfig = (privateKey, datastore, extraServices = {}) =>
64
69
  listen: [
65
70
  `/ip4/${e.listenIpv4}/tcp/${e.tcpPort}`,
66
71
  `/ip4/${e.listenIpv4}/tcp/${e.wsPort}/ws`,
72
+ ...(!e.disableQuic ? [`/ip4/${e.listenIpv4}/udp/${e.quicPort}/quic-v1`] : []),
67
73
  ...(!e.disableWebRtc ? [`/ip4/${e.listenIpv4}/udp/${e.webrtcPort}/webrtc-direct`] : []),
68
74
  ...(!e.disableIpv6
69
75
  ? [
70
76
  `/ip6/${e.listenIpv6}/tcp/${e.tcpPort}`,
71
77
  `/ip6/${e.listenIpv6}/tcp/${e.wsPort}/ws`,
78
+ ...(!e.disableQuic ? [`/ip6/${e.listenIpv6}/udp/${e.quicPort}/quic-v1`] : []),
72
79
  ...(!e.disableWebRtc ? [`/ip6/${e.listenIpv6}/udp/${e.webrtcPort}/webrtc-direct`] : []),
73
80
  ]
74
81
  : []),
@@ -78,6 +85,7 @@ export const createLibp2pConfig = (privateKey, datastore, extraServices = {}) =>
78
85
  transports: [
79
86
  circuitRelayTransport(),
80
87
  tcp(),
88
+ ...(!e.disableQuic ? [quic()] : []),
81
89
  ...(!e.disableWebRtc ? [webRTC(), webRTCDirect()] : []),
82
90
  webSockets(),
83
91
  ],
@@ -1 +1 @@
1
- {"version":3,"file":"libp2p.js","sourceRoot":"","sources":["../../src/config/libp2p.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"libp2p.js","sourceRoot":"","sources":["../../src/config/libp2p.ts"],"names":[],"mappings":"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"}
@@ -13,6 +13,7 @@ export declare class DatabaseService {
13
13
  eventHandlers: Map<string, any>;
14
14
  syncInFlight: Map<string, Promise<void>>;
15
15
  openInFlight: Map<string, Promise<any>>;
16
+ databaseUseCounts: Map<string, number>;
16
17
  pinQueue: PQueue;
17
18
  queuedImageCids: Set<string>;
18
19
  pinnedImageCids: Set<string>;
@@ -26,6 +27,7 @@ export declare class DatabaseService {
26
27
  address: string;
27
28
  lastSyncedAt: string;
28
29
  }>;
30
+ knownDatabasesByAddress: Set<string>;
29
31
  /** Manifest `name` by OrbitDB address (for logs / pubsub). */
30
32
  orbitDbNameByAddress: Map<string, string>;
31
33
  constructor();
@@ -33,6 +35,13 @@ export declare class DatabaseService {
33
35
  getCachedDbName(dbAddress: string): string | undefined;
34
36
  /** Load manifest to populate {@link orbitDbNameByAddress} without sync logging (e.g. before pubsub subscribe log). */
35
37
  prefetchManifestForLogging(dbAddress: string): Promise<void>;
38
+ getKnownHeadsProtocols(): string[];
39
+ isKnownHeadsProtocol(protocol: string): boolean;
40
+ handleOnDemandHeadsProtocol(protocol: string, context: {
41
+ connection?: {
42
+ remotePeer?: unknown;
43
+ };
44
+ }, getRegisteredHandler: (protocol: string) => any): Promise<void>;
36
45
  createPinningHttpHandlers(): PinningHttpHandlers;
37
46
  /**
38
47
  * GET `/ipfs/<cid>` — stream content only when the CID is pinned in Helia and all bytes come from the local blockstore.
@@ -58,12 +67,21 @@ export declare class DatabaseService {
58
67
  private enqueueImageCidsForPinning;
59
68
  private waitForUpdateEvent;
60
69
  private normalizeOrbitdbAccessAddress;
70
+ private rememberKnownDatabaseAddress;
71
+ private rememberKnownDatabaseAddressesFromRecords;
72
+ private dbAddressFromHeadsProtocol;
73
+ private waitForRegisteredHeadsHandler;
74
+ private ensurePeerConnection;
61
75
  private summarizeManifest;
62
76
  private loadManifest;
63
77
  private waitForDatabaseActivity;
64
78
  private waitForDatabaseHeads;
65
79
  private preOpenAccessController;
66
80
  private openDatabase;
81
+ private retainOpenDatabase;
82
+ private releaseOpenDatabase;
83
+ private closeDatabaseSilently;
84
+ private installNonFatalDatabaseErrorHandlers;
67
85
  private installAccessControllerDebugHooks;
68
86
  private inspectIdentityHash;
69
87
  private collectIdentityHashesFromLog;
@@ -1 +1 @@
1
- {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/services/database.ts"],"names":[],"mappings":"AAeA,OAAO,MAAM,MAAM,SAAS,CAAA;AAE5B,OAAO,EAAE,aAAa,EAAE,KAAK,mBAAmB,EAA8B,MAAM,cAAc,CAAA;AAkBlG,qFAAqF;AACrF,MAAM,MAAM,iBAAiB,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAA;AAElE,qBAAa,eAAe;IAC1B,OAAO,EAAE,aAAa,CAAA;IACtB,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACnC,gBAAgB,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAClC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC9B,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC/B,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;IACxC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAA;IACvC,QAAQ,EAAE,MAAM,CAAA;IAChB,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAC5B,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAC5B,cAAc,EAAE,OAAO,CAAA;IACvB,OAAO,EAAE,GAAG,CAAA;IACZ,IAAI,EAAE,GAAG,CAAA;IACT,0FAA0F;IAC1F,qBAAqB,EAAE,MAAM,CAAA;IAC7B,kBAAkB,EAAE,MAAM,CAAA;IAC1B,wBAAwB,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAChF,8DAA8D;IAC9D,oBAAoB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;;IAoBzC,qFAAqF;IACrF,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAItD,sHAAsH;IAChH,0BAA0B,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASlE,yBAAyB,IAAI,mBAAmB;IAgDhD;;OAEG;YACW,uBAAuB;IAgDrC;;;OAGG;YACW,+BAA+B;IA2LvC,UAAU,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,CAAC,EAAE,MAAM;IA+B9C,OAAO,CAAC,2BAA2B;IAgGnC,OAAO,CAAC,gBAAgB;IAiBxB,OAAO,CAAC,sBAAsB;IAU9B,OAAO,CAAC,6BAA6B;IAmDrC,OAAO,CAAC,sBAAsB;IAkB9B,OAAO,CAAC,iBAAiB;IAezB,OAAO,CAAC,4BAA4B;IAcpC,OAAO,CAAC,oCAAoC;IAe5C,OAAO,CAAC,kCAAkC;YAU5B,2BAA2B;YAkE3B,WAAW;IA6BzB,OAAO,CAAC,0BAA0B;YAuCpB,kBAAkB;IAkChC,OAAO,CAAC,6BAA6B;IAQrC,OAAO,CAAC,iBAAiB;YAWX,YAAY;YAkCZ,uBAAuB;YAqCvB,oBAAoB;YA+BpB,uBAAuB;YA8DvB,YAAY;IAiB1B,OAAO,CAAC,iCAAiC;YAwD3B,mBAAmB;YAsDnB,4BAA4B;YA2B5B,qBAAqB;YA4BrB,4BAA4B;IAkBpC,qBAAqB,CAAC,SAAS,EAAE,MAAM;IAK7C,aAAa;IAIP,IAAI;CAaX"}
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/services/database.ts"],"names":[],"mappings":"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"}
@@ -25,6 +25,9 @@ const DelegatedTodoAccessController = (opts = {}) => DelegatedTodoAccessControll
25
25
  DelegatedTodoAccessController.type = DelegatedTodoAccessControllerBase.type;
26
26
  const DEFERRED_ACL_PREFIX = '/orbitdb-deferred/';
27
27
  const ORBITDB_PREFIX = '/orbitdb/';
28
+ const ORBITDB_HEADS_PREFIX = '/orbitdb/heads';
29
+ const ON_DEMAND_HEADS_HANDLER_TIMEOUT_MS = 5000;
30
+ const RELAY_ERROR_HANDLER_INSTALLED = Symbol('relayErrorHandlerInstalled');
28
31
  export class DatabaseService {
29
32
  metrics;
30
33
  identityDatabases;
@@ -33,6 +36,7 @@ export class DatabaseService {
33
36
  eventHandlers;
34
37
  syncInFlight;
35
38
  openInFlight;
39
+ databaseUseCounts;
36
40
  pinQueue;
37
41
  queuedImageCids;
38
42
  pinnedImageCids;
@@ -43,6 +47,7 @@ export class DatabaseService {
43
47
  pinningSyncOperations;
44
48
  pinningFailedSyncs;
45
49
  pinnedDatabasesByAddress;
50
+ knownDatabasesByAddress;
46
51
  /** Manifest `name` by OrbitDB address (for logs / pubsub). */
47
52
  orbitDbNameByAddress;
48
53
  constructor() {
@@ -53,6 +58,7 @@ export class DatabaseService {
53
58
  this.eventHandlers = new Map();
54
59
  this.syncInFlight = new Map();
55
60
  this.openInFlight = new Map();
61
+ this.databaseUseCounts = new Map();
56
62
  this.pinQueue = new PQueue({ concurrency: 4 });
57
63
  this.queuedImageCids = new Set();
58
64
  this.pinnedImageCids = new Set();
@@ -60,6 +66,7 @@ export class DatabaseService {
60
66
  this.pinningSyncOperations = 0;
61
67
  this.pinningFailedSyncs = 0;
62
68
  this.pinnedDatabasesByAddress = new Map();
69
+ this.knownDatabasesByAddress = new Set();
63
70
  this.orbitDbNameByAddress = new Map();
64
71
  }
65
72
  /** Resolved DB name from last successful manifest load for this address (if any). */
@@ -77,6 +84,28 @@ export class DatabaseService {
77
84
  // ignore
78
85
  }
79
86
  }
87
+ getKnownHeadsProtocols() {
88
+ return Array.from(this.knownDatabasesByAddress).map((dbAddress) => `${ORBITDB_HEADS_PREFIX}${dbAddress}`);
89
+ }
90
+ isKnownHeadsProtocol(protocol) {
91
+ const dbAddress = this.dbAddressFromHeadsProtocol(protocol);
92
+ return dbAddress != null && this.knownDatabasesByAddress.has(dbAddress);
93
+ }
94
+ async handleOnDemandHeadsProtocol(protocol, context, getRegisteredHandler) {
95
+ const dbAddress = this.dbAddressFromHeadsProtocol(protocol);
96
+ if (dbAddress == null || !this.knownDatabasesByAddress.has(dbAddress)) {
97
+ throw new Error(`No replicated database known for protocol ${protocol}`);
98
+ }
99
+ await this.ensurePeerConnection(context?.connection?.remotePeer);
100
+ const db = await this.retainOpenDatabase(dbAddress);
101
+ try {
102
+ const handlerRecord = await this.waitForRegisteredHeadsHandler(protocol, getRegisteredHandler);
103
+ await handlerRecord.handler(context);
104
+ }
105
+ finally {
106
+ await this.releaseOpenDatabase(dbAddress, db);
107
+ }
108
+ }
80
109
  createPinningHttpHandlers() {
81
110
  return {
82
111
  getStats: () => ({
@@ -204,6 +233,7 @@ export class DatabaseService {
204
233
  }
205
234
  const syncPromise = (async () => {
206
235
  this.pinningSyncOperations++;
236
+ this.rememberKnownDatabaseAddress(dbAddress);
207
237
  const manifest = await this.loadManifest(dbAddress);
208
238
  let dbName = typeof manifest?.name === 'string' && manifest.name ? manifest.name : null;
209
239
  syncLog('Starting sync for database:', inspect({ dbAddress, dbName }, { depth: null, colors: false, compact: false }));
@@ -214,10 +244,12 @@ export class DatabaseService {
214
244
  let receivedUpdate = false;
215
245
  let fallbackScanUsed = false;
216
246
  let extractedMediaCids = [];
247
+ const aclDbAddress = this.normalizeOrbitdbAccessAddress(manifest?.accessController || null);
248
+ this.rememberKnownDatabaseAddress(aclDbAddress);
217
249
  try {
218
250
  aclDb = await this.preOpenAccessController(dbAddress, { manifest });
219
251
  syncLog('Opening database:', inspect({ dbAddress, dbName }, { depth: null, colors: false, compact: false }));
220
- db = await this.openDatabase(dbAddress);
252
+ db = await this.retainOpenDatabase(dbAddress);
221
253
  if (typeof db?.name === 'string' && db.name) {
222
254
  dbName = db.name;
223
255
  }
@@ -234,6 +266,7 @@ export class DatabaseService {
234
266
  if (didReceiveUpdate) {
235
267
  receivedUpdate = true;
236
268
  const updateRecords = updates.map((entry) => ({ value: entry?.payload?.value ?? entry?.value ?? entry }));
269
+ this.rememberKnownDatabaseAddressesFromRecords(updateRecords);
237
270
  const extractedEntries = this.extractImageCids(updateRecords);
238
271
  extractedMediaCids = extractedEntries.map((e) => e.cid);
239
272
  this.logDiscoveredMediaCids(dbAddress, extractedEntries, 'updates');
@@ -249,6 +282,7 @@ export class DatabaseService {
249
282
  const all = await db.all();
250
283
  const rows = Array.isArray(all) ? all : [];
251
284
  const scanRecords = rows.map((row) => ({ value: row?.value ?? row }));
285
+ this.rememberKnownDatabaseAddressesFromRecords(scanRecords);
252
286
  const scanEntries = this.extractImageCids(scanRecords);
253
287
  extractedMediaCids = scanEntries.map((e) => e.cid);
254
288
  if (rows.length === 0) {
@@ -295,19 +329,11 @@ export class DatabaseService {
295
329
  }
296
330
  }
297
331
  finally {
298
- try {
299
- await db?.close?.();
332
+ if (db) {
333
+ await this.releaseOpenDatabase(dbAddress, db);
300
334
  }
301
- catch {
302
- // ignore close failures
303
- }
304
- try {
305
- if (aclDb && aclDb !== db) {
306
- await aclDb.close?.();
307
- }
308
- }
309
- catch {
310
- // ignore close failures
335
+ if (aclDb && aclDb !== db && aclDbAddress) {
336
+ await this.releaseOpenDatabase(aclDbAddress, aclDb);
311
337
  }
312
338
  }
313
339
  return { success, receivedUpdate, fallbackScanUsed, extractedMediaCids };
@@ -723,6 +749,80 @@ export class DatabaseService {
723
749
  }
724
750
  return address.startsWith(ORBITDB_PREFIX) ? address : null;
725
751
  }
752
+ rememberKnownDatabaseAddress(dbAddress) {
753
+ if (typeof dbAddress !== 'string' || !dbAddress.startsWith(ORBITDB_PREFIX)) {
754
+ return;
755
+ }
756
+ this.knownDatabasesByAddress.add(dbAddress);
757
+ }
758
+ rememberKnownDatabaseAddressesFromRecords(records) {
759
+ const visit = (value, depth = 0) => {
760
+ if (depth > 4 || value == null)
761
+ return;
762
+ if (typeof value === 'string') {
763
+ this.rememberKnownDatabaseAddress(value);
764
+ return;
765
+ }
766
+ if (Array.isArray(value)) {
767
+ for (const item of value)
768
+ visit(item, depth + 1);
769
+ return;
770
+ }
771
+ if (typeof value === 'object') {
772
+ for (const nested of Object.values(value)) {
773
+ visit(nested, depth + 1);
774
+ }
775
+ }
776
+ };
777
+ for (const record of records) {
778
+ visit(record?.value ?? record);
779
+ }
780
+ }
781
+ dbAddressFromHeadsProtocol(protocol) {
782
+ if (typeof protocol !== 'string' || !protocol.startsWith(`${ORBITDB_HEADS_PREFIX}/`))
783
+ return null;
784
+ const dbAddress = protocol.slice(ORBITDB_HEADS_PREFIX.length);
785
+ return dbAddress.startsWith(ORBITDB_PREFIX) ? dbAddress : null;
786
+ }
787
+ async waitForRegisteredHeadsHandler(protocol, getRegisteredHandler, timeoutMs = ON_DEMAND_HEADS_HANDLER_TIMEOUT_MS) {
788
+ const startedAt = Date.now();
789
+ let lastError = null;
790
+ while (!this.isShuttingDown && Date.now() - startedAt < timeoutMs) {
791
+ try {
792
+ return getRegisteredHandler(protocol);
793
+ }
794
+ catch (error) {
795
+ lastError = error;
796
+ await delay(50);
797
+ }
798
+ }
799
+ throw lastError ?? new Error(`Timed out waiting for handler ${protocol}`);
800
+ }
801
+ async ensurePeerConnection(remotePeer) {
802
+ if (remotePeer == null)
803
+ return;
804
+ const libp2p = this.ipfs?.libp2p;
805
+ if (!libp2p || typeof libp2p.getConnections !== 'function' || typeof libp2p.dial !== 'function') {
806
+ return;
807
+ }
808
+ try {
809
+ const existingConnections = libp2p.getConnections(remotePeer);
810
+ if (Array.isArray(existingConnections) && existingConnections.some((connection) => connection?.status !== 'closed')) {
811
+ return;
812
+ }
813
+ }
814
+ catch {
815
+ // fall through and try a best-effort dial
816
+ }
817
+ const peerId = remotePeer?.toString?.() || String(remotePeer);
818
+ try {
819
+ await libp2p.dial(remotePeer);
820
+ syncLog('Dialed peer back before on-demand heads open:', peerId);
821
+ }
822
+ catch (error) {
823
+ syncLog('Failed to dial peer back before on-demand heads open:', peerId, error?.message || String(error));
824
+ }
825
+ }
726
826
  summarizeManifest(manifest, dbAddress, cid) {
727
827
  return {
728
828
  dbAddress,
@@ -828,7 +928,7 @@ export class DatabaseService {
828
928
  return null;
829
929
  }
830
930
  syncLog('Pre-opening access controller before database sync:', dbCtx(), 'acl:', accessControllerAddress);
831
- const aclDb = await this.openDatabase(accessControllerAddress);
931
+ const aclDb = await this.retainOpenDatabase(accessControllerAddress);
832
932
  this.installAccessControllerDebugHooks(aclDb, accessControllerAddress);
833
933
  syncLog('Access-controller state after open:', inspect(await this.snapshotDatabaseState(aclDb, 'acl-open'), { depth: null, colors: false, compact: false }));
834
934
  const { didReceiveActivity, activity } = await this.waitForDatabaseActivity(aclDb, timeoutMs);
@@ -856,12 +956,60 @@ export class DatabaseService {
856
956
  const openPromise = this.orbitdb.open(dbAddress);
857
957
  this.openInFlight.set(dbAddress, openPromise);
858
958
  try {
859
- return await openPromise;
959
+ const db = await openPromise;
960
+ this.installNonFatalDatabaseErrorHandlers(db, dbAddress);
961
+ return db;
860
962
  }
861
963
  finally {
862
964
  this.openInFlight.delete(dbAddress);
863
965
  }
864
966
  }
967
+ async retainOpenDatabase(dbAddress) {
968
+ const db = await this.openDatabase(dbAddress);
969
+ this.databaseUseCounts.set(dbAddress, (this.databaseUseCounts.get(dbAddress) ?? 0) + 1);
970
+ return db;
971
+ }
972
+ async releaseOpenDatabase(dbAddress, db) {
973
+ const current = this.databaseUseCounts.get(dbAddress) ?? 0;
974
+ if (current <= 1) {
975
+ this.databaseUseCounts.delete(dbAddress);
976
+ await this.closeDatabaseSilently(db);
977
+ return;
978
+ }
979
+ this.databaseUseCounts.set(dbAddress, current - 1);
980
+ }
981
+ async closeDatabaseSilently(db) {
982
+ try {
983
+ await db?.close?.();
984
+ }
985
+ catch {
986
+ // ignore close failures
987
+ }
988
+ }
989
+ installNonFatalDatabaseErrorHandlers(db, dbAddress) {
990
+ const attach = (emitter, source) => {
991
+ if (!emitter?.on)
992
+ return;
993
+ if (emitter[RELAY_ERROR_HANDLER_INSTALLED])
994
+ return;
995
+ emitter.on('error', (error) => {
996
+ const payload = {
997
+ dbAddress,
998
+ dbName: db?.name || null,
999
+ source,
1000
+ error: error?.message || String(error),
1001
+ stack: error?.stack || null,
1002
+ };
1003
+ // eslint-disable-next-line no-console
1004
+ console.error('OrbitDB emitted a non-fatal error:', inspect(payload, { depth: null, colors: false, compact: false }));
1005
+ });
1006
+ emitter[RELAY_ERROR_HANDLER_INSTALLED] = true;
1007
+ };
1008
+ attach(db?.events, 'db.events');
1009
+ if (db?.sync?.events && db.sync.events !== db.events) {
1010
+ attach(db.sync.events, 'db.sync.events');
1011
+ }
1012
+ }
865
1013
  installAccessControllerDebugHooks(db, dbAddress) {
866
1014
  if (!loggingConfig.enableSyncLogs)
867
1015
  return;