Add request client (#342)

* add `preview-client.ts`

* add exports

* fix imports

* set emoji hash

* use `message.timestamp`

* rename `RequestClient`

* drop preview keyword

* rm `appUrl`

* rm todo?:

* remove social urls

* remove if clause
This commit is contained in:
Felicio Mununga 2023-03-15 14:14:26 +01:00 committed by GitHub
parent a28c7e50bf
commit fd372f9445
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 1419 additions and 4 deletions

View File

@ -11,3 +11,10 @@ export { createClient } from './client/client'
export type { Community } from './client/community/community'
export type { Reaction, Reactions } from './client/community/get-reactions'
export type { Member } from './client/member'
export type { ChannelInfo } from './request-client/map-channel'
export type { CommunityInfo } from './request-client/map-community'
export type { UserInfo } from './request-client/map-user'
export type { RequestClient } from './request-client/request-client'
export { createRequestClient } from './request-client/request-client'
export { deserializePublicKey } from './utils/deserialize-public-key'
export { publicKeyToEmojiHash } from './utils/public-key-to-emoji-hash'

View File

@ -58,7 +58,16 @@ message HRHeader {
// Community message number for this key_id
uint32 seq_no = 2;
// Community ID
string group_id = 3;
bytes group_id = 3;
}
message HRKeys {
repeated HRKey keys = 1;
}
message HRKey {
uint32 key_id = 1;
bytes key = 2;
}
// Direct message value

View File

@ -339,9 +339,9 @@ export class HRHeader extends Message<HRHeader> {
/**
* Community ID
*
* @generated from field: string group_id = 3;
* @generated from field: bytes group_id = 3;
*/
groupId = "";
groupId = new Uint8Array(0);
constructor(data?: PartialMessage<HRHeader>) {
super();
@ -353,7 +353,7 @@ export class HRHeader extends Message<HRHeader> {
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "key_id", kind: "scalar", T: 13 /* ScalarType.UINT32 */ },
{ no: 2, name: "seq_no", kind: "scalar", T: 13 /* ScalarType.UINT32 */ },
{ no: 3, name: "group_id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 3, name: "group_id", kind: "scalar", T: 12 /* ScalarType.BYTES */ },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): HRHeader {
@ -373,6 +373,86 @@ export class HRHeader extends Message<HRHeader> {
}
}
/**
* @generated from message HRKeys
*/
export class HRKeys extends Message<HRKeys> {
/**
* @generated from field: repeated HRKey keys = 1;
*/
keys: HRKey[] = [];
constructor(data?: PartialMessage<HRKeys>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime = proto3;
static readonly typeName = "HRKeys";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "keys", kind: "message", T: HRKey, repeated: true },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): HRKeys {
return new HRKeys().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): HRKeys {
return new HRKeys().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): HRKeys {
return new HRKeys().fromJsonString(jsonString, options);
}
static equals(a: HRKeys | PlainMessage<HRKeys> | undefined, b: HRKeys | PlainMessage<HRKeys> | undefined): boolean {
return proto3.util.equals(HRKeys, a, b);
}
}
/**
* @generated from message HRKey
*/
export class HRKey extends Message<HRKey> {
/**
* @generated from field: uint32 key_id = 1;
*/
keyId = 0;
/**
* @generated from field: bytes key = 2;
*/
key = new Uint8Array(0);
constructor(data?: PartialMessage<HRKey>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime = proto3;
static readonly typeName = "HRKey";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "key_id", kind: "scalar", T: 13 /* ScalarType.UINT32 */ },
{ no: 2, name: "key", kind: "scalar", T: 12 /* ScalarType.BYTES */ },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): HRKey {
return new HRKey().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): HRKey {
return new HRKey().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): HRKey {
return new HRKey().fromJsonString(jsonString, options);
}
static equals(a: HRKey | PlainMessage<HRKey> | undefined, b: HRKey | PlainMessage<HRKey> | undefined): boolean {
return proto3.util.equals(HRKey, a, b);
}
}
/**
* Direct message value
*

View File

@ -0,0 +1,103 @@
syntax = "proto3";
import "chat-identity.proto";
message PushNotificationRegistration {
enum TokenType {
UNKNOWN_TOKEN_TYPE = 0;
APN_TOKEN = 1;
FIREBASE_TOKEN = 2;
}
TokenType token_type = 1;
string device_token = 2;
string installation_id = 3;
string access_token = 4;
bool enabled = 5;
uint64 version = 6;
repeated bytes allowed_key_list = 7;
repeated bytes blocked_chat_list = 8;
bool unregister = 9;
bytes grant = 10;
bool allow_from_contacts_only = 11;
string apn_topic = 12;
bool block_mentions = 13;
repeated bytes allowed_mentions_chat_list = 14;
}
message PushNotificationRegistrationResponse {
bool success = 1;
ErrorType error = 2;
bytes request_id = 3;
enum ErrorType {
UNKNOWN_ERROR_TYPE = 0;
MALFORMED_MESSAGE = 1;
VERSION_MISMATCH = 2;
UNSUPPORTED_TOKEN_TYPE = 3;
INTERNAL_ERROR = 4;
}
}
message ContactCodeAdvertisement {
repeated PushNotificationQueryInfo push_notification_info = 1;
ChatIdentity chat_identity = 2;
}
message PushNotificationQuery {
repeated bytes public_keys = 1;
}
message PushNotificationQueryInfo {
string access_token = 1;
string installation_id = 2;
bytes public_key = 3;
repeated bytes allowed_key_list = 4;
bytes grant = 5;
uint64 version = 6;
bytes server_public_key = 7;
}
message PushNotificationQueryResponse {
repeated PushNotificationQueryInfo info = 1;
bytes message_id = 2;
bool success = 3;
}
message PushNotification {
string access_token = 1;
bytes chat_id = 2;
bytes public_key = 3;
string installation_id = 4;
bytes message = 5;
PushNotificationType type = 6;
enum PushNotificationType {
UNKNOWN_PUSH_NOTIFICATION_TYPE = 0;
MESSAGE = 1;
MENTION = 2;
REQUEST_TO_JOIN_COMMUNITY = 3;
}
bytes author = 7;
}
message PushNotificationRequest {
repeated PushNotification requests = 1;
bytes message_id = 2;
}
message PushNotificationReport {
bool success = 1;
ErrorType error = 2;
enum ErrorType {
UNKNOWN_ERROR_TYPE = 0;
WRONG_TOKEN = 1;
INTERNAL_ERROR = 2;
NOT_REGISTERED = 3;
}
bytes public_key = 3;
string installation_id = 4;
}
message PushNotificationResponse {
bytes message_id = 1;
repeated PushNotificationReport reports = 2;
}

View File

@ -0,0 +1,717 @@
// @generated by protoc-gen-es v1.0.0 with parameter "target=ts"
// @generated from file push-notifications.proto (syntax proto3)
/* eslint-disable */
// @ts-nocheck
import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf";
import { Message, proto3, protoInt64 } from "@bufbuild/protobuf";
import { ChatIdentity } from "./chat-identity_pb.js";
/**
* @generated from message PushNotificationRegistration
*/
export class PushNotificationRegistration extends Message<PushNotificationRegistration> {
/**
* @generated from field: PushNotificationRegistration.TokenType token_type = 1;
*/
tokenType = PushNotificationRegistration_TokenType.UNKNOWN_TOKEN_TYPE;
/**
* @generated from field: string device_token = 2;
*/
deviceToken = "";
/**
* @generated from field: string installation_id = 3;
*/
installationId = "";
/**
* @generated from field: string access_token = 4;
*/
accessToken = "";
/**
* @generated from field: bool enabled = 5;
*/
enabled = false;
/**
* @generated from field: uint64 version = 6;
*/
version = protoInt64.zero;
/**
* @generated from field: repeated bytes allowed_key_list = 7;
*/
allowedKeyList: Uint8Array[] = [];
/**
* @generated from field: repeated bytes blocked_chat_list = 8;
*/
blockedChatList: Uint8Array[] = [];
/**
* @generated from field: bool unregister = 9;
*/
unregister = false;
/**
* @generated from field: bytes grant = 10;
*/
grant = new Uint8Array(0);
/**
* @generated from field: bool allow_from_contacts_only = 11;
*/
allowFromContactsOnly = false;
/**
* @generated from field: string apn_topic = 12;
*/
apnTopic = "";
/**
* @generated from field: bool block_mentions = 13;
*/
blockMentions = false;
/**
* @generated from field: repeated bytes allowed_mentions_chat_list = 14;
*/
allowedMentionsChatList: Uint8Array[] = [];
constructor(data?: PartialMessage<PushNotificationRegistration>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime = proto3;
static readonly typeName = "PushNotificationRegistration";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "token_type", kind: "enum", T: proto3.getEnumType(PushNotificationRegistration_TokenType) },
{ no: 2, name: "device_token", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 3, name: "installation_id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 4, name: "access_token", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 5, name: "enabled", kind: "scalar", T: 8 /* ScalarType.BOOL */ },
{ no: 6, name: "version", kind: "scalar", T: 4 /* ScalarType.UINT64 */ },
{ no: 7, name: "allowed_key_list", kind: "scalar", T: 12 /* ScalarType.BYTES */, repeated: true },
{ no: 8, name: "blocked_chat_list", kind: "scalar", T: 12 /* ScalarType.BYTES */, repeated: true },
{ no: 9, name: "unregister", kind: "scalar", T: 8 /* ScalarType.BOOL */ },
{ no: 10, name: "grant", kind: "scalar", T: 12 /* ScalarType.BYTES */ },
{ no: 11, name: "allow_from_contacts_only", kind: "scalar", T: 8 /* ScalarType.BOOL */ },
{ no: 12, name: "apn_topic", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 13, name: "block_mentions", kind: "scalar", T: 8 /* ScalarType.BOOL */ },
{ no: 14, name: "allowed_mentions_chat_list", kind: "scalar", T: 12 /* ScalarType.BYTES */, repeated: true },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): PushNotificationRegistration {
return new PushNotificationRegistration().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): PushNotificationRegistration {
return new PushNotificationRegistration().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): PushNotificationRegistration {
return new PushNotificationRegistration().fromJsonString(jsonString, options);
}
static equals(a: PushNotificationRegistration | PlainMessage<PushNotificationRegistration> | undefined, b: PushNotificationRegistration | PlainMessage<PushNotificationRegistration> | undefined): boolean {
return proto3.util.equals(PushNotificationRegistration, a, b);
}
}
/**
* @generated from enum PushNotificationRegistration.TokenType
*/
export enum PushNotificationRegistration_TokenType {
/**
* @generated from enum value: UNKNOWN_TOKEN_TYPE = 0;
*/
UNKNOWN_TOKEN_TYPE = 0,
/**
* @generated from enum value: APN_TOKEN = 1;
*/
APN_TOKEN = 1,
/**
* @generated from enum value: FIREBASE_TOKEN = 2;
*/
FIREBASE_TOKEN = 2,
}
// Retrieve enum metadata with: proto3.getEnumType(PushNotificationRegistration_TokenType)
proto3.util.setEnumType(PushNotificationRegistration_TokenType, "PushNotificationRegistration.TokenType", [
{ no: 0, name: "UNKNOWN_TOKEN_TYPE" },
{ no: 1, name: "APN_TOKEN" },
{ no: 2, name: "FIREBASE_TOKEN" },
]);
/**
* @generated from message PushNotificationRegistrationResponse
*/
export class PushNotificationRegistrationResponse extends Message<PushNotificationRegistrationResponse> {
/**
* @generated from field: bool success = 1;
*/
success = false;
/**
* @generated from field: PushNotificationRegistrationResponse.ErrorType error = 2;
*/
error = PushNotificationRegistrationResponse_ErrorType.UNKNOWN_ERROR_TYPE;
/**
* @generated from field: bytes request_id = 3;
*/
requestId = new Uint8Array(0);
constructor(data?: PartialMessage<PushNotificationRegistrationResponse>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime = proto3;
static readonly typeName = "PushNotificationRegistrationResponse";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "success", kind: "scalar", T: 8 /* ScalarType.BOOL */ },
{ no: 2, name: "error", kind: "enum", T: proto3.getEnumType(PushNotificationRegistrationResponse_ErrorType) },
{ no: 3, name: "request_id", kind: "scalar", T: 12 /* ScalarType.BYTES */ },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): PushNotificationRegistrationResponse {
return new PushNotificationRegistrationResponse().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): PushNotificationRegistrationResponse {
return new PushNotificationRegistrationResponse().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): PushNotificationRegistrationResponse {
return new PushNotificationRegistrationResponse().fromJsonString(jsonString, options);
}
static equals(a: PushNotificationRegistrationResponse | PlainMessage<PushNotificationRegistrationResponse> | undefined, b: PushNotificationRegistrationResponse | PlainMessage<PushNotificationRegistrationResponse> | undefined): boolean {
return proto3.util.equals(PushNotificationRegistrationResponse, a, b);
}
}
/**
* @generated from enum PushNotificationRegistrationResponse.ErrorType
*/
export enum PushNotificationRegistrationResponse_ErrorType {
/**
* @generated from enum value: UNKNOWN_ERROR_TYPE = 0;
*/
UNKNOWN_ERROR_TYPE = 0,
/**
* @generated from enum value: MALFORMED_MESSAGE = 1;
*/
MALFORMED_MESSAGE = 1,
/**
* @generated from enum value: VERSION_MISMATCH = 2;
*/
VERSION_MISMATCH = 2,
/**
* @generated from enum value: UNSUPPORTED_TOKEN_TYPE = 3;
*/
UNSUPPORTED_TOKEN_TYPE = 3,
/**
* @generated from enum value: INTERNAL_ERROR = 4;
*/
INTERNAL_ERROR = 4,
}
// Retrieve enum metadata with: proto3.getEnumType(PushNotificationRegistrationResponse_ErrorType)
proto3.util.setEnumType(PushNotificationRegistrationResponse_ErrorType, "PushNotificationRegistrationResponse.ErrorType", [
{ no: 0, name: "UNKNOWN_ERROR_TYPE" },
{ no: 1, name: "MALFORMED_MESSAGE" },
{ no: 2, name: "VERSION_MISMATCH" },
{ no: 3, name: "UNSUPPORTED_TOKEN_TYPE" },
{ no: 4, name: "INTERNAL_ERROR" },
]);
/**
* @generated from message ContactCodeAdvertisement
*/
export class ContactCodeAdvertisement extends Message<ContactCodeAdvertisement> {
/**
* @generated from field: repeated PushNotificationQueryInfo push_notification_info = 1;
*/
pushNotificationInfo: PushNotificationQueryInfo[] = [];
/**
* @generated from field: ChatIdentity chat_identity = 2;
*/
chatIdentity?: ChatIdentity;
constructor(data?: PartialMessage<ContactCodeAdvertisement>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime = proto3;
static readonly typeName = "ContactCodeAdvertisement";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "push_notification_info", kind: "message", T: PushNotificationQueryInfo, repeated: true },
{ no: 2, name: "chat_identity", kind: "message", T: ChatIdentity },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): ContactCodeAdvertisement {
return new ContactCodeAdvertisement().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): ContactCodeAdvertisement {
return new ContactCodeAdvertisement().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): ContactCodeAdvertisement {
return new ContactCodeAdvertisement().fromJsonString(jsonString, options);
}
static equals(a: ContactCodeAdvertisement | PlainMessage<ContactCodeAdvertisement> | undefined, b: ContactCodeAdvertisement | PlainMessage<ContactCodeAdvertisement> | undefined): boolean {
return proto3.util.equals(ContactCodeAdvertisement, a, b);
}
}
/**
* @generated from message PushNotificationQuery
*/
export class PushNotificationQuery extends Message<PushNotificationQuery> {
/**
* @generated from field: repeated bytes public_keys = 1;
*/
publicKeys: Uint8Array[] = [];
constructor(data?: PartialMessage<PushNotificationQuery>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime = proto3;
static readonly typeName = "PushNotificationQuery";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "public_keys", kind: "scalar", T: 12 /* ScalarType.BYTES */, repeated: true },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): PushNotificationQuery {
return new PushNotificationQuery().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): PushNotificationQuery {
return new PushNotificationQuery().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): PushNotificationQuery {
return new PushNotificationQuery().fromJsonString(jsonString, options);
}
static equals(a: PushNotificationQuery | PlainMessage<PushNotificationQuery> | undefined, b: PushNotificationQuery | PlainMessage<PushNotificationQuery> | undefined): boolean {
return proto3.util.equals(PushNotificationQuery, a, b);
}
}
/**
* @generated from message PushNotificationQueryInfo
*/
export class PushNotificationQueryInfo extends Message<PushNotificationQueryInfo> {
/**
* @generated from field: string access_token = 1;
*/
accessToken = "";
/**
* @generated from field: string installation_id = 2;
*/
installationId = "";
/**
* @generated from field: bytes public_key = 3;
*/
publicKey = new Uint8Array(0);
/**
* @generated from field: repeated bytes allowed_key_list = 4;
*/
allowedKeyList: Uint8Array[] = [];
/**
* @generated from field: bytes grant = 5;
*/
grant = new Uint8Array(0);
/**
* @generated from field: uint64 version = 6;
*/
version = protoInt64.zero;
/**
* @generated from field: bytes server_public_key = 7;
*/
serverPublicKey = new Uint8Array(0);
constructor(data?: PartialMessage<PushNotificationQueryInfo>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime = proto3;
static readonly typeName = "PushNotificationQueryInfo";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "access_token", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 2, name: "installation_id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 3, name: "public_key", kind: "scalar", T: 12 /* ScalarType.BYTES */ },
{ no: 4, name: "allowed_key_list", kind: "scalar", T: 12 /* ScalarType.BYTES */, repeated: true },
{ no: 5, name: "grant", kind: "scalar", T: 12 /* ScalarType.BYTES */ },
{ no: 6, name: "version", kind: "scalar", T: 4 /* ScalarType.UINT64 */ },
{ no: 7, name: "server_public_key", kind: "scalar", T: 12 /* ScalarType.BYTES */ },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): PushNotificationQueryInfo {
return new PushNotificationQueryInfo().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): PushNotificationQueryInfo {
return new PushNotificationQueryInfo().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): PushNotificationQueryInfo {
return new PushNotificationQueryInfo().fromJsonString(jsonString, options);
}
static equals(a: PushNotificationQueryInfo | PlainMessage<PushNotificationQueryInfo> | undefined, b: PushNotificationQueryInfo | PlainMessage<PushNotificationQueryInfo> | undefined): boolean {
return proto3.util.equals(PushNotificationQueryInfo, a, b);
}
}
/**
* @generated from message PushNotificationQueryResponse
*/
export class PushNotificationQueryResponse extends Message<PushNotificationQueryResponse> {
/**
* @generated from field: repeated PushNotificationQueryInfo info = 1;
*/
info: PushNotificationQueryInfo[] = [];
/**
* @generated from field: bytes message_id = 2;
*/
messageId = new Uint8Array(0);
/**
* @generated from field: bool success = 3;
*/
success = false;
constructor(data?: PartialMessage<PushNotificationQueryResponse>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime = proto3;
static readonly typeName = "PushNotificationQueryResponse";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "info", kind: "message", T: PushNotificationQueryInfo, repeated: true },
{ no: 2, name: "message_id", kind: "scalar", T: 12 /* ScalarType.BYTES */ },
{ no: 3, name: "success", kind: "scalar", T: 8 /* ScalarType.BOOL */ },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): PushNotificationQueryResponse {
return new PushNotificationQueryResponse().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): PushNotificationQueryResponse {
return new PushNotificationQueryResponse().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): PushNotificationQueryResponse {
return new PushNotificationQueryResponse().fromJsonString(jsonString, options);
}
static equals(a: PushNotificationQueryResponse | PlainMessage<PushNotificationQueryResponse> | undefined, b: PushNotificationQueryResponse | PlainMessage<PushNotificationQueryResponse> | undefined): boolean {
return proto3.util.equals(PushNotificationQueryResponse, a, b);
}
}
/**
* @generated from message PushNotification
*/
export class PushNotification extends Message<PushNotification> {
/**
* @generated from field: string access_token = 1;
*/
accessToken = "";
/**
* @generated from field: bytes chat_id = 2;
*/
chatId = new Uint8Array(0);
/**
* @generated from field: bytes public_key = 3;
*/
publicKey = new Uint8Array(0);
/**
* @generated from field: string installation_id = 4;
*/
installationId = "";
/**
* @generated from field: bytes message = 5;
*/
message = new Uint8Array(0);
/**
* @generated from field: PushNotification.PushNotificationType type = 6;
*/
type = PushNotification_PushNotificationType.UNKNOWN_PUSH_NOTIFICATION_TYPE;
/**
* @generated from field: bytes author = 7;
*/
author = new Uint8Array(0);
constructor(data?: PartialMessage<PushNotification>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime = proto3;
static readonly typeName = "PushNotification";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "access_token", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 2, name: "chat_id", kind: "scalar", T: 12 /* ScalarType.BYTES */ },
{ no: 3, name: "public_key", kind: "scalar", T: 12 /* ScalarType.BYTES */ },
{ no: 4, name: "installation_id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
{ no: 5, name: "message", kind: "scalar", T: 12 /* ScalarType.BYTES */ },
{ no: 6, name: "type", kind: "enum", T: proto3.getEnumType(PushNotification_PushNotificationType) },
{ no: 7, name: "author", kind: "scalar", T: 12 /* ScalarType.BYTES */ },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): PushNotification {
return new PushNotification().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): PushNotification {
return new PushNotification().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): PushNotification {
return new PushNotification().fromJsonString(jsonString, options);
}
static equals(a: PushNotification | PlainMessage<PushNotification> | undefined, b: PushNotification | PlainMessage<PushNotification> | undefined): boolean {
return proto3.util.equals(PushNotification, a, b);
}
}
/**
* @generated from enum PushNotification.PushNotificationType
*/
export enum PushNotification_PushNotificationType {
/**
* @generated from enum value: UNKNOWN_PUSH_NOTIFICATION_TYPE = 0;
*/
UNKNOWN_PUSH_NOTIFICATION_TYPE = 0,
/**
* @generated from enum value: MESSAGE = 1;
*/
MESSAGE = 1,
/**
* @generated from enum value: MENTION = 2;
*/
MENTION = 2,
/**
* @generated from enum value: REQUEST_TO_JOIN_COMMUNITY = 3;
*/
REQUEST_TO_JOIN_COMMUNITY = 3,
}
// Retrieve enum metadata with: proto3.getEnumType(PushNotification_PushNotificationType)
proto3.util.setEnumType(PushNotification_PushNotificationType, "PushNotification.PushNotificationType", [
{ no: 0, name: "UNKNOWN_PUSH_NOTIFICATION_TYPE" },
{ no: 1, name: "MESSAGE" },
{ no: 2, name: "MENTION" },
{ no: 3, name: "REQUEST_TO_JOIN_COMMUNITY" },
]);
/**
* @generated from message PushNotificationRequest
*/
export class PushNotificationRequest extends Message<PushNotificationRequest> {
/**
* @generated from field: repeated PushNotification requests = 1;
*/
requests: PushNotification[] = [];
/**
* @generated from field: bytes message_id = 2;
*/
messageId = new Uint8Array(0);
constructor(data?: PartialMessage<PushNotificationRequest>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime = proto3;
static readonly typeName = "PushNotificationRequest";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "requests", kind: "message", T: PushNotification, repeated: true },
{ no: 2, name: "message_id", kind: "scalar", T: 12 /* ScalarType.BYTES */ },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): PushNotificationRequest {
return new PushNotificationRequest().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): PushNotificationRequest {
return new PushNotificationRequest().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): PushNotificationRequest {
return new PushNotificationRequest().fromJsonString(jsonString, options);
}
static equals(a: PushNotificationRequest | PlainMessage<PushNotificationRequest> | undefined, b: PushNotificationRequest | PlainMessage<PushNotificationRequest> | undefined): boolean {
return proto3.util.equals(PushNotificationRequest, a, b);
}
}
/**
* @generated from message PushNotificationReport
*/
export class PushNotificationReport extends Message<PushNotificationReport> {
/**
* @generated from field: bool success = 1;
*/
success = false;
/**
* @generated from field: PushNotificationReport.ErrorType error = 2;
*/
error = PushNotificationReport_ErrorType.UNKNOWN_ERROR_TYPE;
/**
* @generated from field: bytes public_key = 3;
*/
publicKey = new Uint8Array(0);
/**
* @generated from field: string installation_id = 4;
*/
installationId = "";
constructor(data?: PartialMessage<PushNotificationReport>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime = proto3;
static readonly typeName = "PushNotificationReport";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "success", kind: "scalar", T: 8 /* ScalarType.BOOL */ },
{ no: 2, name: "error", kind: "enum", T: proto3.getEnumType(PushNotificationReport_ErrorType) },
{ no: 3, name: "public_key", kind: "scalar", T: 12 /* ScalarType.BYTES */ },
{ no: 4, name: "installation_id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): PushNotificationReport {
return new PushNotificationReport().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): PushNotificationReport {
return new PushNotificationReport().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): PushNotificationReport {
return new PushNotificationReport().fromJsonString(jsonString, options);
}
static equals(a: PushNotificationReport | PlainMessage<PushNotificationReport> | undefined, b: PushNotificationReport | PlainMessage<PushNotificationReport> | undefined): boolean {
return proto3.util.equals(PushNotificationReport, a, b);
}
}
/**
* @generated from enum PushNotificationReport.ErrorType
*/
export enum PushNotificationReport_ErrorType {
/**
* @generated from enum value: UNKNOWN_ERROR_TYPE = 0;
*/
UNKNOWN_ERROR_TYPE = 0,
/**
* @generated from enum value: WRONG_TOKEN = 1;
*/
WRONG_TOKEN = 1,
/**
* @generated from enum value: INTERNAL_ERROR = 2;
*/
INTERNAL_ERROR = 2,
/**
* @generated from enum value: NOT_REGISTERED = 3;
*/
NOT_REGISTERED = 3,
}
// Retrieve enum metadata with: proto3.getEnumType(PushNotificationReport_ErrorType)
proto3.util.setEnumType(PushNotificationReport_ErrorType, "PushNotificationReport.ErrorType", [
{ no: 0, name: "UNKNOWN_ERROR_TYPE" },
{ no: 1, name: "WRONG_TOKEN" },
{ no: 2, name: "INTERNAL_ERROR" },
{ no: 3, name: "NOT_REGISTERED" },
]);
/**
* @generated from message PushNotificationResponse
*/
export class PushNotificationResponse extends Message<PushNotificationResponse> {
/**
* @generated from field: bytes message_id = 1;
*/
messageId = new Uint8Array(0);
/**
* @generated from field: repeated PushNotificationReport reports = 2;
*/
reports: PushNotificationReport[] = [];
constructor(data?: PartialMessage<PushNotificationResponse>) {
super();
proto3.util.initPartial(data, this);
}
static readonly runtime = proto3;
static readonly typeName = "PushNotificationResponse";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "message_id", kind: "scalar", T: 12 /* ScalarType.BYTES */ },
{ no: 2, name: "reports", kind: "message", T: PushNotificationReport, repeated: true },
]);
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): PushNotificationResponse {
return new PushNotificationResponse().fromBinary(bytes, options);
}
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): PushNotificationResponse {
return new PushNotificationResponse().fromJson(jsonValue, options);
}
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): PushNotificationResponse {
return new PushNotificationResponse().fromJsonString(jsonString, options);
}
static equals(a: PushNotificationResponse | PlainMessage<PushNotificationResponse> | undefined, b: PushNotificationResponse | PlainMessage<PushNotificationResponse> | undefined): boolean {
return proto3.util.equals(PushNotificationResponse, a, b);
}
}

View File

@ -0,0 +1,42 @@
import { mapCommunity } from './map-community'
import type {
CommunityChat,
CommunityDescription,
} from '../protos/communities_pb'
import type { CommunityInfo } from './map-community'
export type ChannelInfo = {
emoji?: string
displayName: string
description: string
color: string
community: CommunityInfo
}
export function mapChannel(
communityChat: CommunityChat,
communityDescription: CommunityDescription
): ChannelInfo | undefined {
const community = mapCommunity(communityDescription)
if (!community) {
return
}
const { identity } = communityChat
if (!identity) {
return
}
const channelInfo: ChannelInfo = {
emoji: identity.emoji,
displayName: identity.displayName,
description: identity.description,
color: identity.color,
community,
}
return channelInfo
}

View File

@ -0,0 +1,51 @@
import { tags as tagsMap } from './tags'
import type { CommunityDescription } from '../protos/communities_pb'
export type CommunityInfo = {
banner?: Uint8Array
photo?: Uint8Array
displayName: string
description: string
membersCount: number
tags: Array<{
emoji: string
text: string
}>
color: string
}
export function mapCommunity(
communityDescription: CommunityDescription
): CommunityInfo | undefined {
const { identity, tags, members } = communityDescription
if (!identity) {
return
}
const communityInfo: CommunityInfo = {
banner: identity.images.banner?.payload,
photo: identity.images.thumbnail?.payload,
displayName: identity.displayName,
description: identity.description,
membersCount: Object.keys(members).length,
tags: tags.reduce<CommunityInfo['tags']>((tags, nextTag) => {
const emoji = tagsMap[nextTag as keyof typeof tagsMap]
if (!emoji) {
return tags
}
tags.push({
text: nextTag,
emoji,
})
return tags
}, []),
color: identity.color,
}
return communityInfo
}

View File

@ -0,0 +1,32 @@
import { publicKeyToEmojiHash } from '../utils/public-key-to-emoji-hash'
import type { ContactCodeAdvertisement } from '../protos/push-notifications_pb'
export type UserInfo = {
photo?: Uint8Array
displayName: string
description?: string
emojiHash: string
// todo: currently not in protobuf nor in product
// color: string
}
export function mapUser(
contactCodeAdvertisement: ContactCodeAdvertisement,
userPublicKey: string
): UserInfo | undefined {
const { chatIdentity: identity } = contactCodeAdvertisement
if (!identity) {
return
}
const userInfo: UserInfo = {
photo: identity.images.thumbnail?.payload,
displayName: identity.displayName,
description: identity.description,
emojiHash: publicKeyToEmojiHash(userPublicKey),
}
return userInfo
}

View File

@ -0,0 +1,320 @@
import { bytesToHex } from 'ethereum-cryptography/utils'
import { Protocols } from 'js-waku'
import { createLightNode } from 'js-waku/lib/create_waku'
import { PeerDiscoveryStaticPeers } from 'js-waku/lib/peer_discovery_static_list'
import { waitForRemotePeer } from 'js-waku/lib/wait_for_remote_peer'
import { SymDecoder } from 'js-waku/lib/waku_message/version_1'
import { peers } from '../consts/peers'
import {
ApplicationMetadataMessage,
ApplicationMetadataMessage_Type,
} from '../protos/application-metadata-message_pb'
import { CommunityDescription } from '../protos/communities_pb'
import { ProtocolMessage } from '../protos/protocol-message_pb'
import { ContactCodeAdvertisement } from '../protos/push-notifications_pb'
import { compressPublicKey } from '../utils/compress-public-key'
import { generateKeyFromPassword } from '../utils/generate-key-from-password'
import { idToContentTopic } from '../utils/id-to-content-topic'
import { isClockValid } from '../utils/is-clock-valid'
import { payloadToId } from '../utils/payload-to-id'
import { recoverPublicKey } from '../utils/recover-public-key'
import { mapChannel } from './map-channel'
import { mapCommunity } from './map-community'
import { mapUser } from './map-user'
import type { ChannelInfo } from './map-channel'
import type { CommunityInfo } from './map-community'
import type { UserInfo } from './map-user'
import type { WakuLight } from 'js-waku/lib/interfaces'
import type { MessageV1 as WakuMessage } from 'js-waku/lib/waku_message/version_1'
export interface RequestClientOptions {
environment?: 'production' | 'test'
}
class RequestClient {
public waku: WakuLight
/** Cache. */
public readonly wakuMessages: Set<string>
constructor(waku: WakuLight) {
this.waku = waku
this.wakuMessages = new Set()
}
static async start(options: RequestClientOptions): Promise<RequestClient> {
const { environment = 'production' } = options
let waku: WakuLight | undefined
let client: RequestClient | undefined
try {
// Waku
waku = await createLightNode({
defaultBootstrap: false,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
emitSelf: true,
pingKeepAlive: 0,
relayKeepAlive: 0,
libp2p: {
peerDiscovery: [
new PeerDiscoveryStaticPeers(peers[environment], { maxPeers: 1 }),
],
},
})
await waku.start()
await waitForRemotePeer(waku, [Protocols.Store], 10 * 1000)
client = new RequestClient(waku)
} catch (error) {
if (waku) {
await waku.stop()
}
throw error
}
return client
}
public async stop() {
await this.waku.stop()
}
public fetchCommunity = async (
/** Uncompressed */
publicKey: string
): Promise<CommunityInfo | undefined> => {
const communityDescription = await this.fetchCommunityDescription(publicKey)
if (!communityDescription) {
return
}
return mapCommunity(communityDescription)
}
public fetchChannel = async (
/** Compressed */
publicKey: string,
uuid: string
): Promise<ChannelInfo | undefined> => {
const communityDescription = await this.fetchCommunityDescription(publicKey)
if (!communityDescription) {
return
}
const communityChat = communityDescription.chats[uuid]
return mapChannel(communityChat, communityDescription)
}
public fetchUser = async (
/** Uncompressed */
publicKey: string
): Promise<UserInfo | undefined> => {
const contactCodeAdvertisement = await this.fetchContactCodeAdvertisement(
publicKey
)
if (!contactCodeAdvertisement) {
return
}
return mapUser(contactCodeAdvertisement, publicKey)
}
private fetchCommunityDescription = async (
/** Uncompressed */
publicKey: string
): Promise<CommunityDescription | undefined> => {
const contentTopic = idToContentTopic(publicKey)
const symmetricKey = await generateKeyFromPassword(publicKey)
let communityDescription: CommunityDescription | undefined = undefined
await this.waku.store.queryOrderedCallback(
[new SymDecoder(contentTopic, symmetricKey)],
wakuMessage => {
// handle
const message = this.handleWakuMessage(wakuMessage)
if (!message) {
return
}
if (
message.type !== ApplicationMetadataMessage_Type.COMMUNITY_DESCRIPTION
) {
return
}
// decode
const decodedCommunityDescription = CommunityDescription.fromBinary(
message.payload
)
// validate
if (
!isClockValid(
BigInt(decodedCommunityDescription.clock),
message.timestamp
)
) {
return
}
if (publicKey !== `0x${compressPublicKey(message.signerPublicKey)}`) {
return
}
if (!communityDescription) {
communityDescription = decodedCommunityDescription
}
// stop
return true
}
)
return communityDescription
}
private fetchContactCodeAdvertisement = async (
publicKey: string
): Promise<ContactCodeAdvertisement | undefined> => {
const contentTopic = idToContentTopic(`${publicKey}-contact-code`)
const symmetricKey = await generateKeyFromPassword(
`${publicKey}-contact-code`
)
let contactCodeAdvertisement: ContactCodeAdvertisement | undefined =
undefined
await this.waku.store.queryOrderedCallback(
[new SymDecoder(contentTopic, symmetricKey)],
wakuMessage => {
// handle
const message = this.handleWakuMessage(wakuMessage)
if (!message) {
return
}
if (
message.type !==
ApplicationMetadataMessage_Type.CONTACT_CODE_ADVERTISEMENT
) {
return
}
// decode
const decodedContactCode = ContactCodeAdvertisement.fromBinary(
message.payload
)
// validate
if (!decodedContactCode.chatIdentity) {
return
}
if (
!isClockValid(
BigInt(decodedContactCode.chatIdentity.clock),
message.timestamp
)
) {
return
}
if (publicKey !== message.signerPublicKey) {
return
}
if (!contactCodeAdvertisement) {
contactCodeAdvertisement = decodedContactCode
}
// stop
return true
}
)
return contactCodeAdvertisement
}
private handleWakuMessage = (
wakuMessage: WakuMessage
):
| {
timestamp: Date
signerPublicKey: string
type: ApplicationMetadataMessage_Type
payload: Uint8Array
}
| undefined => {
// validate
if (!wakuMessage.payload) {
return
}
if (!wakuMessage.signaturePublicKey) {
return
}
if (!wakuMessage.timestamp) {
return
}
// decode (layers)
let messageToDecode = wakuMessage.payload
let decodedProtocol
try {
decodedProtocol = ProtocolMessage.fromBinary(messageToDecode)
if (decodedProtocol) {
messageToDecode = decodedProtocol.publicMessage
}
} catch {
// eslint-disable-next-line no-empty
}
const decodedMetadata =
ApplicationMetadataMessage.fromBinary(messageToDecode)
if (!decodedMetadata.payload) {
return
}
const signerPublicKeyBytes = recoverPublicKey(
decodedMetadata.signature,
decodedMetadata.payload
)
const messageId = payloadToId(
decodedProtocol?.publicMessage ?? wakuMessage.payload,
signerPublicKeyBytes
)
// already handled
if (this.wakuMessages.has(messageId)) {
return
}
this.wakuMessages.add(messageId)
return {
timestamp: wakuMessage.timestamp,
signerPublicKey: `0x${bytesToHex(signerPublicKeyBytes)}`,
type: decodedMetadata.type,
payload: decodedMetadata.payload,
}
}
}
export async function createRequestClient(
options: RequestClientOptions
): Promise<RequestClient> {
return await RequestClient.start(options)
}
export type { RequestClient }

View File

@ -0,0 +1,54 @@
export const tags = {
Activism: '✊',
Art: '🎨',
Blockchain: '🔗',
'Books & blogs': '📚',
Career: '💼',
Collaboration: '🤝',
Commerce: '🛒',
Culture: '🎎',
DAO: '🚀',
DeFi: '📈',
Design: '🧩',
DIY: '🔨',
Environment: '🌿',
Education: '🎒',
Entertainment: '🍿',
Ethereum: 'Ξ',
Event: '🗓',
Fantasy: '🧙‍♂️',
Fashion: '🧦',
Food: '🌶',
Gaming: '🎮',
Global: '🌍',
Health: '🧠',
Hobby: '📐',
Innovation: '🧪',
Language: '📜',
Lifestyle: '✨',
Local: '📍',
Love: '❤️',
Markets: '💎',
'Movies & TV': '🎞',
Music: '🎶',
News: '🗞',
NFT: '🖼',
'Non-profit': '🙏',
NSFW: '🍆',
Org: '🏢',
Pets: '🐶',
Play: '🎲',
Podcast: '🎙️',
Politics: '🗳️',
Product: '🍱',
Psyche: '🍁',
Privacy: '👻',
Security: '🔒',
Social: '☕',
'Software dev': '👩‍💻',
Sports: '⚽️',
Tech: '📱',
Travel: '🗺',
Vehicles: '🚕',
Web3: '🌐',
}