@pkcprotocol/pkc-js 0.0.93 → 0.0.94

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.
Files changed (67) hide show
  1. package/dist/browser/clients/base-client-manager.d.ts +1 -0
  2. package/dist/browser/clients/base-client-manager.js +7 -1
  3. package/dist/browser/clients/base-client-manager.js.map +1 -1
  4. package/dist/browser/clients/rpc-client/pkc-rpc-client.d.ts +1 -0
  5. package/dist/browser/clients/rpc-client/pkc-rpc-client.js +27 -1
  6. package/dist/browser/clients/rpc-client/pkc-rpc-client.js.map +1 -1
  7. package/dist/browser/community/community-client-manager.d.ts +16 -0
  8. package/dist/browser/community/community-client-manager.js +307 -31
  9. package/dist/browser/community/community-client-manager.js.map +1 -1
  10. package/dist/browser/community/remote-community.js +7 -0
  11. package/dist/browser/community/remote-community.js.map +1 -1
  12. package/dist/browser/generated-version.d.ts +1 -1
  13. package/dist/browser/generated-version.js +1 -1
  14. package/dist/browser/helia/helia-for-pkc.js +56 -1
  15. package/dist/browser/helia/helia-for-pkc.js.map +1 -1
  16. package/dist/browser/helia/types.d.ts +16 -0
  17. package/dist/browser/helia/util.d.ts +1 -0
  18. package/dist/browser/helia/util.js +21 -1
  19. package/dist/browser/helia/util.js.map +1 -1
  20. package/dist/browser/rpc/src/index.d.ts +2 -0
  21. package/dist/browser/rpc/src/index.js +52 -19
  22. package/dist/browser/rpc/src/index.js.map +1 -1
  23. package/dist/browser/test/test-util.d.ts +353 -5
  24. package/dist/browser/test/test-util.js +88 -5
  25. package/dist/browser/test/test-util.js.map +1 -1
  26. package/dist/browser/util.d.ts +7 -0
  27. package/dist/browser/util.js +21 -11
  28. package/dist/browser/util.js.map +1 -1
  29. package/dist/bundled/bundle-manifest.json +25 -25
  30. package/dist/bundled/chunks/{helia-for-pkc-C8tOPlIj.js → helia-for-pkc-Bj-Zb4JN.js} +70 -33
  31. package/dist/bundled/chunks/{local-community-DYEWq5rq.js → local-community-BrMLMEmt.js} +1 -1
  32. package/dist/bundled/chunks/{local-community-DgbMuVAA.js → local-community-Ce7303vY.js} +30 -30
  33. package/dist/bundled/chunks/{node-BrLiC0qX.js → node-C37nDOa8.js} +21 -6
  34. package/dist/bundled/chunks/{rpc-local-community-DOSee621.js → rpc-local-community-Dr_-Lb8I.js} +151 -18
  35. package/dist/bundled/chunks/{schema-HH2zeH-j.js → schema-5-rYJ-bC.js} +29 -12
  36. package/dist/bundled/chunks/{util-DSIDv1Cb.js → util-_-fNQNIV.js} +11 -3
  37. package/dist/bundled/index.js +1 -1
  38. package/dist/bundled/rpc/src/index.js +43 -22
  39. package/dist/node/clients/base-client-manager.d.ts +1 -0
  40. package/dist/node/clients/base-client-manager.js +7 -1
  41. package/dist/node/clients/base-client-manager.js.map +1 -1
  42. package/dist/node/clients/rpc-client/pkc-rpc-client.d.ts +1 -0
  43. package/dist/node/clients/rpc-client/pkc-rpc-client.js +27 -1
  44. package/dist/node/clients/rpc-client/pkc-rpc-client.js.map +1 -1
  45. package/dist/node/community/community-client-manager.d.ts +16 -0
  46. package/dist/node/community/community-client-manager.js +307 -31
  47. package/dist/node/community/community-client-manager.js.map +1 -1
  48. package/dist/node/community/remote-community.js +7 -0
  49. package/dist/node/community/remote-community.js.map +1 -1
  50. package/dist/node/generated-version.d.ts +1 -1
  51. package/dist/node/generated-version.js +1 -1
  52. package/dist/node/helia/helia-for-pkc.js +56 -1
  53. package/dist/node/helia/helia-for-pkc.js.map +1 -1
  54. package/dist/node/helia/types.d.ts +16 -0
  55. package/dist/node/helia/util.d.ts +1 -0
  56. package/dist/node/helia/util.js +21 -1
  57. package/dist/node/helia/util.js.map +1 -1
  58. package/dist/node/rpc/src/index.d.ts +2 -0
  59. package/dist/node/rpc/src/index.js +52 -19
  60. package/dist/node/rpc/src/index.js.map +1 -1
  61. package/dist/node/test/test-util.d.ts +353 -5
  62. package/dist/node/test/test-util.js +88 -5
  63. package/dist/node/test/test-util.js.map +1 -1
  64. package/dist/node/util.d.ts +7 -0
  65. package/dist/node/util.js +21 -11
  66. package/dist/node/util.js.map +1 -1
  67. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import { i as __toESM, n as __exportAll, r as __require, t as __commonJSMin } from "./chunk-2rV9d50f.js";
2
- import { $ as pubsubTopicToDhtKey, $n as n$10, $t as ChallengeFileSchema, A as extractNetworkErrorDetails, An as CommentUpdateSignedPropertyNames, Ar as literal, At as refreshTrackedCommunityAliases, B as isIpfsCid, Bt as pTimeout, Cn as CommentPubsubMessageWithFlexibleAuthorRefinementSchema, Cr as require_supports_color, Ct as findStartedCommunity, D as deepMergeRuntimeFields, Dn as CommentUpdateForChallengeVerificationSignedPropertyNames, Dr as array, E as createAbortError, Er as _enum, Et as listStartedCommunities, Fn as ModQueuePageIpfsSchema, Ft as untrackStartedCommunity, Gn as AuthorCommentIpfsReservedFields, Gt as CreateCommunityEditPublicationOptionsWithRefinementSchema, H as isIpns, I as getPostUpdateTimestampRange, In as PageIpfsSchema, It as untrackUpdatingComment, Jn as CidPathSchema, Kt as CommentModerationChallengeRequestToEncryptSchema, L as hideClassPrivateProps, Ln as CommentEditChallengeRequestToEncryptSchema, Lt as untrackUpdatingCommunity, Mr as object, Mt as trackStartedCommunity, Nn as CreateCommentOptionsWithRefinementSchema, Nr as record, O as derivePublicationFromChallengeRequest, On as CommentUpdateReservedFields, Or as boolean, Ot as listUpdatingCommunities, Pn as GetPageParamSchema, Pr as string, Pt as trackUpdatingCommunity, Q as isStringDomain, Qn as CreateSignerSchema, Qt as ChallengeFileFactorySchema, R as ipnsNameToIpnsOverPubsubTopic, Rt as require_sha256$1, Sr as logger_default, Tn as CommentUpdateChallengeReservedFieldNames, Tt as findUpdatingCommunity, U as isIpnsPath, Un as CreateCommentEditOptionsWithRefinementSchema, Ut as CommunityEditPublicationSignedPropertyNames, V as isIpfsPath, Vn as CommentEditSignedPropertyNames, Vt as CommunityEditPublicationChallengeRequestToEncryptSchema, Wn as AuthorAddressSchema, Wt as CommunityEditPubsubMessagePublicationSchema, X as isRequestPubsubPublicationOfPost, Xn as CommunityAddressSchema, Xt as CommentModerationsTableRowSchema, Yn as CidStringSchema, Yt as CommentModerationSignedPropertyNames, Z as isRequestPubsubPublicationOfReply, Zn as CommunityAuthorChallengeReservedFieldNames, Zt as CreateCommentModerationOptionsWithRefinementSchema, _ as PKCUserOptionBaseSchema, _n as VoteSignedPropertyNames, _r as FailedToFetchCommunityFromGatewaysError, an as CommunityIpfsSchema, ar as e$5, b as areEquivalentCommunityAddresses, bn as CommentIpfsReservedFields, br as PKCError, bt as waitForUpdateInCommunityInstanceWithErrorAndTimeout, c as ChallengeVerificationMessageSignedPropertyNames, cn as CreateRemoteCommunityFunctionArgumentSchema, cr as t$12, dr as t$10, f as DecryptedChallengeSchema, fn as RpcRemoteCommunityUpdateEventResultSchema, fr as t$9, g as PKCParsedOptionsSchema, gr as FailedToFetchCommentUpdateFromGatewaysError, gt as sleepUntilTimeoutOrAbort, h as NameResolverSerializedSchema, hn as VotePubsubMessagePublicationSchema, hr as FailedToFetchCommentIpfsFromGatewaysError, ht as shortifyCid, i as ChallengeMessageSignedPropertyNames, in as CommunityIpfsReservedFields, ir as e$6, j as fetchAndValidateIpnsRecordFromGateway, jr as number, k as doesDomainAddressHaveCapitalLetter, kn as CommentUpdateSchema, kr as custom, l as DecryptedChallengeAnswerSchema, ln as CreateRpcCommunityFunctionArgumentSchema, lr as n$8, m as NameResolveCacheOptionsSchema, mn as VoteChallengeRequestToEncryptSchema, mr as require_retry$1, mt as shortifyAddress, n as ChallengeAnswerMessageSignedPropertyNames, nn as CommunityEditOptionsSchema, o as ChallengeRequestMessageSignedPropertyNames, on as CommunitySignedPropertyNames, or as t$11, ot as removeNullUndefinedEmptyObjectsValuesRecursively, p as DecryptedChallengeVerificationSchema, pn as CreateVoteUserOptionsWithRefinementSchema, pr as e$4, qn as ChallengeAnswersSchema, qt as CommentModerationPubsubMessagePublicationSchema, rn as CommunityExportRecordsSchema, rr as t$13, sn as CreateNewLocalCommunityUserOptionsSchema, sr as r$8, tn as CommunityChallengeSettingSchema, tr as n$9, tt as raceAgainstAbort, un as ExportCommunityModLogsOptionsSchema, ur as r$7, ut as resolveWhenPredicateIsTrue, v as PKCUserOptionsSchema, vr as FailedToFetchGenericIpfsFromGatewaysError, vt as throwIfAbortSignalAborted, wn as CommentSignedPropertyNames, wr as require_ms$1, wt as findUpdatingComment, x as calculateIpfsCidV0, xn as CommentIpfsSchema, xr as messages, yn as CommentChallengeRequestToEncryptSchema, yr as FailedToFetchPageIpfsFromGatewaysError, yt as timestamp, z as isAbortError, zn as CommentEditPubsubMessagePublicationWithFlexibleAuthorSchema } from "./schema-HH2zeH-j.js";
2
+ import { $ as isRequestPubsubPublicationOfReply, $n as CommunityAuthorChallengeReservedFieldNames, $t as CreateCommentModerationOptionsWithRefinementSchema, A as doesDomainAddressHaveCapitalLetter, An as CommentUpdateReservedFields, Ar as boolean, At as listUpdatingCommunities, B as ipnsNameToIpnsOverPubsubTopic, Bt as require_sha256$1, Cn as CommentIpfsSchema, Cr as messages, D as createAbortError, Dn as CommentUpdateChallengeReservedFieldNames, Dt as findUpdatingCommunity, En as CommentSignedPropertyNames, Er as require_ms$1, Et as findUpdatingComment, Fn as CreateCommentOptionsWithRefinementSchema, Fr as record, G as isIpnsPath, Gn as CreateCommentEditOptionsWithRefinementSchema, Gt as CommunityEditPublicationSignedPropertyNames, H as isIpfsCid, Ht as pTimeout, In as GetPageParamSchema, Ir as string, It as trackUpdatingCommunity, Jt as CommentModerationChallengeRequestToEncryptSchema, Kn as AuthorAddressSchema, Kt as CommunityEditPubsubMessagePublicationSchema, L as getPostUpdateTimestampRange, Ln as ModQueuePageIpfsSchema, Lt as untrackStartedCommunity, M as fetchAndValidateIpnsRecordFromGateway, Mn as CommentUpdateSignedPropertyNames, Mr as literal, Mt as refreshTrackedCommunityAliases, Nr as number, O as deepMergeRuntimeFields, Or as _enum, Ot as listStartedCommunities, Pr as object, Pt as trackStartedCommunity, Q as isRequestPubsubPublicationOfPost, Qn as CommunityAddressSchema, Qt as CommentModerationsTableRowSchema, R as hideClassPrivateProps, Rn as PageIpfsSchema, Rt as untrackUpdatingComment, S as calculateIpfsCidV0, Sn as CommentIpfsReservedFields, Sr as PKCError, St as waitForUpdateInCommunityInstanceWithErrorAndTimeout, Tn as CommentPubsubMessageWithFlexibleAuthorRefinementSchema, Tr as require_supports_color, Tt as findStartedCommunity, U as isIpfsPath, Un as CommentEditSignedPropertyNames, Ut as CommunityEditPublicationChallengeRequestToEncryptSchema, V as isAbortError, Vn as CommentEditPubsubMessagePublicationWithFlexibleAuthorSchema, W as isIpns, Xn as CidPathSchema, Yn as ChallengeAnswersSchema, Yt as CommentModerationPubsubMessagePublicationSchema, Zn as CidStringSchema, Zt as CommentModerationSignedPropertyNames, _ as PKCUserOptionBaseSchema, _n as VotePubsubMessagePublicationSchema, _r as FailedToFetchCommentIpfsFromGatewaysError, _t as shortifyCid, an as CommunityExportRecordsSchema, ar as t$13, b as areEquivalentCommunityAddresses, br as FailedToFetchGenericIpfsFromGatewaysError, bt as throwIfAbortSignalAborted, c as ChallengeVerificationMessageSignedPropertyNames, cn as CommunitySignedPropertyNames, cr as t$11, ct as removeNullUndefinedEmptyObjectsValuesRecursively, dn as CreateRpcCommunityFunctionArgumentSchema, dr as n$8, en as ChallengeFileFactorySchema, er as CreateSignerSchema, et as isStringDomain, f as DecryptedChallengeSchema, fn as ExportCommunityModLogsOptionsSchema, fr as r$7, ft as resolveWhenPredicateIsTrue, g as PKCParsedOptionsSchema, gn as VoteChallengeRequestToEncryptSchema, gr as require_retry$1, gt as shortifyAddress, h as NameResolverSerializedSchema, hn as CreateVoteUserOptionsWithRefinementSchema, hr as e$4, i as ChallengeMessageSignedPropertyNames, in as CommunityEditOptionsSchema, j as extractNetworkErrorDetails, jn as CommentUpdateSchema, jr as custom, k as derivePublicationFromChallengeRequest, kn as CommentUpdateForChallengeVerificationSignedPropertyNames, kr as array, l as DecryptedChallengeAnswerSchema, ln as CreateNewLocalCommunityUserOptionsSchema, lr as r$8, m as NameResolveCacheOptionsSchema, mn as RpcRemoteCommunityUpdateEventResultSchema, mr as t$9, n as ChallengeAnswerMessageSignedPropertyNames, o as ChallengeRequestMessageSignedPropertyNames, on as CommunityIpfsReservedFields, or as e$6, p as DecryptedChallengeVerificationSchema, pr as t$10, qn as AuthorCommentIpfsReservedFields, qt as CreateCommunityEditPublicationOptionsWithRefinementSchema, rn as CommunityChallengeSettingSchema, rr as n$9, rt as raceAgainstAbort, sn as CommunityIpfsSchema, sr as e$5, tn as ChallengeFileSchema, tr as n$10, tt as pubsubTopicToDhtKey, un as CreateRemoteCommunityFunctionArgumentSchema, ur as t$12, v as PKCUserOptionsSchema, vr as FailedToFetchCommentUpdateFromGatewaysError, vt as sleepUntilTimeoutOrAbort, wr as logger_default, xn as CommentChallengeRequestToEncryptSchema, xr as FailedToFetchPageIpfsFromGatewaysError, xt as timestamp, yn as VoteSignedPropertyNames, yr as FailedToFetchCommunityFromGatewaysError, z as interruptibleSleep, zn as CommentEditChallengeRequestToEncryptSchema, zt as untrackUpdatingCommunity } from "./schema-5-rYJ-bC.js";
3
3
  import { t as all } from "./src-CYIMjhjK.js";
4
4
  import { createHash } from "node:crypto";
5
5
  import { pathToFileURL } from "node:url";
@@ -125415,12 +125415,18 @@ function selectWinningGatewayCommunity(opts) {
125415
125415
  //#endregion
125416
125416
  //#region dist/node/community/community-client-manager.js
125417
125417
  const MAX_FILE_SIZE_BYTES_FOR_COMMUNITY_IPFS = 1024 * 1024;
125418
+ const FORCED_IPNS_NETWORK_REVALIDATION_MIN_INTERVAL_MS = 3e4;
125418
125419
  var CommunityClientsManager = class extends PKCClientsManager {
125419
125420
  constructor(community) {
125420
125421
  super(community._pkc);
125421
125422
  this._suppressUpdatingStateForNameResolution = 0;
125422
125423
  this._ipnsLoadingOperation = void 0;
125423
125424
  this._updateCidsAlreadyLoaded = new LimitedSet(30);
125425
+ this._subscribedIpnsArrivalTopics = /* @__PURE__ */ new Set();
125426
+ this._pendingIpnsArrivalCids = /* @__PURE__ */ new Set();
125427
+ this._pendingIpnsArrivalHopTargets = /* @__PURE__ */ new Set();
125428
+ this._nextResolveRevalidatesNetwork = false;
125429
+ this._lastForcedIpnsNetworkRevalidationAtMs = 0;
125424
125430
  this._community = community;
125425
125431
  this._initPKCRpcClients();
125426
125432
  hideClassPrivateProps(this);
@@ -125583,20 +125589,127 @@ var CommunityClientsManager = class extends PKCClientsManager {
125583
125589
  async startUpdatingLoop() {
125584
125590
  const log = logger_default("pkc-js:remote-community:update");
125585
125591
  this._community._createStopAbortController();
125586
- const updateInterval = Object.keys(this._pkc.clients.kuboRpcClients).length > 0 || Object.keys(this._pkc.clients.libp2pJsClients).length > 0 ? 1e3 : this._pkc.updateInterval;
125592
+ const areWeConnectedToKuboOrHelia = Object.keys(this._pkc.clients.kuboRpcClients).length > 0 || Object.keys(this._pkc.clients.libp2pJsClients).length > 0;
125593
+ const defaultIpfsClient = areWeConnectedToKuboOrHelia ? this.getDefaultKuboRpcClientOrHelia() : void 0;
125594
+ const defaultLibp2pJsClient = defaultIpfsClient && "_helia" in defaultIpfsClient ? defaultIpfsClient : void 0;
125595
+ if (defaultLibp2pJsClient) {
125596
+ try {
125597
+ this._syncIpnsArrivalSubscriptions(defaultLibp2pJsClient);
125598
+ } catch (e) {
125599
+ log.error(`Failed to arm IPNS record arrival subscriptions of community ${this._community.address} before its first update`, e);
125600
+ }
125601
+ this._lastForcedIpnsNetworkRevalidationAtMs = Date.now();
125602
+ }
125587
125603
  while (this._community.state === "updating" && !this._community._getStopAbortSignal()?.aborted) try {
125588
125604
  await this.updateOnce();
125589
125605
  } catch (e) {
125590
125606
  log.error(`Failed to update community ${this._community.address} for this iteration, will retry later`, e);
125591
125607
  } finally {
125592
- await sleepUntilTimeoutOrAbort(updateInterval, this._community._getStopAbortSignal());
125608
+ if (defaultLibp2pJsClient) {
125609
+ try {
125610
+ this._syncIpnsArrivalSubscriptions(defaultLibp2pJsClient);
125611
+ } catch (e) {
125612
+ log.error(`Failed to sync IPNS record arrival subscriptions of community ${this._community.address}`, e);
125613
+ }
125614
+ const safetyNetMs = this._pkc.updateInterval * (.75 + Math.random() * .5);
125615
+ await this._sleepUntilIpnsArrivalOrTimeoutOrAbort({
125616
+ ms: safetyNetMs,
125617
+ signal: this._community._getStopAbortSignal()
125618
+ });
125619
+ } else await sleepUntilTimeoutOrAbort(areWeConnectedToKuboOrHelia ? 1e3 : this._pkc.updateInterval, this._community._getStopAbortSignal());
125593
125620
  }
125621
+ this._clearIpnsArrivalSubscriptions();
125594
125622
  this._community._clearStopAbortController();
125595
125623
  log("Community", this._community.address, "is no longer updating");
125596
125624
  }
125597
125625
  async stopUpdatingLoop() {
125598
125626
  this._ipnsLoadingOperation?.stop();
125599
125627
  this._updateCidsAlreadyLoaded.clear();
125628
+ this._clearIpnsArrivalSubscriptions();
125629
+ }
125630
+ _onIpnsRecordArrival(arrival) {
125631
+ const value = arrival.record.value;
125632
+ if (isIpfsPath(value)) {
125633
+ const cid = value.split("/")[2];
125634
+ if (this._updateCidsAlreadyLoaded.has(cid) || this._community.updateCid === cid) return;
125635
+ this._pendingIpnsArrivalCids.add(cid);
125636
+ } else if (isIpnsPath(value)) {
125637
+ const hopTarget = value.split("/")[2];
125638
+ if (this._community.ipnsHops?.includes(hopTarget)) return;
125639
+ this._pendingIpnsArrivalHopTargets.add(hopTarget);
125640
+ } else return;
125641
+ this._wakeUpdateLoopForIpnsArrival?.();
125642
+ }
125643
+ _consumePendingIpnsArrivals() {
125644
+ for (const cid of this._pendingIpnsArrivalCids) if (this._updateCidsAlreadyLoaded.has(cid) || this._community.updateCid === cid) this._pendingIpnsArrivalCids.delete(cid);
125645
+ for (const hopTarget of this._pendingIpnsArrivalHopTargets) if (this._community.ipnsHops?.includes(hopTarget)) this._pendingIpnsArrivalHopTargets.delete(hopTarget);
125646
+ if (this._pendingIpnsArrivalCids.size === 0 && this._pendingIpnsArrivalHopTargets.size === 0) return false;
125647
+ this._pendingIpnsArrivalCids.clear();
125648
+ this._pendingIpnsArrivalHopTargets.clear();
125649
+ return true;
125650
+ }
125651
+ _syncIpnsArrivalSubscriptions(client) {
125652
+ if (!this._ipnsArrivalListener) this._ipnsArrivalListener = (arrival) => this._onIpnsRecordArrival(arrival);
125653
+ this._ipnsArrivalClient = client;
125654
+ const preResolveIpnsName = this._community.ipnsName ?? this._pinnedIpnsName() ?? (!isStringDomain(this._community.address) ? this._community.address : void 0);
125655
+ const ipnsNamesToWatch = this._community.ipnsHops?.length ? this._community.ipnsHops : preResolveIpnsName ? [preResolveIpnsName] : [];
125656
+ const desiredTopics = new Set(ipnsNamesToWatch.map(ipnsNameToIpnsOverPubsubTopic));
125657
+ for (const topic of this._subscribedIpnsArrivalTopics) if (!desiredTopics.has(topic)) {
125658
+ client.heliaWithKuboRpcClientFunctions.ipnsRecordArrivals.unsubscribe({
125659
+ pubsubTopic: topic,
125660
+ listener: this._ipnsArrivalListener
125661
+ });
125662
+ this._subscribedIpnsArrivalTopics.delete(topic);
125663
+ }
125664
+ for (const topic of desiredTopics) if (!this._subscribedIpnsArrivalTopics.has(topic)) {
125665
+ client.heliaWithKuboRpcClientFunctions.ipnsRecordArrivals.subscribe({
125666
+ pubsubTopic: topic,
125667
+ listener: this._ipnsArrivalListener
125668
+ });
125669
+ this._subscribedIpnsArrivalTopics.add(topic);
125670
+ }
125671
+ }
125672
+ _resyncIpnsArrivalSubscriptionsIfArmed() {
125673
+ if (!this._ipnsArrivalClient) return;
125674
+ try {
125675
+ this._syncIpnsArrivalSubscriptions(this._ipnsArrivalClient);
125676
+ } catch (e) {
125677
+ logger_default("pkc-js:remote-community:update").error(`Failed to sync IPNS record arrival subscriptions of community ${this._community.address}`, e);
125678
+ }
125679
+ }
125680
+ _clearIpnsArrivalSubscriptions() {
125681
+ if (this._ipnsArrivalClient && this._ipnsArrivalListener) for (const topic of this._subscribedIpnsArrivalTopics) this._ipnsArrivalClient.heliaWithKuboRpcClientFunctions.ipnsRecordArrivals.unsubscribe({
125682
+ pubsubTopic: topic,
125683
+ listener: this._ipnsArrivalListener
125684
+ });
125685
+ this._subscribedIpnsArrivalTopics.clear();
125686
+ this._ipnsArrivalClient = void 0;
125687
+ this._pendingIpnsArrivalCids.clear();
125688
+ this._pendingIpnsArrivalHopTargets.clear();
125689
+ this._nextResolveRevalidatesNetwork = false;
125690
+ }
125691
+ async _sleepUntilIpnsArrivalOrTimeoutOrAbort({ ms, signal }) {
125692
+ if (this._consumePendingIpnsArrivals()) {
125693
+ this._nextResolveRevalidatesNetwork = false;
125694
+ return;
125695
+ }
125696
+ const { promise, wake } = interruptibleSleep({
125697
+ ms,
125698
+ signal
125699
+ });
125700
+ let wokenByArrival = false;
125701
+ const wakeForArrival = () => {
125702
+ wokenByArrival = true;
125703
+ wake();
125704
+ };
125705
+ this._wakeUpdateLoopForIpnsArrival = wakeForArrival;
125706
+ await promise;
125707
+ if (this._wakeUpdateLoopForIpnsArrival === wakeForArrival) this._wakeUpdateLoopForIpnsArrival = void 0;
125708
+ if (wokenByArrival) {
125709
+ this._pendingIpnsArrivalCids.clear();
125710
+ this._pendingIpnsArrivalHopTargets.clear();
125711
+ }
125712
+ this._nextResolveRevalidatesNetwork = !wokenByArrival && Date.now() - this._lastForcedIpnsNetworkRevalidationAtMs >= FORCED_IPNS_NETWORK_REVALIDATION_MIN_INTERVAL_MS;
125600
125713
  }
125601
125714
  async _resolveCommunityNameWithoutUpdatingState({ communityName, abortSignal, cache }) {
125602
125715
  this._suppressUpdatingStateForNameResolution++;
@@ -125618,6 +125731,25 @@ var CommunityClientsManager = class extends PKCClientsManager {
125618
125731
  if (this._community.publicKey) chainKeys.delete(this._community.publicKey);
125619
125732
  return [...chainKeys];
125620
125733
  }
125734
+ _applyKeyMigration({ communityName, newPublicKey }) {
125735
+ logger_default("pkc-js:community-client-manager:_applyKeyMigration")("Key migration detected for", communityName, "old:", this._community.publicKey, "new:", newPublicKey);
125736
+ const previousPublicKey = this._community.publicKey;
125737
+ const error = new PKCError("ERR_COMMUNITY_NAME_RESOLVES_TO_DIFFERENT_PUBLIC_KEY", {
125738
+ communityName,
125739
+ previousPublicKey,
125740
+ newPublicKey
125741
+ });
125742
+ this._community._clearDataForKeyMigration(newPublicKey);
125743
+ this._updateCidsAlreadyLoaded.clear();
125744
+ this._community.nameResolved = true;
125745
+ this._pendingIpnsArrivalCids.clear();
125746
+ this._pendingIpnsArrivalHopTargets.clear();
125747
+ this._resyncIpnsArrivalSubscriptionsIfArmed();
125748
+ this._community._abortStopOperations("Key migration: name resolved to different public key");
125749
+ this._community._createStopAbortController();
125750
+ this._community.emit("update", this._community);
125751
+ this._community.emit("error", error);
125752
+ }
125621
125753
  _resolveNameInBackground(name) {
125622
125754
  const log = logger_default("pkc-js:community-client-manager:_resolveNameInBackground");
125623
125755
  const setNameResolvedAndEmitUpdate = (newNameResolved) => {
@@ -125636,20 +125768,10 @@ var CommunityClientsManager = class extends PKCClientsManager {
125636
125768
  setNameResolvedAndEmitUpdate(false);
125637
125769
  return;
125638
125770
  }
125639
- log("Key migration detected for", name, "old:", this._community.publicKey, "new:", resolved);
125640
- const previousPublicKey = this._community.publicKey;
125641
- const error = new PKCError("ERR_COMMUNITY_NAME_RESOLVES_TO_DIFFERENT_PUBLIC_KEY", {
125771
+ this._applyKeyMigration({
125642
125772
  communityName: name,
125643
- previousPublicKey,
125644
125773
  newPublicKey: resolved
125645
125774
  });
125646
- this._community._clearDataForKeyMigration(resolved);
125647
- this._updateCidsAlreadyLoaded.clear();
125648
- this._community.nameResolved = true;
125649
- this._community._abortStopOperations("Key migration: name resolved to different public key");
125650
- this._community._createStopAbortController();
125651
- this._community.emit("update", this._community);
125652
- this._community.emit("error", error);
125653
125775
  } else if (resolved) setNameResolvedAndEmitUpdate(true);
125654
125776
  if (!resolved && this._community.name) setNameResolvedAndEmitUpdate(false);
125655
125777
  }).catch((e) => {
@@ -125681,13 +125803,18 @@ var CommunityClientsManager = class extends PKCClientsManager {
125681
125803
  abortSignal: this._community._getStopAbortSignal()
125682
125804
  });
125683
125805
  }
125806
+ _pinnedIpnsName() {
125807
+ const isDomain = isStringDomain(this._community.address);
125808
+ const hasAnchorClaim = Boolean(this._community.anchor);
125809
+ if (this._community.publicKey && (isDomain || hasAnchorClaim || !isDomain && this._community.name && this._community.nameResolved === true)) return this._community.publicKey;
125810
+ }
125684
125811
  async fetchNewUpdateForCommunity(communityAddress) {
125685
125812
  return this._withInflightCommunityFetch(communityAddress, async () => {
125686
125813
  let ipnsName;
125687
125814
  const isDomain = isStringDomain(communityAddress);
125688
- const hasAnchorClaim = Boolean(this._community.anchor);
125689
- if (this._community.publicKey && (isDomain || hasAnchorClaim || !isDomain && this._community.name && this._community.nameResolved === true)) {
125690
- ipnsName = this._community.publicKey;
125815
+ const pinnedIpnsName = this._pinnedIpnsName();
125816
+ if (pinnedIpnsName) {
125817
+ ipnsName = pinnedIpnsName;
125691
125818
  if (isDomain) this._resolveNameInBackground(communityAddress);
125692
125819
  } else ipnsName = await this.resolveCommunityNameIfNeeded({
125693
125820
  communityName: communityAddress,
@@ -125701,6 +125828,7 @@ var CommunityClientsManager = class extends PKCClientsManager {
125701
125828
  this._community.ipnsHops = [ipnsName];
125702
125829
  this._community.ipnsPubsubTopic = ipnsNameToIpnsOverPubsubTopic(ipnsName);
125703
125830
  this._community.ipnsPubsubTopicRoutingCid = pubsubTopicToDhtKey(this._community.ipnsPubsubTopic);
125831
+ this._resyncIpnsArrivalSubscriptionsIfArmed();
125704
125832
  }
125705
125833
  if (this._community.updateCid) this._updateCidsAlreadyLoaded.add(this._community.updateCid);
125706
125834
  this._community._setUpdatingStateWithEventEmissionIfNewState("fetching-ipns");
@@ -125742,9 +125870,13 @@ var CommunityClientsManager = class extends PKCClientsManager {
125742
125870
  const kuboRpcOrHelia = this.getDefaultKuboRpcClientOrHelia();
125743
125871
  if ("_helia" in kuboRpcOrHelia) this.updateLibp2pJsClientState("fetching-ipns", kuboRpcOrHelia._libp2pJsClientsOptions.key);
125744
125872
  else this.updateKuboRpcState("fetching-ipns", kuboRpcOrHelia.url);
125873
+ const forceNetworkRevalidation = this._nextResolveRevalidatesNetwork;
125874
+ this._nextResolveRevalidatesNetwork = false;
125875
+ if (forceNetworkRevalidation) this._lastForcedIpnsNetworkRevalidationAtMs = Date.now();
125745
125876
  const { cid: latestCommunityCid, ipnsHops } = await this.resolveIpnsToCidP2P(ipnsName, {
125746
125877
  timeoutMs: this._pkc._timeouts["community-ipns"],
125747
- abortSignal: this._community._getStopAbortSignal()
125878
+ abortSignal: this._community._getStopAbortSignal(),
125879
+ ...forceNetworkRevalidation ? { nocache: true } : {}
125748
125880
  });
125749
125881
  this._community.ipnsHops = ipnsHops;
125750
125882
  ipnsHops[ipnsHops.length - 1];
@@ -126387,6 +126519,7 @@ var RemoteCommunity = class extends import_lib$1.TypedEmitter {
126387
126519
  this.pubsubTopicRoutingCid = void 0;
126388
126520
  this.publicKey = newPublicKey;
126389
126521
  this.ipnsName = newPublicKey;
126522
+ this.ipnsHops = [newPublicKey];
126390
126523
  this.ipnsPubsubTopic = ipnsNameToIpnsOverPubsubTopic(newPublicKey);
126391
126524
  this.ipnsPubsubTopicRoutingCid = pubsubTopicToDhtKey(this.ipnsPubsubTopic);
126392
126525
  this._assertHasIdentity();
@@ -15376,17 +15376,28 @@ function throwIfAbortSignalAborted(signal) {
15376
15376
  if (typeof signal.reason === "string" && signal.reason.length > 0) throw createAbortError(signal.reason);
15377
15377
  throw createAbortError();
15378
15378
  }
15379
+ function interruptibleSleep({ ms, signal }) {
15380
+ let wake = () => void 0;
15381
+ return {
15382
+ promise: new Promise((resolve) => {
15383
+ if (signal?.aborted) return resolve();
15384
+ const settle = () => {
15385
+ clearTimeout(timer);
15386
+ signal?.removeEventListener("abort", settle);
15387
+ resolve();
15388
+ };
15389
+ const timer = setTimeout(settle, ms);
15390
+ signal?.addEventListener("abort", settle, { once: true });
15391
+ wake = settle;
15392
+ }),
15393
+ wake
15394
+ };
15395
+ }
15379
15396
  function sleepUntilTimeoutOrAbort(ms, signal) {
15380
- return new Promise((resolve) => {
15381
- if (signal?.aborted) return resolve();
15382
- const onAbortOrTimeout = () => {
15383
- clearTimeout(timer);
15384
- signal?.removeEventListener("abort", onAbortOrTimeout);
15385
- resolve();
15386
- };
15387
- const timer = setTimeout(onAbortOrTimeout, ms);
15388
- signal?.addEventListener("abort", onAbortOrTimeout, { once: true });
15389
- });
15397
+ return interruptibleSleep({
15398
+ ms,
15399
+ signal
15400
+ }).promise;
15390
15401
  }
15391
15402
  async function raceAgainstAbort(promise, signal) {
15392
15403
  if (!signal) return promise;
@@ -15803,6 +15814,12 @@ async function waitForUpdateInCommunityInstanceWithErrorAndTimeout(opts) {
15803
15814
  function calculateIpfsCidV0(content) {
15804
15815
  return of(content);
15805
15816
  }
15817
+ /**
15818
+ * converts a binary record key to a pubsub topic key
15819
+ */
15820
+ function binaryKeyToPubsubTopic(key) {
15821
+ return `/record/${toString(key, "base64url")}`;
15822
+ }
15806
15823
  function ipnsNameToIpnsOverPubsubTopic(ipnsName) {
15807
15824
  const ipnsNamespaceBytes = new TextEncoder().encode("/ipns/");
15808
15825
  const ipnsNameBytes = peerIdFromString(ipnsName).toMultihash().bytes;
@@ -16206,7 +16223,7 @@ function extractNetworkErrorDetails(err, depth = 0) {
16206
16223
  }
16207
16224
  //#endregion
16208
16225
  //#region dist/node/generated-version.js
16209
- const version = "0.0.93";
16226
+ const version = "0.0.94";
16210
16227
  //#endregion
16211
16228
  //#region dist/node/version.js
16212
16229
  const protocolVersion = ProtocolVersionSchema.parse("1.0.0");
@@ -16360,4 +16377,4 @@ const DecryptedChallengeVerificationSchema = object({
16360
16377
  }).strict();
16361
16378
  const ChallengeVerificationMessageSignedPropertyNames = t$3(n$3(ChallengeVerificationMessageSchema.shape, ["signature"]));
16362
16379
  //#endregion
16363
- export { pubsubTopicToDhtKey as $, n as $n, ChallengeFileSchema as $t, extractNetworkErrorDetails as A, CommentUpdateSignedPropertyNames as An, literal as Ar, refreshTrackedCommunityAliases as At, isIpfsCid as B, CommentEditReservedFields as Bn, pTimeout as Bt, contentContainsMarkdownAudio as C, CommentPubsubMessageWithFlexibleAuthorRefinementSchema as Cn, require_supports_color as Cr, findStartedCommunity as Ct, deepMergeRuntimeFields as D, CommentUpdateForChallengeVerificationSignedPropertyNames as Dn, array as Dr, listUpdatingComments as Dt, createAbortError as E, CommentUpdateForChallengeVerificationSchema as En, _enum as Er, listStartedCommunities as Et, getIpnsRecordInLocalKuboNode as F, ModQueuePageIpfsSchema as Fn, ZodError as Fr, untrackStartedCommunity as Ft, isLinkOfAudio as G, AuthorCommentIpfsReservedFields as Gn, CreateCommunityEditPublicationOptionsWithRefinementSchema as Gt, isIpns as H, CommentEditsTableRowSchema as Hn, CommunityEditPublicationPubsubReservedFields as Ht, getPostUpdateTimestampRange as I, PageIpfsSchema as In, joinValues as Ir, untrackUpdatingComment as It, isLinkOfVideo as J, CidPathSchema as Jn, CommentModerationReservedFields as Jt, isLinkOfImage as K, AuthorReservedFields as Kn, CommentModerationChallengeRequestToEncryptSchema as Kt, hideClassPrivateProps as L, CommentEditChallengeRequestToEncryptSchema as Ln, parsedType as Lr, untrackUpdatingCommunity as Lt, genToArray as M, CommentsTableRowSchema as Mn, object as Mr, trackStartedCommunity as Mt, getEquivalentCommunityAddresses as N, CreateCommentOptionsWithRefinementSchema as Nn, record as Nr, trackUpdatingComment as Nt, derivePublicationFromChallengeRequest as O, CommentUpdateReservedFields as On, boolean as Or, listUpdatingCommunities as Ot, getErrorCodeFromMessage as P, GetPageParamSchema as Pn, string as Pr, trackUpdatingCommunity as Pt, isStringDomain as Q, CreateSignerSchema as Qn, ChallengeFileFactorySchema as Qt, ipnsNameToIpnsOverPubsubTopic as R, CommentEditPubsubMessagePublicationSchema as Rn, stringifyPrimitive as Rr, require_sha256 as Rt, calculateStringSizeSameAsIpfsAddCidV0 as S, CommentPubsubMessageReservedFields as Sn, logger_default as Sr, findCommunityInRegistry as St, contentContainsMarkdownVideos as T, CommentUpdateChallengeReservedFieldNames as Tn, setErrorMap as Tr, findUpdatingCommunity as Tt, isIpnsPath as U, CreateCommentEditOptionsWithRefinementSchema as Un, CommunityEditPublicationSignedPropertyNames as Ut, isIpfsPath as V, CommentEditSignedPropertyNames as Vn, CommunityEditPublicationChallengeRequestToEncryptSchema as Vt, isLinkOfAnimatedImage as W, AuthorAddressSchema as Wn, CommunityEditPubsubMessagePublicationSchema as Wt, isRequestPubsubPublicationOfPost as X, CommunityAddressSchema as Xn, CommentModerationsTableRowSchema as Xt, isLinkValid as Y, CidStringSchema as Yn, CommentModerationSignedPropertyNames as Yt, isRequestPubsubPublicationOfReply as Z, CommunityAuthorChallengeReservedFieldNames as Zn, CreateCommentModerationOptionsWithRefinementSchema as Zt, PKCUserOptionBaseSchema as _, VoteSignedPropertyNames as _n, FailedToFetchCommunityFromGatewaysError as _r, statMfsPathSafely as _t, ChallengeRequestMessageSchema as a, CommunityIpfsSchema as an, e$2 as ar, removeMfsFilesSafely as at, areEquivalentCommunityAddresses as b, CommentIpfsReservedFields as bn, PKCError as br, waitForUpdateInCommunityInstanceWithErrorAndTimeout as bt, ChallengeVerificationMessageSignedPropertyNames as c, CreateRemoteCommunityFunctionArgumentSchema as cn, t$5 as cr, removeUndefinedValuesRecursively as ct, DecryptedChallengeRequestSchema as d, PubsubTopicSchema as dn, t$7 as dr, retryKuboBlockPutPinAndProvidePubsubTopic as dt, CommunityAnchorSchema as en, t$1 as er, pubsubTopicToDhtKeyCid as et, DecryptedChallengeSchema as f, RpcRemoteCommunityUpdateEventResultSchema as fn, t$8 as fr, retryKuboIpfsAdd as ft, PKCParsedOptionsSchema as g, VotePubsubReservedFields as gn, FailedToFetchCommentUpdateFromGatewaysError as gr, sleepUntilTimeoutOrAbort as gt, NameResolverSerializedSchema as h, VotePubsubMessagePublicationSchema as hn, FailedToFetchCommentIpfsFromGatewaysError as hr, shortifyCid as ht, ChallengeMessageSignedPropertyNames as i, CommunityIpfsReservedFields as in, e as ir, removeBlocksFromKuboNode as it, fetchAndValidateIpnsRecordFromGateway as j, CommentUpdateTableRowSchema as jn, number as jr, syncCommunityRegistryEntry as jt, doesDomainAddressHaveCapitalLetter as k, CommentUpdateSchema as kn, custom as kr, refreshTrackedCommentAliases as kt, DecryptedChallengeAnswerSchema as l, CreateRpcCommunityFunctionArgumentSchema as ln, n$7 as lr, replaceXWithY as lt, NameResolveCacheOptionsSchema as m, VoteChallengeRequestToEncryptSchema as mn, require_retry as mr, shortifyAddress as mt, ChallengeAnswerMessageSignedPropertyNames as n, CommunityEditOptionsSchema as nn, t$2 as nr, rejectWhenAbortSignalFires as nt, ChallengeRequestMessageSignedPropertyNames as o, CommunitySignedPropertyNames as on, t$4 as or, removeNullUndefinedEmptyObjectsValuesRecursively as ot, DecryptedChallengeVerificationSchema as p, CreateVoteUserOptionsWithRefinementSchema as pn, e$4 as pr, retryKuboIpfsAddAndProvide as pt, isLinkOfMedia as q, ChallengeAnswersSchema as qn, CommentModerationPubsubMessagePublicationSchema as qt, ChallengeMessageSchema as r, CommunityExportRecordsSchema as rn, t$3 as rr, rejectWhenCommunityStopsOrAborts as rt, ChallengeVerificationMessageSchema as s, CreateNewLocalCommunityUserOptionsSchema as sn, r$2 as sr, removeNullUndefinedValues as st, ChallengeAnswerMessageSchema as t, CommunityChallengeSettingSchema as tn, n$3 as tr, raceAgainstAbort as tt, DecryptedChallengeRequestPublicationSchema as u, ExportCommunityModLogsOptionsSchema as un, r$4 as ur, resolveWhenPredicateIsTrue as ut, PKCUserOptionsSchema as v, VoteTablesRowSchema as vn, FailedToFetchGenericIpfsFromGatewaysError as vr, throwIfAbortSignalAborted as vt, contentContainsMarkdownImages as w, CommentSignedPropertyNames as wn, require_ms as wr, findUpdatingComment as wt, calculateIpfsCidV0 as x, CommentIpfsSchema as xn, messages as xr, writeKuboFilesWithTimeout as xt, version_default as y, CommentChallengeRequestToEncryptSchema as yn, FailedToFetchPageIpfsFromGatewaysError as yr, timestamp as yt, isAbortError as z, CommentEditPubsubMessagePublicationWithFlexibleAuthorSchema as zn, TimeoutError as zt };
16380
+ export { isRequestPubsubPublicationOfReply as $, CommunityAuthorChallengeReservedFieldNames as $n, CreateCommentModerationOptionsWithRefinementSchema as $t, doesDomainAddressHaveCapitalLetter as A, CommentUpdateReservedFields as An, boolean as Ar, listUpdatingCommunities as At, ipnsNameToIpnsOverPubsubTopic as B, CommentEditPubsubMessagePublicationSchema as Bn, stringifyPrimitive as Br, require_sha256 as Bt, calculateStringSizeSameAsIpfsAddCidV0 as C, CommentIpfsSchema as Cn, messages as Cr, writeKuboFilesWithTimeout as Ct, createAbortError as D, CommentUpdateChallengeReservedFieldNames as Dn, setErrorMap as Dr, findUpdatingCommunity as Dt, contentContainsMarkdownVideos as E, CommentSignedPropertyNames as En, require_ms as Er, findUpdatingComment as Et, getErrorCodeFromMessage as F, CreateCommentOptionsWithRefinementSchema as Fn, record as Fr, trackUpdatingComment as Ft, isIpnsPath as G, CreateCommentEditOptionsWithRefinementSchema as Gn, CommunityEditPublicationSignedPropertyNames as Gt, isIpfsCid as H, CommentEditReservedFields as Hn, pTimeout as Ht, getIpnsRecordInLocalKuboNode as I, GetPageParamSchema as In, string as Ir, trackUpdatingCommunity as It, isLinkOfImage as J, AuthorReservedFields as Jn, CommentModerationChallengeRequestToEncryptSchema as Jt, isLinkOfAnimatedImage as K, AuthorAddressSchema as Kn, CommunityEditPubsubMessagePublicationSchema as Kt, getPostUpdateTimestampRange as L, ModQueuePageIpfsSchema as Ln, ZodError as Lr, untrackStartedCommunity as Lt, fetchAndValidateIpnsRecordFromGateway as M, CommentUpdateSignedPropertyNames as Mn, literal as Mr, refreshTrackedCommunityAliases as Mt, genToArray as N, CommentUpdateTableRowSchema as Nn, number as Nr, syncCommunityRegistryEntry as Nt, deepMergeRuntimeFields as O, CommentUpdateForChallengeVerificationSchema as On, _enum as Or, listStartedCommunities as Ot, getEquivalentCommunityAddresses as P, CommentsTableRowSchema as Pn, object as Pr, trackStartedCommunity as Pt, isRequestPubsubPublicationOfPost as Q, CommunityAddressSchema as Qn, CommentModerationsTableRowSchema as Qt, hideClassPrivateProps as R, PageIpfsSchema as Rn, joinValues as Rr, untrackUpdatingComment as Rt, calculateIpfsCidV0 as S, CommentIpfsReservedFields as Sn, PKCError as Sr, waitForUpdateInCommunityInstanceWithErrorAndTimeout as St, contentContainsMarkdownImages as T, CommentPubsubMessageWithFlexibleAuthorRefinementSchema as Tn, require_supports_color as Tr, findStartedCommunity as Tt, isIpfsPath as U, CommentEditSignedPropertyNames as Un, CommunityEditPublicationChallengeRequestToEncryptSchema as Ut, isAbortError as V, CommentEditPubsubMessagePublicationWithFlexibleAuthorSchema as Vn, TimeoutError as Vt, isIpns as W, CommentEditsTableRowSchema as Wn, CommunityEditPublicationPubsubReservedFields as Wt, isLinkOfVideo as X, CidPathSchema as Xn, CommentModerationReservedFields as Xt, isLinkOfMedia as Y, ChallengeAnswersSchema as Yn, CommentModerationPubsubMessagePublicationSchema as Yt, isLinkValid as Z, CidStringSchema as Zn, CommentModerationSignedPropertyNames as Zt, PKCUserOptionBaseSchema as _, VotePubsubMessagePublicationSchema as _n, FailedToFetchCommentIpfsFromGatewaysError as _r, shortifyCid as _t, ChallengeRequestMessageSchema as a, CommunityExportRecordsSchema as an, t$3 as ar, rejectWhenCommunityStopsOrAborts as at, areEquivalentCommunityAddresses as b, VoteTablesRowSchema as bn, FailedToFetchGenericIpfsFromGatewaysError as br, throwIfAbortSignalAborted as bt, ChallengeVerificationMessageSignedPropertyNames as c, CommunitySignedPropertyNames as cn, t$4 as cr, removeNullUndefinedEmptyObjectsValuesRecursively as ct, DecryptedChallengeRequestSchema as d, CreateRpcCommunityFunctionArgumentSchema as dn, n$7 as dr, replaceXWithY as dt, ChallengeFileFactorySchema as en, CreateSignerSchema as er, isStringDomain as et, DecryptedChallengeSchema as f, ExportCommunityModLogsOptionsSchema as fn, r$4 as fr, resolveWhenPredicateIsTrue as ft, PKCParsedOptionsSchema as g, VoteChallengeRequestToEncryptSchema as gn, require_retry as gr, shortifyAddress as gt, NameResolverSerializedSchema as h, CreateVoteUserOptionsWithRefinementSchema as hn, e$4 as hr, retryKuboIpfsAddAndProvide as ht, ChallengeMessageSignedPropertyNames as i, CommunityEditOptionsSchema as in, t$2 as ir, rejectWhenAbortSignalFires as it, extractNetworkErrorDetails as j, CommentUpdateSchema as jn, custom as jr, refreshTrackedCommentAliases as jt, derivePublicationFromChallengeRequest as k, CommentUpdateForChallengeVerificationSignedPropertyNames as kn, array as kr, listUpdatingComments as kt, DecryptedChallengeAnswerSchema as l, CreateNewLocalCommunityUserOptionsSchema as ln, r$2 as lr, removeNullUndefinedValues as lt, NameResolveCacheOptionsSchema as m, RpcRemoteCommunityUpdateEventResultSchema as mn, t$8 as mr, retryKuboIpfsAdd as mt, ChallengeAnswerMessageSignedPropertyNames as n, CommunityAnchorSchema as nn, t$1 as nr, pubsubTopicToDhtKeyCid as nt, ChallengeRequestMessageSignedPropertyNames as o, CommunityIpfsReservedFields as on, e as or, removeBlocksFromKuboNode as ot, DecryptedChallengeVerificationSchema as p, PubsubTopicSchema as pn, t$7 as pr, retryKuboBlockPutPinAndProvidePubsubTopic as pt, isLinkOfAudio as q, AuthorCommentIpfsReservedFields as qn, CreateCommunityEditPublicationOptionsWithRefinementSchema as qt, ChallengeMessageSchema as r, CommunityChallengeSettingSchema as rn, n$3 as rr, raceAgainstAbort as rt, ChallengeVerificationMessageSchema as s, CommunityIpfsSchema as sn, e$2 as sr, removeMfsFilesSafely as st, ChallengeAnswerMessageSchema as t, ChallengeFileSchema as tn, n as tr, pubsubTopicToDhtKey as tt, DecryptedChallengeRequestPublicationSchema as u, CreateRemoteCommunityFunctionArgumentSchema as un, t$5 as ur, removeUndefinedValuesRecursively as ut, PKCUserOptionsSchema as v, VotePubsubReservedFields as vn, FailedToFetchCommentUpdateFromGatewaysError as vr, sleepUntilTimeoutOrAbort as vt, contentContainsMarkdownAudio as w, CommentPubsubMessageReservedFields as wn, logger_default as wr, findCommunityInRegistry as wt, binaryKeyToPubsubTopic as x, CommentChallengeRequestToEncryptSchema as xn, FailedToFetchPageIpfsFromGatewaysError as xr, timestamp as xt, version_default as y, VoteSignedPropertyNames as yn, FailedToFetchCommunityFromGatewaysError as yr, statMfsPathSafely as yt, interruptibleSleep as z, CommentEditChallengeRequestToEncryptSchema as zn, parsedType as zr, untrackUpdatingCommunity as zt };
@@ -1,4 +1,4 @@
1
- import { br as PKCError, et as pubsubTopicToDhtKeyCid } from "./schema-HH2zeH-j.js";
1
+ import { Sr as PKCError, nt as pubsubTopicToDhtKeyCid } from "./schema-5-rYJ-bC.js";
2
2
  import { ipnsSelector } from "ipns/selector";
3
3
  import { ipnsValidator } from "ipns/validator";
4
4
  import { unmarshalIPNSRecord } from "ipns";
@@ -476,6 +476,14 @@ async function cacheIpnsRecordInPubsubLocalStore({ localStore, routingKey, marsh
476
476
  await localStore.put(routingKey, marshalledRecord);
477
477
  }
478
478
  const DEFAULT_CACHED_IPNS_RECORD_TTL_MS = 6e4;
479
+ function ipnsCacheTtlJitterFactor(routingKey) {
480
+ let hash = 2166136261;
481
+ for (let i = 0; i < routingKey.length; i++) {
482
+ hash ^= routingKey[i];
483
+ hash = Math.imul(hash, 16777619) >>> 0;
484
+ }
485
+ return .75 + hash / 4294967296 * .25;
486
+ }
479
487
  async function readFreshCachedIpnsRecordFromPubsubLocalStore({ localStore, routingKey, lastNetworkValidatedAtMs }) {
480
488
  if (!await localStore.has(routingKey)) return void 0;
481
489
  const { record: recordBytes, created } = await localStore.get(routingKey);
@@ -485,9 +493,9 @@ async function readFreshCachedIpnsRecordFromPubsubLocalStore({ localStore, routi
485
493
  return;
486
494
  }
487
495
  const record = unmarshalIPNSRecord(recordBytes);
488
- const ttlMs = record.ttl !== void 0 ? Number(record.ttl / 1000000n) : DEFAULT_CACHED_IPNS_RECORD_TTL_MS;
496
+ const effectiveTtlMs = (record.ttl !== void 0 ? Number(record.ttl / 1000000n) : DEFAULT_CACHED_IPNS_RECORD_TTL_MS) * ipnsCacheTtlJitterFactor(routingKey);
489
497
  const lastConfirmedCurrentAtMs = Math.max(created.getTime(), lastNetworkValidatedAtMs ?? 0);
490
- if (Date.now() - lastConfirmedCurrentAtMs >= ttlMs) return void 0;
498
+ if (Date.now() - lastConfirmedCurrentAtMs >= effectiveTtlMs) return void 0;
491
499
  return record;
492
500
  }
493
501
  //#endregion
@@ -1,2 +1,2 @@
1
- import { a as getShortCid, i as getShortAddress, n as challenges, o as nativeFunctions, r as createAnchorIpnsRecord, s as setNativeFunctions, t as PKC } from "./chunks/node-BrLiC0qX.js";
1
+ import { a as getShortCid, i as getShortAddress, n as challenges, o as nativeFunctions, r as createAnchorIpnsRecord, s as setNativeFunctions, t as PKC } from "./chunks/node-C37nDOa8.js";
2
2
  export { challenges, createAnchorIpnsRecord, PKC as default, getShortAddress, getShortCid, nativeFunctions, setNativeFunctions };
@@ -1,7 +1,7 @@
1
- import { Ct as findStartedCommunity, L as hideClassPrivateProps, Sr as logger_default, br as PKCError, lt as replaceXWithY, rr as t, tr as n } from "../../chunks/schema-HH2zeH-j.js";
2
- import { _ as parseRpcPublishAnchorRecordParam, c as parseRpcAuthorNameParam, d as parseRpcCommentRepliesPageParam, f as parseRpcCommunityIdentifierParam, g as parseRpcExportCommunityParam, h as parseRpcExportCommunityModLogsParam, l as parseRpcCancelExportParam, m as parseRpcEditCommunityParam, p as parseRpcCommunityPageParam, t as PKC, u as parseRpcCidParam, v as parseRpcPublishChallengeAnswersParam, y as parseRpcUnsubscribeParam } from "../../chunks/node-BrLiC0qX.js";
3
- import { An as parseSetNewSettingsPKCWsServerSchemaWithPKCErrorIfItFails, Cn as parseDecryptedChallengeAnswerWithPKCErrorIfItFails, J as buildPagesRuntimeFields, ct as pRetry, dn as parseCommunityEditOptionsSchemaWithPKCErrorIfItFails, dt as require_lib, jn as parseVoteChallengeRequestToEncryptSchemaWithPKCErrorIfItFails, lt as pLimit, nn as parseCommentChallengeRequestToEncryptSchemaWithPKCErrorIfItFails, on as parseCommentModerationChallengeRequestToEncryptSchemaWithPKCErrorIfItFails, q as buildPageRuntimeFields, rn as parseCommentEditChallengeRequestToEncryptSchemaWithPKCErrorIfItFails, rr as t$1, rt as extractCrosspostRuntimeFields, un as parseCommunityEditChallengeRequestToEncryptSchemaWithPKCErrorIfItFails, ur as stringify, vn as parseCreateNewLocalCommunityUserOptionsSchemaWithPKCErrorIfItFails, yn as parseCreatePKCWsServerOptionsSchemaWithPKCErrorIfItFails } from "../../chunks/rpc-local-community-DOSee621.js";
4
- import { t as LocalCommunity } from "../../chunks/local-community-DgbMuVAA.js";
1
+ import { Ht as pTimeout, R as hideClassPrivateProps, Sr as PKCError, Tt as findStartedCommunity, ar as t, dt as replaceXWithY, rr as n, wr as logger_default } from "../../chunks/schema-5-rYJ-bC.js";
2
+ import { _ as parseRpcPublishAnchorRecordParam, c as parseRpcAuthorNameParam, d as parseRpcCommentRepliesPageParam, f as parseRpcCommunityIdentifierParam, g as parseRpcExportCommunityParam, h as parseRpcExportCommunityModLogsParam, l as parseRpcCancelExportParam, m as parseRpcEditCommunityParam, p as parseRpcCommunityPageParam, t as PKC, u as parseRpcCidParam, v as parseRpcPublishChallengeAnswersParam, y as parseRpcUnsubscribeParam } from "../../chunks/node-C37nDOa8.js";
3
+ import { An as parseSetNewSettingsPKCWsServerSchemaWithPKCErrorIfItFails, Cn as parseDecryptedChallengeAnswerWithPKCErrorIfItFails, J as buildPagesRuntimeFields, ct as pRetry, dn as parseCommunityEditOptionsSchemaWithPKCErrorIfItFails, dt as require_lib, jn as parseVoteChallengeRequestToEncryptSchemaWithPKCErrorIfItFails, lt as pLimit, nn as parseCommentChallengeRequestToEncryptSchemaWithPKCErrorIfItFails, on as parseCommentModerationChallengeRequestToEncryptSchemaWithPKCErrorIfItFails, q as buildPageRuntimeFields, rn as parseCommentEditChallengeRequestToEncryptSchemaWithPKCErrorIfItFails, rr as t$1, rt as extractCrosspostRuntimeFields, un as parseCommunityEditChallengeRequestToEncryptSchemaWithPKCErrorIfItFails, ur as stringify, vn as parseCreateNewLocalCommunityUserOptionsSchemaWithPKCErrorIfItFails, yn as parseCreatePKCWsServerOptionsSchemaWithPKCErrorIfItFails } from "../../chunks/rpc-local-community-Dr_-Lb8I.js";
4
+ import { t as LocalCommunity } from "../../chunks/local-community-Ce7303vY.js";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import path from "path";
7
7
  import assert from "assert";
@@ -103,6 +103,7 @@ function sanitizeRpcNotificationResult(event, result) {
103
103
  //#endregion
104
104
  //#region dist/node/rpc/src/index.js
105
105
  const log = logger_default("pkc-js-rpc:pkc-ws-server");
106
+ const DESTROY_CLIENTS_CLOSE_TIMEOUT_MS = 5e3;
106
107
  const AUTO_START_TRANSIENT_RETRIES = 8;
107
108
  const _isTransientKuboError = (error) => {
108
109
  const markers = [
@@ -138,6 +139,7 @@ var PKCWsServer = class extends import_lib.TypedEmitter {
138
139
  this._autoStartOnBoot = false;
139
140
  this._exportCommunityInstances = /* @__PURE__ */ new Map();
140
141
  this._ownsHttpServer = false;
142
+ this._pendingDisconnectionCleanups = /* @__PURE__ */ new Set();
141
143
  const log = logger_default("pkc-js:PKCWsServer");
142
144
  this.authKey = authKey;
143
145
  this._autoStartOnBoot = startStartedCommunitiesOnStartup ?? true;
@@ -185,24 +187,14 @@ var PKCWsServer = class extends import_lib.TypedEmitter {
185
187
  this._onSettingsChange[ws._id] = {};
186
188
  log("Established connection with new RPC client", ws._id);
187
189
  });
188
- this.rpcWebsockets.on("disconnection", async (ws) => {
189
- log("RPC client disconnected", ws._id, "number of rpc clients connected", this.rpcWebsockets.wss.clients.size);
190
- const subscriptionCleanups = this.subscriptionCleanups[ws._id];
191
- if (!subscriptionCleanups) {
192
- delete this.subscriptionCleanups[ws._id];
193
- delete this.connections[ws._id];
194
- delete this._onSettingsChange[ws._id];
195
- log("Disconnected from RPC client (no subscriptions to clean)", ws._id);
196
- return;
197
- }
198
- for (const subscriptionId in subscriptionCleanups) {
199
- await subscriptionCleanups[subscriptionId]();
200
- delete subscriptionCleanups[subscriptionId];
201
- }
202
- delete this.subscriptionCleanups[ws._id];
203
- delete this.connections[ws._id];
204
- delete this._onSettingsChange[ws._id];
205
- log("Disconnected from RPC client", ws._id);
190
+ this.rpcWebsockets.on("disconnection", (ws) => {
191
+ const cleanup = this._cleanUpDisconnectedClient(ws._id);
192
+ this._pendingDisconnectionCleanups.add(cleanup);
193
+ const untrack = () => this._pendingDisconnectionCleanups.delete(cleanup);
194
+ cleanup.then(untrack, (e) => {
195
+ log.error("Failed to clean up after RPC client disconnected", ws._id, e);
196
+ untrack();
197
+ });
206
198
  });
207
199
  this.rpcWebsocketsRegister("getComment", this.getComment.bind(this));
208
200
  this.rpcWebsocketsRegister("getCommunityPage", this.getCommunityPage.bind(this));
@@ -1520,9 +1512,38 @@ var PKCWsServer = class extends import_lib.TypedEmitter {
1520
1512
  delete connectionCleanups[subscriptionId];
1521
1513
  return { success: true };
1522
1514
  }
1515
+ async _cleanUpDisconnectedClient(connectionId) {
1516
+ log("RPC client disconnected", connectionId, "number of rpc clients connected", this.rpcWebsockets.wss.clients.size);
1517
+ const subscriptionCleanups = this.subscriptionCleanups[connectionId];
1518
+ if (!subscriptionCleanups) {
1519
+ delete this.subscriptionCleanups[connectionId];
1520
+ delete this.connections[connectionId];
1521
+ delete this._onSettingsChange[connectionId];
1522
+ log("Disconnected from RPC client (no subscriptions to clean)", connectionId);
1523
+ return;
1524
+ }
1525
+ for (const subscriptionId in subscriptionCleanups) {
1526
+ await subscriptionCleanups[subscriptionId]();
1527
+ delete subscriptionCleanups[subscriptionId];
1528
+ }
1529
+ delete this.subscriptionCleanups[connectionId];
1530
+ delete this.connections[connectionId];
1531
+ delete this._onSettingsChange[connectionId];
1532
+ log("Disconnected from RPC client", connectionId);
1533
+ }
1523
1534
  async destroy() {
1524
1535
  for (const connectionId of t(this.subscriptionCleanups)) for (const subscriptionId of t(this.subscriptionCleanups[connectionId])) await this.unsubscribe([{ subscriptionId: Number(subscriptionId) }], connectionId);
1536
+ const wssClosed = new Promise((resolve) => this.ws.once("close", () => resolve()));
1525
1537
  this.ws.close();
1538
+ for (const client of this.ws.clients) client.close(1e3, "PKCWsServer is shutting down");
1539
+ try {
1540
+ await pTimeout(wssClosed, { milliseconds: DESTROY_CLIENTS_CLOSE_TIMEOUT_MS });
1541
+ } catch {
1542
+ log.error("Some RPC clients did not complete the close handshake within", DESTROY_CLIENTS_CLOSE_TIMEOUT_MS, "ms of destroy(), terminating them");
1543
+ for (const client of this.ws.clients) client.terminate();
1544
+ await wssClosed;
1545
+ }
1546
+ await Promise.allSettled(this._pendingDisconnectionCleanups);
1526
1547
  if (this._ownsHttpServer && this._httpServer) await new Promise((r) => this._httpServer.close(() => r()));
1527
1548
  await (await this._getPKCInstance()).destroy();
1528
1549
  for (const communityAddress of t(this._startedCommunities)) delete this._startedCommunities[communityAddress];
@@ -96,6 +96,7 @@ export declare class BaseClientsManager {
96
96
  resolveIpnsToCidP2P(ipnsName: string, loadOpts: {
97
97
  timeoutMs: number;
98
98
  abortSignal?: AbortSignal;
99
+ nocache?: boolean;
99
100
  }): Promise<{
100
101
  cid: string;
101
102
  ipnsHops: string[];
@@ -469,7 +469,13 @@ export class BaseClientsManager {
469
469
  // chain of IPNS names traversed: ipnsHops[0] is the anchor (the name we were asked to
470
470
  // resolve) and ipnsHops.at(-1) is the terminal name (the name whose record points
471
471
  // directly at the /ipfs/ CID, i.e. the key that signs the content).
472
- async resolveIpnsToCidP2P(ipnsName, loadOpts) {
472
+ async resolveIpnsToCidP2P(ipnsName,
473
+ // `nocache: true` forces a network revalidation even on the libp2p-js resolver (whose
474
+ // default below is to let its gossip-fed routing-layer cache serve, issue #301). The
475
+ // community update loop sets it on safety-net ticks, which exist precisely for pushed
476
+ // records the cache never received. It is spread AFTER the per-client default, so the
477
+ // caller's value wins.
478
+ loadOpts) {
473
479
  const log = Logger("pkc-js:clients-manager:resolveIpnsToCidP2P");
474
480
  throwIfAbortSignalAborted(loadOpts.abortSignal);
475
481
  // recursive: false so the resolver returns the IMMEDIATE value of each record (so we can