2023-12-11 02:06:43 +00:00
|
|
|
import { DEFAULT_BASE_OPTIONS } from "../utils/options.js";
|
|
|
|
import { CustomClientOptions, S5Client } from "../client.js";
|
|
|
|
import { ensureBytes } from "@noble/curves/abstract/utils";
|
|
|
|
|
|
|
|
import WS from "isomorphic-ws";
|
|
|
|
import { buildRequestUrl } from "#request.js";
|
2023-12-12 03:44:43 +00:00
|
|
|
import {
|
|
|
|
CID,
|
|
|
|
createKeyPair,
|
|
|
|
KeyPairEd25519,
|
|
|
|
Packer,
|
|
|
|
SignedRegistryEntry,
|
|
|
|
} from "@lumeweb/libs5";
|
2023-12-12 03:26:42 +00:00
|
|
|
import {
|
|
|
|
deserializeRegistryEntry,
|
2023-12-12 03:44:43 +00:00
|
|
|
signRegistryEntry,
|
2023-12-12 03:26:42 +00:00
|
|
|
verifyRegistryEntry,
|
|
|
|
} from "@lumeweb/libs5/lib/service/registry.js";
|
2023-12-11 02:06:43 +00:00
|
|
|
import { Buffer } from "buffer";
|
2023-12-12 03:26:42 +00:00
|
|
|
import { throwValidationError } from "../utils/validation.js";
|
2023-12-12 19:34:08 +00:00
|
|
|
import { base64url } from "multiformats/bases/base64";
|
2023-12-11 02:06:43 +00:00
|
|
|
export const DEFAULT_GET_ENTRY_OPTIONS = {
|
|
|
|
...DEFAULT_BASE_OPTIONS,
|
|
|
|
endpointGetEntry: "/s5/registry",
|
|
|
|
};
|
|
|
|
|
|
|
|
export const DEFAULT_SET_ENTRY_OPTIONS = {
|
|
|
|
...DEFAULT_BASE_OPTIONS,
|
|
|
|
endpointSetEntry: "/s5/registry",
|
|
|
|
deleteForever: false,
|
|
|
|
};
|
|
|
|
|
|
|
|
export const DEFAULT_SUBSCRIBE_ENTRY_OPTIONS = {
|
|
|
|
...DEFAULT_BASE_OPTIONS,
|
|
|
|
endpointSubscribeEntry: "/s5/registry/subscription",
|
|
|
|
};
|
|
|
|
|
2023-12-12 03:26:42 +00:00
|
|
|
export const DEFAULT_PUBLISH_ENTRY_OPTIONS = {
|
|
|
|
...DEFAULT_BASE_OPTIONS,
|
|
|
|
endpointPublishEntry: "/s5/registry",
|
|
|
|
};
|
|
|
|
|
2023-12-11 02:06:43 +00:00
|
|
|
export type BaseCustomOptions = CustomClientOptions;
|
|
|
|
|
|
|
|
export type CustomRegistryOptions = BaseCustomOptions & {
|
|
|
|
endpointSubscribeEntry?: string;
|
2023-12-12 03:26:42 +00:00
|
|
|
endpointPublishEntry?: string;
|
2023-12-11 02:06:43 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
export async function subscribeToEntry(
|
|
|
|
this: S5Client,
|
|
|
|
publicKey: Uint8Array,
|
|
|
|
customOptions?: CustomRegistryOptions,
|
|
|
|
) {
|
|
|
|
const opts = {
|
|
|
|
...DEFAULT_SUBSCRIBE_ENTRY_OPTIONS,
|
|
|
|
...this.customOptions,
|
|
|
|
...customOptions,
|
|
|
|
};
|
|
|
|
|
|
|
|
publicKey = ensureBytes("public key", publicKey, 32);
|
|
|
|
|
|
|
|
const url = await buildRequestUrl(this, {
|
|
|
|
baseUrl: await this.portalUrl(),
|
|
|
|
endpointPath: opts.endpointSubscribeEntry,
|
|
|
|
});
|
|
|
|
|
|
|
|
const socket = new WS(url);
|
|
|
|
|
|
|
|
socket.once("open", () => {
|
|
|
|
const packer = new Packer();
|
|
|
|
packer.pack(2);
|
|
|
|
packer.pack(publicKey);
|
|
|
|
|
|
|
|
socket.send(packer.takeBytes());
|
|
|
|
});
|
|
|
|
|
|
|
|
return {
|
|
|
|
listen(cb: (entry: SignedRegistryEntry) => void) {
|
|
|
|
socket.on("message", (data) => {
|
|
|
|
cb(deserializeRegistryEntry(new Uint8Array(data as Buffer)));
|
|
|
|
});
|
|
|
|
},
|
|
|
|
end() {
|
|
|
|
if ([socket.CLOSING, socket.CLOSED].includes(socket.readyState as any)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
socket.close();
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
2023-12-12 03:26:42 +00:00
|
|
|
|
|
|
|
export async function publishEntry(
|
|
|
|
this: S5Client,
|
|
|
|
signedEntry: SignedRegistryEntry,
|
|
|
|
customOptions?: CustomRegistryOptions,
|
|
|
|
) {
|
|
|
|
const opts = {
|
|
|
|
...DEFAULT_PUBLISH_ENTRY_OPTIONS,
|
|
|
|
...this.customOptions,
|
|
|
|
...customOptions,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!verifyRegistryEntry(signedEntry)) {
|
|
|
|
throwValidationError(
|
|
|
|
"signedEntry", // name of the variable
|
|
|
|
signedEntry, // actual value
|
|
|
|
"parameter", // valueKind (assuming it's a function parameter)
|
|
|
|
"a valid signed registry entry", // expected description
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return await this.executeRequest({
|
|
|
|
...opts,
|
|
|
|
endpointPath: opts.endpointPublishEntry,
|
|
|
|
method: "post",
|
|
|
|
data: {
|
2023-12-12 19:34:08 +00:00
|
|
|
pk: base64url.encode(signedEntry.pk),
|
2023-12-12 03:26:42 +00:00
|
|
|
revision: signedEntry.revision,
|
2023-12-12 19:34:08 +00:00
|
|
|
data: base64url.encode(signedEntry.data),
|
|
|
|
signature: base64url.encode(signedEntry.signature),
|
2023-12-12 03:26:42 +00:00
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
2023-12-12 03:44:43 +00:00
|
|
|
|
|
|
|
export async function createEntry(
|
|
|
|
this: S5Client,
|
|
|
|
sk: Uint8Array | KeyPairEd25519,
|
|
|
|
cid: CID,
|
|
|
|
revision = 0,
|
|
|
|
) {
|
|
|
|
if (sk instanceof Uint8Array) {
|
|
|
|
sk = createKeyPair(sk);
|
|
|
|
}
|
|
|
|
|
|
|
|
const entry = {
|
|
|
|
kp: sk,
|
|
|
|
data: cid.toBytes(),
|
|
|
|
revision,
|
|
|
|
};
|
|
|
|
|
2023-12-12 03:55:02 +00:00
|
|
|
const signedEntry = signRegistryEntry(entry);
|
|
|
|
|
|
|
|
await this.publishEntry(signedEntry);
|
|
|
|
|
|
|
|
return signedEntry;
|
2023-12-12 03:44:43 +00:00
|
|
|
}
|