@pkcprotocol/pkc-js 0.0.124 → 0.0.125
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/README.md +54 -54
- package/dist/browser/clients/rpc-client/pkc-rpc-client.d.ts +3 -1
- package/dist/browser/clients/rpc-client/pkc-rpc-client.js +18 -3
- package/dist/browser/clients/rpc-client/pkc-rpc-client.js.map +1 -1
- package/dist/browser/clients/rpc-client/rpc-schema-util.d.ts +16 -0
- package/dist/browser/clients/rpc-client/rpc-schema-util.js +6 -1
- package/dist/browser/clients/rpc-client/rpc-schema-util.js.map +1 -1
- package/dist/browser/clients/rpc-client/schema.d.ts +12 -0
- package/dist/browser/clients/rpc-client/schema.js +9 -0
- package/dist/browser/clients/rpc-client/schema.js.map +1 -1
- package/dist/browser/clients/rpc-client/types.d.ts +5 -1
- package/dist/browser/community-list/community-list.d.ts +143 -0
- package/dist/browser/community-list/community-list.js +401 -0
- package/dist/browser/community-list/community-list.js.map +1 -0
- package/dist/browser/community-list/schema.d.ts +239 -0
- package/dist/browser/community-list/schema.js +95 -0
- package/dist/browser/community-list/schema.js.map +1 -0
- package/dist/browser/community-list/types.d.ts +19 -0
- package/dist/browser/community-list/types.js +2 -0
- package/dist/browser/community-list/types.js.map +1 -0
- package/dist/browser/errors.d.ts +18 -1
- package/dist/browser/errors.js +18 -0
- package/dist/browser/errors.js.map +1 -1
- package/dist/browser/generated-version.d.ts +1 -1
- package/dist/browser/generated-version.js +1 -1
- package/dist/browser/index.d.ts +2 -0
- package/dist/browser/pkc/pkc-client-manager.d.ts +4 -1
- package/dist/browser/pkc/pkc-client-manager.js +6 -4
- package/dist/browser/pkc/pkc-client-manager.js.map +1 -1
- package/dist/browser/pkc/pkc.d.ts +7 -0
- package/dist/browser/pkc/pkc.js +93 -0
- package/dist/browser/pkc/pkc.js.map +1 -1
- package/dist/browser/pkc-error.d.ts +1 -1
- package/dist/browser/rpc/src/index.d.ts +3 -1
- package/dist/browser/rpc/src/index.js +45 -3
- package/dist/browser/rpc/src/index.js.map +1 -1
- package/dist/browser/schema/schema-util.d.ts +3 -0
- package/dist/browser/schema/schema-util.js +10 -0
- package/dist/browser/schema/schema-util.js.map +1 -1
- package/dist/browser/signer/signatures.d.ts +9 -0
- package/dist/browser/signer/signatures.js +30 -1
- package/dist/browser/signer/signatures.js.map +1 -1
- package/dist/bundled/bundle-manifest.json +54 -50
- package/dist/bundled/challenges.js +1 -1
- package/dist/bundled/chunks/{helia-for-pkc-DfpR6JSl.js → helia-for-pkc-DXygdFt-.js} +33 -33
- package/dist/bundled/chunks/{local-community-CQ9M4cEY.js → local-community-Bbqx5IaD.js} +1 -1
- package/dist/bundled/chunks/{local-community-Ll4pUOKV.js → local-community-D4I0gLqX.js} +31 -31
- package/dist/bundled/chunks/{node-BWOsSCO-.js → node-oqffR7Bn.js} +423 -109
- package/dist/bundled/chunks/{page-sort-scoring-Y3zgv-l4.js → page-sort-scoring-CK4vshII.js} +1 -1
- package/dist/bundled/chunks/{rpc-local-community-D8wgBsuD.js → rpc-local-community-UpO9cs7k.js} +2251 -841
- package/dist/bundled/chunks/{util-IESnqTnj.js → util-D3vx4Na0.js} +1 -1
- package/dist/bundled/chunks/{util-Bd4vp_w6.js → util-nmnnrzbz.js} +2703 -988
- package/dist/bundled/chunks/{validate-package-factories-D527vDd_.js → validate-package-factories-DkJmLpRe.js} +2 -2
- package/dist/bundled/index.js +1 -1
- package/dist/bundled/page-sorts.js +1 -1
- package/dist/bundled/rpc/src/index.js +31 -4
- package/dist/node/clients/rpc-client/pkc-rpc-client.d.ts +3 -1
- package/dist/node/clients/rpc-client/pkc-rpc-client.js +18 -3
- package/dist/node/clients/rpc-client/pkc-rpc-client.js.map +1 -1
- package/dist/node/clients/rpc-client/rpc-schema-util.d.ts +16 -0
- package/dist/node/clients/rpc-client/rpc-schema-util.js +6 -1
- package/dist/node/clients/rpc-client/rpc-schema-util.js.map +1 -1
- package/dist/node/clients/rpc-client/schema.d.ts +12 -0
- package/dist/node/clients/rpc-client/schema.js +9 -0
- package/dist/node/clients/rpc-client/schema.js.map +1 -1
- package/dist/node/clients/rpc-client/types.d.ts +5 -1
- package/dist/node/community-list/community-list.d.ts +143 -0
- package/dist/node/community-list/community-list.js +401 -0
- package/dist/node/community-list/community-list.js.map +1 -0
- package/dist/node/community-list/schema.d.ts +239 -0
- package/dist/node/community-list/schema.js +95 -0
- package/dist/node/community-list/schema.js.map +1 -0
- package/dist/node/community-list/types.d.ts +19 -0
- package/dist/node/community-list/types.js +2 -0
- package/dist/node/community-list/types.js.map +1 -0
- package/dist/node/errors.d.ts +18 -1
- package/dist/node/errors.js +18 -0
- package/dist/node/errors.js.map +1 -1
- package/dist/node/generated-version.d.ts +1 -1
- package/dist/node/generated-version.js +1 -1
- package/dist/node/index.d.ts +2 -0
- package/dist/node/pkc/pkc-client-manager.d.ts +4 -1
- package/dist/node/pkc/pkc-client-manager.js +6 -4
- package/dist/node/pkc/pkc-client-manager.js.map +1 -1
- package/dist/node/pkc/pkc.d.ts +7 -0
- package/dist/node/pkc/pkc.js +93 -0
- package/dist/node/pkc/pkc.js.map +1 -1
- package/dist/node/pkc-error.d.ts +1 -1
- package/dist/node/rpc/src/index.d.ts +3 -1
- package/dist/node/rpc/src/index.js +45 -3
- package/dist/node/rpc/src/index.js.map +1 -1
- package/dist/node/schema/schema-util.d.ts +3 -0
- package/dist/node/schema/schema-util.js +10 -0
- package/dist/node/schema/schema-util.js.map +1 -1
- package/dist/node/signer/signatures.d.ts +9 -0
- package/dist/node/signer/signatures.js +30 -1
- package/dist/node/signer/signatures.js.map +1 -1
- package/package.json +6 -6
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { TypedEmitter } from "tiny-typed-emitter";
|
|
2
|
+
import type { PKC } from "../pkc/pkc.js";
|
|
3
|
+
import type { SignerWithPublicKeyAddress } from "../signer/index.js";
|
|
4
|
+
import type { CommunityListEntryJson, CommunityListEvents, CommunityListIpfsType, CommunityListState } from "./types.js";
|
|
5
|
+
import type { AuthorPubsubJsonType } from "../types.js";
|
|
6
|
+
import type { JsonSignature } from "../signer/types.js";
|
|
7
|
+
type UnsignedCommunityListProps = Omit<CommunityListIpfsType, "signature">;
|
|
8
|
+
export declare class CommunityList extends TypedEmitter<CommunityListEvents> {
|
|
9
|
+
title?: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
author?: AuthorPubsubJsonType & {
|
|
12
|
+
nameResolved?: boolean;
|
|
13
|
+
};
|
|
14
|
+
communities?: CommunityListEntryJson[];
|
|
15
|
+
timestamp?: number;
|
|
16
|
+
protocolVersion?: string;
|
|
17
|
+
signature?: JsonSignature;
|
|
18
|
+
cid?: string;
|
|
19
|
+
shortCid?: string;
|
|
20
|
+
signer?: SignerWithPublicKeyAddress;
|
|
21
|
+
state: CommunityListState;
|
|
22
|
+
raw: {
|
|
23
|
+
communityList?: CommunityListIpfsType;
|
|
24
|
+
};
|
|
25
|
+
_pkc: PKC;
|
|
26
|
+
private _unsignedProps?;
|
|
27
|
+
private _stopAbortController?;
|
|
28
|
+
private _loadingAbortController?;
|
|
29
|
+
private _loadingOperation?;
|
|
30
|
+
constructor(pkc: PKC);
|
|
31
|
+
_initWithCidOnly(cid: string): void;
|
|
32
|
+
_initUnsignedProps({ signer, ...props }: UnsignedCommunityListProps & {
|
|
33
|
+
signer: SignerWithPublicKeyAddress;
|
|
34
|
+
}): void;
|
|
35
|
+
private _buildRuntimeEntry;
|
|
36
|
+
private _buildRuntimeAuthor;
|
|
37
|
+
_initFromWireRecord(record: CommunityListIpfsType, cid: string): void;
|
|
38
|
+
private _setAuthorNameResolvedFromCache;
|
|
39
|
+
toJSON(): {
|
|
40
|
+
cid: string | undefined;
|
|
41
|
+
shortCid: string | undefined;
|
|
42
|
+
communities?: {
|
|
43
|
+
[x: string]: unknown;
|
|
44
|
+
publicKey: string;
|
|
45
|
+
name?: string | undefined;
|
|
46
|
+
title?: string | undefined;
|
|
47
|
+
description?: string | undefined;
|
|
48
|
+
languages?: string[] | undefined;
|
|
49
|
+
locations?: string[] | undefined;
|
|
50
|
+
features?: string[] | undefined;
|
|
51
|
+
tags?: string[] | undefined;
|
|
52
|
+
}[] | undefined;
|
|
53
|
+
author?: {
|
|
54
|
+
[x: string]: unknown;
|
|
55
|
+
name?: string | undefined;
|
|
56
|
+
previousCommentCid?: string | undefined;
|
|
57
|
+
displayName?: string | undefined;
|
|
58
|
+
wallets?: Record<string, {
|
|
59
|
+
address: string;
|
|
60
|
+
timestamp: number;
|
|
61
|
+
signature: {
|
|
62
|
+
signature: string;
|
|
63
|
+
type: string;
|
|
64
|
+
};
|
|
65
|
+
}> | undefined;
|
|
66
|
+
avatar?: {
|
|
67
|
+
[x: string]: unknown;
|
|
68
|
+
chainTicker: string;
|
|
69
|
+
address: string;
|
|
70
|
+
id: string;
|
|
71
|
+
timestamp: number;
|
|
72
|
+
signature: {
|
|
73
|
+
signature: string;
|
|
74
|
+
type: string;
|
|
75
|
+
};
|
|
76
|
+
} | undefined;
|
|
77
|
+
flairs?: {
|
|
78
|
+
[x: string]: unknown;
|
|
79
|
+
text: string;
|
|
80
|
+
backgroundColor?: string | undefined;
|
|
81
|
+
textColor?: string | undefined;
|
|
82
|
+
expiresAt?: number | undefined;
|
|
83
|
+
}[] | undefined;
|
|
84
|
+
} | ({
|
|
85
|
+
name?: string | undefined;
|
|
86
|
+
previousCommentCid?: string | undefined;
|
|
87
|
+
displayName?: string | undefined;
|
|
88
|
+
wallets?: Record<string, {
|
|
89
|
+
address: string;
|
|
90
|
+
timestamp: number;
|
|
91
|
+
signature: {
|
|
92
|
+
signature: string;
|
|
93
|
+
type: string;
|
|
94
|
+
};
|
|
95
|
+
}> | undefined;
|
|
96
|
+
avatar?: {
|
|
97
|
+
[x: string]: unknown;
|
|
98
|
+
chainTicker: string;
|
|
99
|
+
address: string;
|
|
100
|
+
id: string;
|
|
101
|
+
timestamp: number;
|
|
102
|
+
signature: {
|
|
103
|
+
signature: string;
|
|
104
|
+
type: string;
|
|
105
|
+
};
|
|
106
|
+
} | undefined;
|
|
107
|
+
flairs?: {
|
|
108
|
+
[x: string]: unknown;
|
|
109
|
+
text: string;
|
|
110
|
+
backgroundColor?: string | undefined;
|
|
111
|
+
textColor?: string | undefined;
|
|
112
|
+
expiresAt?: number | undefined;
|
|
113
|
+
}[] | undefined;
|
|
114
|
+
} & {
|
|
115
|
+
address: string;
|
|
116
|
+
publicKey: string;
|
|
117
|
+
} & {
|
|
118
|
+
shortAddress: string;
|
|
119
|
+
} & {
|
|
120
|
+
nameResolved?: boolean;
|
|
121
|
+
}) | undefined;
|
|
122
|
+
timestamp?: number | undefined;
|
|
123
|
+
protocolVersion?: string | undefined;
|
|
124
|
+
description?: string | undefined;
|
|
125
|
+
title?: string | undefined;
|
|
126
|
+
};
|
|
127
|
+
private _setState;
|
|
128
|
+
private _throwIfPublishAborted;
|
|
129
|
+
publish(): Promise<string>;
|
|
130
|
+
update(): Promise<void>;
|
|
131
|
+
private _runUpdateLoop;
|
|
132
|
+
private _isNonRetriableError;
|
|
133
|
+
_loadCommunityListIpfsWithRetries(outerSignal?: AbortSignal): Promise<void>;
|
|
134
|
+
private _fetchAndVerifyOnce;
|
|
135
|
+
private _authorDomainToSettle;
|
|
136
|
+
private _nameResolvedCacheKey;
|
|
137
|
+
private _resolveAuthorNameVerdictOnce;
|
|
138
|
+
_kickOffBackgroundAuthorNameResolution(): void;
|
|
139
|
+
private _settleAuthorNameResolvedIfNeeded;
|
|
140
|
+
private _delayWithAbort;
|
|
141
|
+
stop(): Promise<void>;
|
|
142
|
+
}
|
|
143
|
+
export {};
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
import { TypedEmitter } from "tiny-typed-emitter";
|
|
2
|
+
import retry from "retry";
|
|
3
|
+
import Logger from "../logger.js";
|
|
4
|
+
import { PKCError } from "../pkc-error.js";
|
|
5
|
+
import { cleanUpBeforePublishing, signCommunityList, verifyCommunityList } from "../signer/signatures.js";
|
|
6
|
+
import { getPKCAddressFromPublicKeySync } from "../signer/util.js";
|
|
7
|
+
import { buildRuntimeAuthor } from "../publications/publication-author.js";
|
|
8
|
+
import { calculateIpfsCidV0, calculateStringSizeSameAsIpfsAddCidV0, calculateStringSizeSameAsIpfsAddCidV0Sync, isStringDomain, retryKuboIpfsAddAndProvide, shortifyAddress, shortifyCid } from "../util.js";
|
|
9
|
+
import { parseCommunityListSchemaWithPKCErrorIfItFails, parseJsonWithPKCErrorIfFails } from "../schema/schema-util.js";
|
|
10
|
+
import { MAX_COMMUNITY_LIST_SIZE_BYTES } from "./schema.js";
|
|
11
|
+
import { sha256 } from "js-sha256";
|
|
12
|
+
// A CommunityList is an immutable, signed IPFS file addressed by CID. One class, no Remote split:
|
|
13
|
+
// constructed with a signer it can publish(), constructed with a cid it can update(). Spec:
|
|
14
|
+
// docs/protocol/community-lists.md
|
|
15
|
+
export class CommunityList extends TypedEmitter {
|
|
16
|
+
constructor(pkc) {
|
|
17
|
+
super();
|
|
18
|
+
this.state = "stopped";
|
|
19
|
+
this.raw = {};
|
|
20
|
+
this._pkc = pkc;
|
|
21
|
+
// The error listener initialized here must never be removed (see AGENTS.md on removeAllListeners)
|
|
22
|
+
this.on("error", (...args) => this.listenerCount("error") === 1 && this._pkc.emit("error", ...args)); // only bubble up to pkc if no other listeners are attached
|
|
23
|
+
}
|
|
24
|
+
_initWithCidOnly(cid) {
|
|
25
|
+
this.cid = cid;
|
|
26
|
+
this.shortCid = shortifyCid(cid);
|
|
27
|
+
}
|
|
28
|
+
_initUnsignedProps({ signer, ...props }) {
|
|
29
|
+
this.signer = signer;
|
|
30
|
+
this._unsignedProps = props;
|
|
31
|
+
this.title = props.title;
|
|
32
|
+
this.description = props.description;
|
|
33
|
+
this.timestamp = props.timestamp;
|
|
34
|
+
this.protocolVersion = props.protocolVersion;
|
|
35
|
+
this.communities = props.communities.map((entry) => this._buildRuntimeEntry(entry));
|
|
36
|
+
// author identity always comes from the signature; before publishing, the signer is who will sign
|
|
37
|
+
this.author = this._buildRuntimeAuthor(props.author, signer.publicKey);
|
|
38
|
+
}
|
|
39
|
+
_buildRuntimeEntry(entry) {
|
|
40
|
+
const address = entry.name || entry.publicKey;
|
|
41
|
+
return { ...entry, address, shortAddress: shortifyAddress(address) };
|
|
42
|
+
}
|
|
43
|
+
_buildRuntimeAuthor(wireAuthor, signaturePublicKey) {
|
|
44
|
+
const runtimeAuthor = buildRuntimeAuthor({ author: wireAuthor, signaturePublicKey });
|
|
45
|
+
return { ...runtimeAuthor, shortAddress: shortifyAddress(runtimeAuthor.address) };
|
|
46
|
+
}
|
|
47
|
+
_initFromWireRecord(record, cid) {
|
|
48
|
+
this.raw.communityList = record;
|
|
49
|
+
this.cid = cid;
|
|
50
|
+
this.shortCid = shortifyCid(cid);
|
|
51
|
+
this.title = record.title;
|
|
52
|
+
this.description = record.description;
|
|
53
|
+
this.timestamp = record.timestamp;
|
|
54
|
+
this.protocolVersion = record.protocolVersion;
|
|
55
|
+
this.signature = record.signature;
|
|
56
|
+
this.communities = record.communities.map((entry) => this._buildRuntimeEntry(entry));
|
|
57
|
+
const previousNameResolved = this.author?.nameResolved;
|
|
58
|
+
this.author = this._buildRuntimeAuthor(record.author, record.signature.publicKey);
|
|
59
|
+
if (typeof previousNameResolved === "boolean")
|
|
60
|
+
this.author.nameResolved = previousNameResolved;
|
|
61
|
+
else
|
|
62
|
+
this._setAuthorNameResolvedFromCache();
|
|
63
|
+
}
|
|
64
|
+
// Reading a cached verdict is free, so a one-shot load shows one like getComment does
|
|
65
|
+
_setAuthorNameResolvedFromCache() {
|
|
66
|
+
const authorDomain = this._authorDomainToSettle();
|
|
67
|
+
if (!authorDomain || !this.author)
|
|
68
|
+
return;
|
|
69
|
+
const cached = this._pkc._memCaches.nameResolvedCache.get(this._nameResolvedCacheKey(authorDomain));
|
|
70
|
+
if (typeof cached === "boolean")
|
|
71
|
+
this.author.nameResolved = cached;
|
|
72
|
+
}
|
|
73
|
+
toJSON() {
|
|
74
|
+
return {
|
|
75
|
+
// An unpublished list has no wire record yet; its props are the ones it will sign
|
|
76
|
+
...(this.raw.communityList ?? this._unsignedProps),
|
|
77
|
+
...(this.author ? { author: this.author } : undefined),
|
|
78
|
+
...(this.communities ? { communities: this.communities } : undefined),
|
|
79
|
+
cid: this.cid,
|
|
80
|
+
shortCid: this.shortCid
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
_setState(newState) {
|
|
84
|
+
if (this.state === newState)
|
|
85
|
+
return;
|
|
86
|
+
this.state = newState;
|
|
87
|
+
this.emit("statechange", newState);
|
|
88
|
+
}
|
|
89
|
+
_throwIfPublishAborted(signal) {
|
|
90
|
+
if (signal.aborted)
|
|
91
|
+
throw new PKCError("ERR_COMMUNITY_LIST_PUBLISH_ABORTED", { cid: this.cid });
|
|
92
|
+
}
|
|
93
|
+
// Sign the JSON and add the file to IPFS (locally, or via the RPC server). Sets cid and returns it
|
|
94
|
+
async publish() {
|
|
95
|
+
const log = Logger("pkc-js:community-list:publish");
|
|
96
|
+
if (!this.signer || !this._unsignedProps)
|
|
97
|
+
throw new PKCError("ERR_COMMUNITY_LIST_HAS_NO_SIGNER", { cid: this.cid });
|
|
98
|
+
if (this.state === "publishing")
|
|
99
|
+
throw new PKCError("ERR_COMMUNITY_LIST_ALREADY_PUBLISHING", {});
|
|
100
|
+
if (this.state === "updating")
|
|
101
|
+
throw new PKCError("ERR_COMMUNITY_LIST_ALREADY_UPDATING", {});
|
|
102
|
+
this._setState("publishing");
|
|
103
|
+
this._stopAbortController = new AbortController();
|
|
104
|
+
const signal = this._stopAbortController.signal;
|
|
105
|
+
try {
|
|
106
|
+
const cleanedProps = cleanUpBeforePublishing(this._unsignedProps);
|
|
107
|
+
const signature = await signCommunityList({ communityList: cleanedProps, signer: this.signer, pkc: this._pkc });
|
|
108
|
+
const record = { ...cleanedProps, signature };
|
|
109
|
+
parseCommunityListSchemaWithPKCErrorIfItFails(record); // throws on schema violations incl. duplicate entry publicKey
|
|
110
|
+
const recordString = JSON.stringify(record);
|
|
111
|
+
const sizeBytes = await calculateStringSizeSameAsIpfsAddCidV0(recordString);
|
|
112
|
+
if (sizeBytes > MAX_COMMUNITY_LIST_SIZE_BYTES)
|
|
113
|
+
throw new PKCError("ERR_COMMUNITY_LIST_OVER_ALLOWED_SIZE", {
|
|
114
|
+
sizeBytes,
|
|
115
|
+
maxSizeBytes: MAX_COMMUNITY_LIST_SIZE_BYTES
|
|
116
|
+
});
|
|
117
|
+
this._throwIfPublishAborted(signal);
|
|
118
|
+
let cid;
|
|
119
|
+
if (this._pkc._pkcRpcClient) {
|
|
120
|
+
// The raw string crosses the wire so the server adds the exact bytes we signed
|
|
121
|
+
const res = await this._pkc._pkcRpcClient.publishCommunityList({ communityListRawString: recordString });
|
|
122
|
+
// The server can pin whatever it wants, but the cid it hands back must be the cid of
|
|
123
|
+
// the exact bytes we signed, or every consumer would fail signature verification
|
|
124
|
+
const expectedCid = await calculateIpfsCidV0(recordString);
|
|
125
|
+
if (res.cid !== expectedCid)
|
|
126
|
+
throw new PKCError("ERR_ADDED_COMMUNITY_LIST_TO_IPFS_BUT_GOT_DIFFERENT_CID", {
|
|
127
|
+
expectedCid,
|
|
128
|
+
cidFromRpcServer: res.cid
|
|
129
|
+
});
|
|
130
|
+
cid = res.cid;
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
const kuboRpcClient = this._pkc._clientsManager.getDefaultKuboRpcClient();
|
|
134
|
+
const addRes = await retryKuboIpfsAddAndProvide({
|
|
135
|
+
ipfsClient: kuboRpcClient._client,
|
|
136
|
+
log,
|
|
137
|
+
content: recordString,
|
|
138
|
+
addOptions: { pin: true },
|
|
139
|
+
provideInBackground: true
|
|
140
|
+
});
|
|
141
|
+
cid = String(addRes.cid);
|
|
142
|
+
}
|
|
143
|
+
this._throwIfPublishAborted(signal);
|
|
144
|
+
this._initFromWireRecord(record, cid);
|
|
145
|
+
log(`Published CommunityList (${cid}) with ${record.communities.length} entries`);
|
|
146
|
+
return cid;
|
|
147
|
+
}
|
|
148
|
+
finally {
|
|
149
|
+
// The add takes no abort signal, so a stopped publish can settle after a newer publish() or
|
|
150
|
+
// update() took over; only the run that still owns the controller may reset the state
|
|
151
|
+
if (this._stopAbortController?.signal === signal)
|
|
152
|
+
this._setState("stopped");
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// Fetch and verify the record (retrying transient failures), emit `update`, then keep driving
|
|
156
|
+
// author.nameResolved until the verdict is definitive, emit `update` again, and stop itself
|
|
157
|
+
async update() {
|
|
158
|
+
if (this.state === "updating")
|
|
159
|
+
return; // no-op, same as Comment.update()
|
|
160
|
+
if (this.state === "publishing")
|
|
161
|
+
throw new PKCError("ERR_COMMUNITY_LIST_ALREADY_PUBLISHING", {});
|
|
162
|
+
if (!this.cid)
|
|
163
|
+
throw new PKCError("ERR_COMMUNITY_LIST_HAS_NO_CID", {});
|
|
164
|
+
this._setState("updating");
|
|
165
|
+
this._stopAbortController = new AbortController();
|
|
166
|
+
const signal = this._stopAbortController.signal;
|
|
167
|
+
this._pkc._updatingCommunityLists.add(this);
|
|
168
|
+
void this._runUpdateLoop(signal);
|
|
169
|
+
}
|
|
170
|
+
async _runUpdateLoop(signal) {
|
|
171
|
+
const log = Logger("pkc-js:community-list:update");
|
|
172
|
+
// Next macrotask, so a caller doing `await list.update()` can attach listeners before the
|
|
173
|
+
// already-loaded path emits synchronously
|
|
174
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
175
|
+
if (signal.aborted)
|
|
176
|
+
return;
|
|
177
|
+
try {
|
|
178
|
+
if (!this.raw.communityList)
|
|
179
|
+
await this._loadCommunityListIpfsWithRetries(signal);
|
|
180
|
+
else
|
|
181
|
+
this.emit("update", this); // already loaded (e.g. update() after publish()): emit current state
|
|
182
|
+
if (signal.aborted)
|
|
183
|
+
return;
|
|
184
|
+
await this._settleAuthorNameResolvedIfNeeded(signal);
|
|
185
|
+
// The record is immutable: once the record is loaded and the nameResolved verdict is
|
|
186
|
+
// definitive (or there is nothing to settle) there is nothing left to watch
|
|
187
|
+
if (!signal.aborted)
|
|
188
|
+
await this.stop();
|
|
189
|
+
}
|
|
190
|
+
catch (e) {
|
|
191
|
+
if (signal.aborted)
|
|
192
|
+
return;
|
|
193
|
+
log.error(`Failed to update CommunityList (${this.cid})`, e);
|
|
194
|
+
this.emit("error", e);
|
|
195
|
+
await this.stop();
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
// Deterministic record errors: the record is content-addressed, so refetching the same cid can
|
|
199
|
+
// never fix these. Everything else (transport) is retried forever
|
|
200
|
+
_isNonRetriableError(e) {
|
|
201
|
+
// Classified by code, not instanceof: an error rejected by an RPC call crosses the wire as a
|
|
202
|
+
// plain object carrying the server-side PKCError's code, never as a PKCError instance
|
|
203
|
+
const { code, details } = (e ?? {});
|
|
204
|
+
if (code === "ERR_FAILED_TO_FETCH_GENERIC_IPFS_FROM_GATEWAYS") {
|
|
205
|
+
// Gateways wrap each gateway's error into one: final only if every gateway hit a record
|
|
206
|
+
// error, same as Comment._isCommentIpfsErrorRetriable
|
|
207
|
+
const gatewayErrors = Object.values(details?.gatewayToError ?? {});
|
|
208
|
+
return gatewayErrors.length > 0 && gatewayErrors.every((gatewayError) => this._isNonRetriableError(gatewayError));
|
|
209
|
+
}
|
|
210
|
+
return (typeof code === "string" &&
|
|
211
|
+
[
|
|
212
|
+
"ERR_INVALID_JSON",
|
|
213
|
+
"ERR_INVALID_COMMUNITY_LIST_SCHEMA",
|
|
214
|
+
"ERR_COMMUNITY_LIST_SIGNATURE_IS_INVALID",
|
|
215
|
+
"ERR_OVER_DOWNLOAD_LIMIT",
|
|
216
|
+
"ERR_CALCULATED_CID_DOES_NOT_MATCH"
|
|
217
|
+
].includes(code));
|
|
218
|
+
}
|
|
219
|
+
async _loadCommunityListIpfsWithRetries(outerSignal) {
|
|
220
|
+
if (this.raw.communityList)
|
|
221
|
+
return;
|
|
222
|
+
const cid = this.cid;
|
|
223
|
+
if (!cid)
|
|
224
|
+
throw new PKCError("ERR_COMMUNITY_LIST_HAS_NO_CID", {});
|
|
225
|
+
// Own controller so stop() can cancel a load that was started without update() (getCommunityList).
|
|
226
|
+
// The controller and retry operation are this run's own: a stopped run can still settle later (an
|
|
227
|
+
// RPC fetch takes no abort signal), and it must not touch a newer run's controller or retry timers.
|
|
228
|
+
// They are mirrored on the instance only so stop() can reach the current run
|
|
229
|
+
const abortController = new AbortController();
|
|
230
|
+
const operation = retry.operation({ forever: true, factor: 2 });
|
|
231
|
+
this._loadingAbortController = abortController;
|
|
232
|
+
this._loadingOperation = operation;
|
|
233
|
+
const signal = abortController.signal;
|
|
234
|
+
const onOuterAbort = () => abortController.abort(outerSignal?.reason);
|
|
235
|
+
outerSignal?.addEventListener("abort", onOuterAbort, { once: true });
|
|
236
|
+
try {
|
|
237
|
+
const record = await new Promise((resolve, reject) => {
|
|
238
|
+
// Settle on abort, not on the next attempt: stop() clears a pending retry timer, so an
|
|
239
|
+
// attempt may never run again, and a load left pending never reaches its finally
|
|
240
|
+
const rejectOnAbort = () => reject(signal.reason || new Error("Aborted loading CommunityList"));
|
|
241
|
+
signal.addEventListener("abort", rejectOnAbort, { once: true });
|
|
242
|
+
operation.attempt(async () => {
|
|
243
|
+
if (signal.aborted)
|
|
244
|
+
return rejectOnAbort();
|
|
245
|
+
try {
|
|
246
|
+
resolve(await this._fetchAndVerifyOnce(cid, signal));
|
|
247
|
+
}
|
|
248
|
+
catch (e) {
|
|
249
|
+
if (signal.aborted || this._isNonRetriableError(e))
|
|
250
|
+
return reject(e);
|
|
251
|
+
this.emit("error", e);
|
|
252
|
+
operation.retry(e);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
if (signal.aborted)
|
|
257
|
+
return;
|
|
258
|
+
this._initFromWireRecord(record, cid);
|
|
259
|
+
this.emit("update", this);
|
|
260
|
+
}
|
|
261
|
+
finally {
|
|
262
|
+
operation.stop();
|
|
263
|
+
outerSignal?.removeEventListener("abort", onOuterAbort);
|
|
264
|
+
if (this._loadingOperation === operation)
|
|
265
|
+
this._loadingOperation = undefined;
|
|
266
|
+
if (this._loadingAbortController === abortController)
|
|
267
|
+
this._loadingAbortController = undefined;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
async _fetchAndVerifyOnce(cid, signal) {
|
|
271
|
+
let rawString;
|
|
272
|
+
if (this._pkc._pkcRpcClient) {
|
|
273
|
+
const res = await this._pkc._pkcRpcClient.fetchCommunityList({ cid });
|
|
274
|
+
rawString = res.communityListRawString;
|
|
275
|
+
// The RPC server is not trusted with record validity: enforce the load cap before hashing or
|
|
276
|
+
// parsing, the same error the direct path throws, then check the bytes are the cid's bytes
|
|
277
|
+
const sizeBytes = calculateStringSizeSameAsIpfsAddCidV0Sync(rawString);
|
|
278
|
+
if (sizeBytes > MAX_COMMUNITY_LIST_SIZE_BYTES)
|
|
279
|
+
throw new PKCError("ERR_OVER_DOWNLOAD_LIMIT", { cid, sizeBytes, maxSizeBytes: MAX_COMMUNITY_LIST_SIZE_BYTES });
|
|
280
|
+
const calculatedCid = await calculateIpfsCidV0(rawString);
|
|
281
|
+
if (calculatedCid !== cid)
|
|
282
|
+
throw new PKCError("ERR_CALCULATED_CID_DOES_NOT_MATCH", { calculatedCid, cid });
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
rawString = await this._pkc._clientsManager.fetchCid(cid, {
|
|
286
|
+
maxFileSizeBytes: MAX_COMMUNITY_LIST_SIZE_BYTES,
|
|
287
|
+
abortSignal: signal
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
const record = parseCommunityListSchemaWithPKCErrorIfItFails(parseJsonWithPKCErrorIfFails(rawString));
|
|
291
|
+
const validity = await verifyCommunityList({ communityList: record });
|
|
292
|
+
if (!validity.valid)
|
|
293
|
+
throw new PKCError("ERR_COMMUNITY_LIST_SIGNATURE_IS_INVALID", { validity, cid });
|
|
294
|
+
return record;
|
|
295
|
+
}
|
|
296
|
+
// The name of the author on the wire, only when it's a domain that can be resolved
|
|
297
|
+
_authorDomainToSettle() {
|
|
298
|
+
const wireAuthorName = this.raw.communityList?.author?.name;
|
|
299
|
+
if (typeof wireAuthorName !== "string" || !isStringDomain(wireAuthorName))
|
|
300
|
+
return undefined;
|
|
301
|
+
return wireAuthorName;
|
|
302
|
+
}
|
|
303
|
+
_nameResolvedCacheKey(authorDomain) {
|
|
304
|
+
return sha256(authorDomain + this.raw.communityList.signature.publicKey);
|
|
305
|
+
}
|
|
306
|
+
// One resolution attempt. Returns a definitive verdict (boolean) or undefined for a transient
|
|
307
|
+
// failure that should be retried. Resolved verdicts are cached pkc-wide, same as publications
|
|
308
|
+
async _resolveAuthorNameVerdictOnce(authorDomain) {
|
|
309
|
+
const cache = this._pkc._memCaches.nameResolvedCache;
|
|
310
|
+
const cacheKey = this._nameResolvedCacheKey(authorDomain);
|
|
311
|
+
const cached = cache.get(cacheKey);
|
|
312
|
+
if (typeof cached === "boolean")
|
|
313
|
+
return cached;
|
|
314
|
+
try {
|
|
315
|
+
// Works over both transports: PKCWithRpcClient overrides resolveAuthorName to delegate to the RPC server
|
|
316
|
+
const { resolvedAuthorName } = await this._pkc.resolveAuthorName({ name: authorDomain });
|
|
317
|
+
const ttlOf = (verdict) => (verdict ? this._pkc._nameResolvedTrueTtlMs : this._pkc._nameResolvedFalseTtlMs);
|
|
318
|
+
if (typeof resolvedAuthorName !== "string") {
|
|
319
|
+
// The resolvers answered and there is no record: definitive, same as
|
|
320
|
+
// resolveAuthorNamesInBackground. All resolvers erroring throws instead (issue #353)
|
|
321
|
+
cache.set(cacheKey, false, { ttl: ttlOf(false) });
|
|
322
|
+
return false;
|
|
323
|
+
}
|
|
324
|
+
const signerAddress = getPKCAddressFromPublicKeySync(this.raw.communityList.signature.publicKey);
|
|
325
|
+
const verdict = resolvedAuthorName === signerAddress;
|
|
326
|
+
// Same per-verdict ttls as resolveAuthorNamesInBackground: a `false` is what a domain looks
|
|
327
|
+
// like while its owner is still configuring it, so it expires quickly (issue #353)
|
|
328
|
+
cache.set(cacheKey, verdict, { ttl: ttlOf(verdict) });
|
|
329
|
+
return verdict;
|
|
330
|
+
}
|
|
331
|
+
catch (e) {
|
|
332
|
+
// Classified by code, not instanceof: over RPC the rejection is a plain object carrying the code
|
|
333
|
+
const code = e?.code;
|
|
334
|
+
if (code === "ERR_RESOLVED_TEXT_RECORD_TO_NON_IPNS") {
|
|
335
|
+
// The resolvers answered: the record exists and is not a key. Definitive non-match
|
|
336
|
+
cache.set(cacheKey, false, { ttl: this._pkc._nameResolvedFalseTtlMs });
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
if (code === "ERR_NO_RESOLVER_FOR_NAME") {
|
|
340
|
+
// Definitive for this list: no resolver in this PKC instance (or its RPC server) handles
|
|
341
|
+
// this TLD. Not cached: the cache is shared with comments and pages, for which "never
|
|
342
|
+
// asked" is undefined, not false (issue #353)
|
|
343
|
+
return false;
|
|
344
|
+
}
|
|
345
|
+
return undefined; // no answer (every resolver errored, a timeout): retry
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
// Fire-and-forget cache warmup, used by the one-shot getCommunityList path which does not wait
|
|
349
|
+
// for the verdict: evented instances pick it up from the pkc-wide cache
|
|
350
|
+
_kickOffBackgroundAuthorNameResolution() {
|
|
351
|
+
const log = Logger("pkc-js:community-list:resolve-author-name");
|
|
352
|
+
const authorDomain = this._authorDomainToSettle();
|
|
353
|
+
if (!authorDomain || !this._pkc.resolveAuthorNames)
|
|
354
|
+
return;
|
|
355
|
+
this._resolveAuthorNameVerdictOnce(authorDomain).catch((e) => log.error("Failed background author name resolution", authorDomain, e));
|
|
356
|
+
}
|
|
357
|
+
async _settleAuthorNameResolvedIfNeeded(signal) {
|
|
358
|
+
const authorDomain = this._authorDomainToSettle();
|
|
359
|
+
if (!authorDomain || !this.author || !this._pkc.resolveAuthorNames)
|
|
360
|
+
return;
|
|
361
|
+
let attempt = 0;
|
|
362
|
+
while (!signal.aborted) {
|
|
363
|
+
const verdict = await this._resolveAuthorNameVerdictOnce(authorDomain);
|
|
364
|
+
if (signal.aborted)
|
|
365
|
+
return;
|
|
366
|
+
if (typeof verdict === "boolean") {
|
|
367
|
+
this.author.nameResolved = verdict;
|
|
368
|
+
this.emit("update", this);
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
attempt++;
|
|
372
|
+
await this._delayWithAbort(Math.min(1000 * 2 ** attempt, 60_000), signal);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
async _delayWithAbort(ms, signal) {
|
|
376
|
+
if (signal.aborted)
|
|
377
|
+
return;
|
|
378
|
+
await new Promise((resolve) => {
|
|
379
|
+
const timeout = setTimeout(() => {
|
|
380
|
+
signal.removeEventListener("abort", onAbort);
|
|
381
|
+
resolve();
|
|
382
|
+
}, ms);
|
|
383
|
+
const onAbort = () => {
|
|
384
|
+
clearTimeout(timeout);
|
|
385
|
+
resolve();
|
|
386
|
+
};
|
|
387
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
// Aborts an in-flight publish(), update(), or getCommunityList() load
|
|
391
|
+
async stop() {
|
|
392
|
+
this._pkc._updatingCommunityLists.delete(this);
|
|
393
|
+
this._stopAbortController?.abort();
|
|
394
|
+
this._loadingAbortController?.abort();
|
|
395
|
+
this._loadingOperation?.stop();
|
|
396
|
+
if (this.state === "stopped")
|
|
397
|
+
return;
|
|
398
|
+
this._setState("stopped");
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
//# sourceMappingURL=community-list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"community-list.js","sourceRoot":"","sources":["../../../src/community-list/community-list.ts"],"names":[],"mappings":"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"}
|