mirror of
https://github.com/stoatchat/javascript-client-sdk.git
synced 2026-07-20 01:23:33 -04:00
feat: work towards spec compliance
This commit is contained in:
+4
-1
@@ -1,7 +1,9 @@
|
||||
{
|
||||
"name": "revolt.js",
|
||||
"version": "7.0.0-beta.0",
|
||||
"main": "lib/index.js",
|
||||
"main": "lib/cjs/index.js",
|
||||
"module": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"repository": "https://github.com/revoltchat/revolt.js",
|
||||
"author": "Paul Makles <insrt.uk>",
|
||||
"license": "MIT",
|
||||
@@ -20,6 +22,7 @@
|
||||
"dependencies": {
|
||||
"@solid-primitives/map": "^0.4.3",
|
||||
"@solid-primitives/set": "^0.4.3",
|
||||
"eventemitter3": "^5.0.0",
|
||||
"isomorphic-ws": "^5.0.0",
|
||||
"revolt-api": "^0.5.17",
|
||||
"solid-js": "^1.7.2",
|
||||
|
||||
+101
-21
@@ -1,8 +1,11 @@
|
||||
import { API } from "revolt-api";
|
||||
import { Accessor, Setter, createSignal } from "solid-js";
|
||||
|
||||
import { API, Metadata } from "revolt-api";
|
||||
import type { DataLogin, RevoltConfig } from "revolt-api";
|
||||
|
||||
import channelClassFactory from "./classes/Channel";
|
||||
import emojiClassFactory from "./classes/Emoji";
|
||||
import messageClassFactory from "./classes/Message";
|
||||
import serverClassFactory from "./classes/Server";
|
||||
import serverMemberClassFactory from "./classes/ServerMember";
|
||||
import userClassFactory from "./classes/User";
|
||||
@@ -11,28 +14,24 @@ import { EventClient, createEventClient } from "./events/client";
|
||||
// eslint-disable-next-line
|
||||
type Obj<T extends (...args: any) => any> = InstanceType<ReturnType<T>>;
|
||||
|
||||
export type Emoji = Obj<typeof emojiClassFactory>;
|
||||
export type Channel = Obj<typeof channelClassFactory>;
|
||||
export type Emoji = Obj<typeof emojiClassFactory>;
|
||||
export type Message = Obj<typeof messageClassFactory>;
|
||||
export type Server = Obj<typeof serverClassFactory>;
|
||||
export type ServerMember = Obj<typeof serverMemberClassFactory>;
|
||||
export type User = Obj<typeof userClassFactory>;
|
||||
export type Session = { token: string } | string;
|
||||
export type Session = { token: string; user_id: string } | string;
|
||||
|
||||
/**
|
||||
* Revolt.js Client
|
||||
*/
|
||||
export class Client {
|
||||
#Emoji = emojiClassFactory(this);
|
||||
#Channel = channelClassFactory(this);
|
||||
#User = userClassFactory(this);
|
||||
#Server = serverClassFactory(this);
|
||||
#ServerMember = serverMemberClassFactory(this);
|
||||
|
||||
readonly emojis = this.#Emoji;
|
||||
readonly channels = this.#Channel;
|
||||
readonly users = this.#User;
|
||||
readonly servers = this.#Server;
|
||||
readonly serverMembers = this.#ServerMember;
|
||||
readonly channels;
|
||||
readonly emojis;
|
||||
readonly messages;
|
||||
readonly users;
|
||||
readonly servers;
|
||||
readonly serverMembers;
|
||||
|
||||
readonly api: API;
|
||||
readonly baseURL: string;
|
||||
@@ -40,17 +39,32 @@ export class Client {
|
||||
|
||||
configuration: RevoltConfig | undefined;
|
||||
session: Session | undefined;
|
||||
user: User | undefined;
|
||||
|
||||
readonly ready: Accessor<boolean>;
|
||||
#setReady: Setter<boolean>;
|
||||
|
||||
/**
|
||||
* Create Revolt.js Client
|
||||
*/
|
||||
constructor(baseURL: string) {
|
||||
this.baseURL = baseURL;
|
||||
constructor(baseURL?: string) {
|
||||
this.baseURL = baseURL ?? "https://api.revolt.chat";
|
||||
this.api = new API({
|
||||
baseURL,
|
||||
});
|
||||
|
||||
this.events = createEventClient(1);
|
||||
|
||||
const [ready, setReady] = createSignal(false);
|
||||
this.ready = ready;
|
||||
this.#setReady = setReady;
|
||||
|
||||
this.channels = channelClassFactory(this);
|
||||
this.emojis = emojiClassFactory(this);
|
||||
this.messages = messageClassFactory(this);
|
||||
this.users = userClassFactory(this);
|
||||
this.servers = serverClassFactory(this);
|
||||
this.serverMembers = serverMemberClassFactory(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,27 +76,31 @@ export class Client {
|
||||
if (event.type === "Ready") {
|
||||
console.time("load users");
|
||||
for (const user of event.users) {
|
||||
new this.#User(user._id, user);
|
||||
const u = new this.users(user._id, user);
|
||||
|
||||
if (u.relationship === "User") {
|
||||
this.user = u;
|
||||
}
|
||||
}
|
||||
console.timeEnd("load users");
|
||||
console.time("load servers");
|
||||
for (const server of event.servers) {
|
||||
new this.#Server(server._id, server);
|
||||
new this.servers(server._id, server);
|
||||
}
|
||||
console.timeEnd("load servers");
|
||||
console.time("load memberships");
|
||||
for (const member of event.members) {
|
||||
new this.#ServerMember(member._id, member);
|
||||
new this.serverMembers(member._id, member);
|
||||
}
|
||||
console.timeEnd("load memberships");
|
||||
console.time("load channels");
|
||||
for (const channel of event.channels) {
|
||||
new this.#Channel(channel._id, channel);
|
||||
new this.channels(channel._id, channel);
|
||||
}
|
||||
console.timeEnd("load channels");
|
||||
console.time("load emojis");
|
||||
for (const emoji of event.emojis) {
|
||||
new this.#Emoji(emoji._id, emoji);
|
||||
new this.emojis(emoji._id, emoji);
|
||||
}
|
||||
console.timeEnd("load emojis");
|
||||
|
||||
@@ -100,6 +118,8 @@ export class Client {
|
||||
this.serverMembers.get({ server: lounge.id, user: lounge.owner!.id })
|
||||
?.joinedAt
|
||||
);
|
||||
|
||||
this.#setReady(true);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -171,4 +191,64 @@ export class Client {
|
||||
this.#updateHeaders();
|
||||
this.connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a URL to a given file with given options.
|
||||
* @param attachment Partial of attachment object
|
||||
* @param options Optional query parameters to modify object
|
||||
* @param allowAnimation Returns GIF if applicable, no operations occur on image
|
||||
* @param fallback Fallback URL
|
||||
* @returns Generated URL or nothing
|
||||
*/
|
||||
generateFileURL(
|
||||
attachment?: {
|
||||
tag: string;
|
||||
_id: string;
|
||||
content_type?: string;
|
||||
metadata?: Metadata;
|
||||
},
|
||||
...args: FileArgs
|
||||
) {
|
||||
const [options, allowAnimation, fallback] = args;
|
||||
|
||||
const autumn = this.configuration?.features.autumn;
|
||||
if (!autumn?.enabled) return fallback;
|
||||
if (!attachment) return fallback;
|
||||
|
||||
const { tag, _id, content_type, metadata } = attachment;
|
||||
|
||||
// TODO: server-side
|
||||
if (metadata?.type === "Image") {
|
||||
if (
|
||||
Math.min(metadata.width, metadata.height) <= 0 ||
|
||||
(content_type === "image/gif" &&
|
||||
Math.max(metadata.width, metadata.height) >= 4096)
|
||||
)
|
||||
return fallback;
|
||||
}
|
||||
|
||||
let query = "";
|
||||
if (options) {
|
||||
if (!allowAnimation || content_type !== "image/gif") {
|
||||
query =
|
||||
"?" +
|
||||
Object.keys(options)
|
||||
.map((k) => `${k}=${options[k as keyof FileArgs[0]]}`)
|
||||
.join("&");
|
||||
}
|
||||
}
|
||||
|
||||
return `${autumn.url}/${tag}/${_id}${query}`;
|
||||
}
|
||||
}
|
||||
|
||||
export type FileArgs = [
|
||||
options?: {
|
||||
max_side?: number;
|
||||
size?: number;
|
||||
width?: number;
|
||||
height?: number;
|
||||
},
|
||||
allowAnimation?: boolean,
|
||||
fallback?: string
|
||||
];
|
||||
|
||||
+168
-10
@@ -1,7 +1,9 @@
|
||||
import { ReactiveMap } from "@solid-primitives/map";
|
||||
import type { Channel as ApiChannel } from "revolt-api";
|
||||
import { decodeTime } from "ulid";
|
||||
|
||||
import { Client } from "../Client";
|
||||
import { Client, FileArgs } from "../Client";
|
||||
import { hydrate } from "../hydration";
|
||||
import { HydratedChannel } from "../hydration/channel";
|
||||
import { ObjectStorage } from "../storage/ObjectStorage";
|
||||
|
||||
@@ -11,17 +13,86 @@ export default (client: Client) =>
|
||||
*/
|
||||
class Channel {
|
||||
static #storage = new ObjectStorage<HydratedChannel>();
|
||||
static #objects: Record<string, Channel> = {};
|
||||
|
||||
static {
|
||||
client.events.on("event", (event) => {
|
||||
switch (event.type) {
|
||||
case "ChannelUpdate": {
|
||||
this.#storage.set(event.id, hydrate("channel", event.data));
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// * Object Map Definition
|
||||
static #objects = new ReactiveMap<string, InstanceType<typeof this>>();
|
||||
|
||||
/**
|
||||
* Get an existing Channel
|
||||
* @param id Channel ID
|
||||
* @returns Channel
|
||||
* Get an existing object
|
||||
* @param id ID
|
||||
* @returns Object
|
||||
*/
|
||||
static get(id: string): Channel | undefined {
|
||||
return Channel.#objects[id];
|
||||
static get(id: string): InstanceType<typeof this> | undefined {
|
||||
return this.#objects.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of stored objects
|
||||
* @returns Size
|
||||
*/
|
||||
static size() {
|
||||
return this.#objects.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterable of keys in the map
|
||||
* @returns Iterable
|
||||
*/
|
||||
static keys() {
|
||||
return this.#objects.keys();
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterable of values in the map
|
||||
* @returns Iterable
|
||||
*/
|
||||
static values() {
|
||||
return this.#objects.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* List of values in the map
|
||||
* @returns List
|
||||
*/
|
||||
static toList() {
|
||||
return [...this.#objects.values()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterable of key, value pairs in the map
|
||||
* @returns Iterable
|
||||
*/
|
||||
static entries() {
|
||||
return this.#objects.entries();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a provided function over each key, value pair in the map
|
||||
* @param cb Callback for each pair
|
||||
* @returns Iterable
|
||||
*/
|
||||
static forEach(
|
||||
cb: (
|
||||
value: InstanceType<typeof this>,
|
||||
key: string,
|
||||
map: ReactiveMap<string, InstanceType<typeof this>>
|
||||
) => void
|
||||
) {
|
||||
return this.#objects.forEach(cb);
|
||||
}
|
||||
// * End Object Map Definition
|
||||
|
||||
/**
|
||||
* Fetch channel by ID
|
||||
* @param id ID
|
||||
@@ -42,9 +113,13 @@ export default (client: Client) =>
|
||||
* @param id Channel Id
|
||||
*/
|
||||
constructor(id: string, data?: ApiChannel) {
|
||||
Channel.#storage.hydrate(id, "channel", data);
|
||||
Channel.#objects[id] = this;
|
||||
this.id = id;
|
||||
Channel.#storage.hydrate(id, "channel", data);
|
||||
Channel.#objects.set(id, this);
|
||||
}
|
||||
|
||||
updateSomething() {
|
||||
Channel.#storage.set(this.id, "name", "troling");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,6 +173,22 @@ export default (client: Client) =>
|
||||
.recipientIds.map((id) => client.users.get(id)!);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find recipient of this DM
|
||||
*/
|
||||
get recipient() {
|
||||
return this.type === "DirectMessage"
|
||||
? this.recipients.find((user) => user.id !== client.user!.id)
|
||||
: undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* User ID
|
||||
*/
|
||||
get userId() {
|
||||
return Channel.#storage.get(this.id).userId!;
|
||||
}
|
||||
|
||||
/**
|
||||
* User this channel belongs to
|
||||
*/
|
||||
@@ -105,6 +196,13 @@ export default (client: Client) =>
|
||||
return client.users.get(Channel.#storage.get(this.id).userId!);
|
||||
}
|
||||
|
||||
/**
|
||||
* Owner ID
|
||||
*/
|
||||
get ownerId() {
|
||||
return Channel.#storage.get(this.id).ownerId!;
|
||||
}
|
||||
|
||||
/**
|
||||
* Owner of the group
|
||||
*/
|
||||
@@ -112,11 +210,18 @@ export default (client: Client) =>
|
||||
return client.users.get(Channel.#storage.get(this.id).ownerId!);
|
||||
}
|
||||
|
||||
/**
|
||||
* Server ID
|
||||
*/
|
||||
get serverId() {
|
||||
return Channel.#storage.get(this.id).serverId!;
|
||||
}
|
||||
|
||||
/**
|
||||
* Server this channel is in
|
||||
*/
|
||||
get server() {
|
||||
return client.users.get(Channel.#storage.get(this.id).serverId!);
|
||||
return client.servers.get(Channel.#storage.get(this.id).serverId!);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,5 +259,58 @@ export default (client: Client) =>
|
||||
return Channel.#storage.get(this.id).lastMessageId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Time when the last message was sent
|
||||
*/
|
||||
get lastMessageAt() {
|
||||
return this.lastMessageId
|
||||
? new Date(decodeTime(this.lastMessageId))
|
||||
: undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Time when the channel was last updated (either created or a message was sent)
|
||||
*/
|
||||
get updatedAt() {
|
||||
return this.lastMessageAt ?? this.createdAt;
|
||||
}
|
||||
|
||||
// TODO: lastMessage
|
||||
|
||||
get unread() {
|
||||
return false;
|
||||
}
|
||||
|
||||
get mentions() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* URL to the channel icon
|
||||
*/
|
||||
get iconURL() {
|
||||
return client.generateFileURL(this.icon ?? this.recipient?.avatar, {
|
||||
max_side: 256,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* URL to a small variant of the channel icon
|
||||
*/
|
||||
get smallIconURL() {
|
||||
return client.generateFileURL(this.icon ?? this.recipient?.avatar, {
|
||||
max_side: 64,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* URL to the animated channel icon
|
||||
*/
|
||||
get animatedIconURL() {
|
||||
return client.generateFileURL(
|
||||
this.icon ?? this.recipient?.avatar,
|
||||
{ max_side: 256 },
|
||||
true
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
+67
-8
@@ -1,3 +1,4 @@
|
||||
import { ReactiveMap } from "@solid-primitives/map";
|
||||
import type { Emoji as ApiEmoji } from "revolt-api";
|
||||
import { decodeTime } from "ulid";
|
||||
|
||||
@@ -11,17 +12,75 @@ export default (client: Client) =>
|
||||
*/
|
||||
class Emoji {
|
||||
static #storage = new ObjectStorage<HydratedEmoji>();
|
||||
static #objects: Record<string, Emoji> = {};
|
||||
|
||||
// * Object Map Definition
|
||||
static #objects = new ReactiveMap<string, InstanceType<typeof this>>();
|
||||
|
||||
/**
|
||||
* Get an existing Emoji
|
||||
* @param id Emoji ID
|
||||
* @returns Emoji
|
||||
* Get an existing object
|
||||
* @param id ID
|
||||
* @returns Object
|
||||
*/
|
||||
static get(id: string): Emoji | undefined {
|
||||
return Emoji.#objects[id];
|
||||
static get(id: string): InstanceType<typeof this> | undefined {
|
||||
return this.#objects.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of stored objects
|
||||
* @returns Size
|
||||
*/
|
||||
static size() {
|
||||
return this.#objects.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterable of keys in the map
|
||||
* @returns Iterable
|
||||
*/
|
||||
static keys() {
|
||||
return this.#objects.keys();
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterable of values in the map
|
||||
* @returns Iterable
|
||||
*/
|
||||
static values() {
|
||||
return this.#objects.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* List of values in the map
|
||||
* @returns List
|
||||
*/
|
||||
static toList() {
|
||||
return [...this.#objects.values()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterable of key, value pairs in the map
|
||||
* @returns Iterable
|
||||
*/
|
||||
static entries() {
|
||||
return this.#objects.entries();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a provided function over each key, value pair in the map
|
||||
* @param cb Callback for each pair
|
||||
* @returns Iterable
|
||||
*/
|
||||
static forEach(
|
||||
cb: (
|
||||
value: InstanceType<typeof this>,
|
||||
key: string,
|
||||
map: ReactiveMap<string, InstanceType<typeof this>>
|
||||
) => void
|
||||
) {
|
||||
return this.#objects.forEach(cb);
|
||||
}
|
||||
// * End Object Map Definition
|
||||
|
||||
/**
|
||||
* Fetch emoji by ID
|
||||
* @param id ID
|
||||
@@ -42,9 +101,9 @@ export default (client: Client) =>
|
||||
* @param id Emoji Id
|
||||
*/
|
||||
constructor(id: string, data?: ApiEmoji) {
|
||||
Emoji.#storage.hydrate(id, "emoji", data);
|
||||
Emoji.#objects[id] = this;
|
||||
this.id = id;
|
||||
Emoji.#storage.hydrate(id, "emoji", data);
|
||||
Emoji.#objects.set(id, this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+81
-8
@@ -1,3 +1,4 @@
|
||||
import { ReactiveMap } from "@solid-primitives/map";
|
||||
import type { Message as ApiMessage } from "revolt-api";
|
||||
import { decodeTime } from "ulid";
|
||||
|
||||
@@ -11,17 +12,75 @@ export default (client: Client) =>
|
||||
*/
|
||||
class Message {
|
||||
static #storage = new ObjectStorage<HydratedMessage>();
|
||||
static #objects: Record<string, Message> = {};
|
||||
|
||||
// * Object Map Definition
|
||||
static #objects = new ReactiveMap<string, InstanceType<typeof this>>();
|
||||
|
||||
/**
|
||||
* Get an existing Message
|
||||
* @param id Message ID
|
||||
* @returns Message
|
||||
* Get an existing object
|
||||
* @param id ID
|
||||
* @returns Object
|
||||
*/
|
||||
static get(id: string): Message | undefined {
|
||||
return Message.#objects[id];
|
||||
static get(id: string): InstanceType<typeof this> | undefined {
|
||||
return this.#objects.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of stored objects
|
||||
* @returns Size
|
||||
*/
|
||||
static size() {
|
||||
return this.#objects.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterable of keys in the map
|
||||
* @returns Iterable
|
||||
*/
|
||||
static keys() {
|
||||
return this.#objects.keys();
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterable of values in the map
|
||||
* @returns Iterable
|
||||
*/
|
||||
static values() {
|
||||
return this.#objects.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* List of values in the map
|
||||
* @returns List
|
||||
*/
|
||||
static toList() {
|
||||
return [...this.#objects.values()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterable of key, value pairs in the map
|
||||
* @returns Iterable
|
||||
*/
|
||||
static entries() {
|
||||
return this.#objects.entries();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a provided function over each key, value pair in the map
|
||||
* @param cb Callback for each pair
|
||||
* @returns Iterable
|
||||
*/
|
||||
static forEach(
|
||||
cb: (
|
||||
value: InstanceType<typeof this>,
|
||||
key: string,
|
||||
map: ReactiveMap<string, InstanceType<typeof this>>
|
||||
) => void
|
||||
) {
|
||||
return this.#objects.forEach(cb);
|
||||
}
|
||||
// * End Object Map Definition
|
||||
|
||||
/**
|
||||
* Fetch message by ID
|
||||
* @param channelId Channel ID
|
||||
@@ -48,9 +107,9 @@ export default (client: Client) =>
|
||||
* @param id Message Id
|
||||
*/
|
||||
constructor(id: string, data?: ApiMessage) {
|
||||
Message.#storage.hydrate(id, "message", data);
|
||||
Message.#objects[id] = this;
|
||||
this.id = id;
|
||||
Message.#storage.hydrate(id, "message", data);
|
||||
Message.#objects.set(id, this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,6 +126,13 @@ export default (client: Client) =>
|
||||
return Message.#storage.get(this.id).nonce;
|
||||
}
|
||||
|
||||
/**
|
||||
* Id of channel this message was sent in
|
||||
*/
|
||||
get channelId() {
|
||||
return Message.#storage.get(this.id).channelId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Channel this message was sent in
|
||||
*/
|
||||
@@ -74,6 +140,13 @@ export default (client: Client) =>
|
||||
return client.channels.get(Message.#storage.get(this.id).channelId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Id of user this message was sent by
|
||||
*/
|
||||
get authorId() {
|
||||
return Message.#storage.get(this.id).authorId;
|
||||
}
|
||||
|
||||
/**
|
||||
* User this message was sent by
|
||||
*/
|
||||
|
||||
+98
-8
@@ -1,3 +1,4 @@
|
||||
import { ReactiveMap } from "@solid-primitives/map";
|
||||
import type { Server as ApiServer, Category } from "revolt-api";
|
||||
import { decodeTime } from "ulid";
|
||||
|
||||
@@ -11,17 +12,75 @@ export default (client: Client) =>
|
||||
*/
|
||||
class Server {
|
||||
static #storage = new ObjectStorage<HydratedServer>();
|
||||
static #objects: Record<string, Server> = {};
|
||||
|
||||
// * Object Map Definition
|
||||
static #objects = new ReactiveMap<string, InstanceType<typeof this>>();
|
||||
|
||||
/**
|
||||
* Get an existing Server
|
||||
* @param id Server ID
|
||||
* @returns Server
|
||||
* Get an existing object
|
||||
* @param id ID
|
||||
* @returns Object
|
||||
*/
|
||||
static get(id: string): Server | undefined {
|
||||
return Server.#objects[id];
|
||||
static get(id: string): InstanceType<typeof this> | undefined {
|
||||
return this.#objects.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of stored objects
|
||||
* @returns Size
|
||||
*/
|
||||
static size() {
|
||||
return this.#objects.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterable of keys in the map
|
||||
* @returns Iterable
|
||||
*/
|
||||
static keys() {
|
||||
return this.#objects.keys();
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterable of values in the map
|
||||
* @returns Iterable
|
||||
*/
|
||||
static values() {
|
||||
return this.#objects.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* List of values in the map
|
||||
* @returns List
|
||||
*/
|
||||
static toList() {
|
||||
return [...this.#objects.values()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterable of key, value pairs in the map
|
||||
* @returns Iterable
|
||||
*/
|
||||
static entries() {
|
||||
return this.#objects.entries();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a provided function over each key, value pair in the map
|
||||
* @param cb Callback for each pair
|
||||
* @returns Iterable
|
||||
*/
|
||||
static forEach(
|
||||
cb: (
|
||||
value: InstanceType<typeof this>,
|
||||
key: string,
|
||||
map: ReactiveMap<string, InstanceType<typeof this>>
|
||||
) => void
|
||||
) {
|
||||
return this.#objects.forEach(cb);
|
||||
}
|
||||
// * End Object Map Definition
|
||||
|
||||
/**
|
||||
* Fetch server by ID
|
||||
* @param id ID
|
||||
@@ -42,9 +101,9 @@ export default (client: Client) =>
|
||||
* @param id Server Id
|
||||
*/
|
||||
constructor(id: string, data?: ApiServer) {
|
||||
Server.#storage.hydrate(id, "server", data);
|
||||
Server.#objects[id] = this;
|
||||
this.id = id;
|
||||
Server.#storage.hydrate(id, "server", data);
|
||||
Server.#objects.set(id, this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -232,4 +291,35 @@ export default (client: Client) =>
|
||||
.sort((a, b) => (a.rank || 0) - (b.rank || 0))
|
||||
: [];
|
||||
}
|
||||
|
||||
get unread() {
|
||||
return false;
|
||||
}
|
||||
|
||||
get mentions() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* URL to the server's icon
|
||||
*/
|
||||
get iconURL() {
|
||||
return client.generateFileURL(this.icon, { max_side: 256 });
|
||||
}
|
||||
|
||||
/**
|
||||
* URL to the server's animated icon
|
||||
*/
|
||||
get animatedIconURL() {
|
||||
return client.generateFileURL(this.icon, { max_side: 256 }, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* URL to the server's banner
|
||||
*/
|
||||
get bannerURL() {
|
||||
return client.generateFileURL(this.banner, {
|
||||
max_side: 256,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { ReactiveMap } from "@solid-primitives/map";
|
||||
import type { Member as ApiMember, MemberCompositeKey } from "revolt-api";
|
||||
|
||||
import { Client } from "../Client";
|
||||
@@ -19,7 +20,9 @@ export default (client: Client) =>
|
||||
*/
|
||||
class ServerMember {
|
||||
static #storage = new ObjectStorage<HydratedServerMember>();
|
||||
static #objects: Record<string, ServerMember> = {};
|
||||
|
||||
// * Object Map Definition
|
||||
static #objects = new ReactiveMap<string, InstanceType<typeof this>>();
|
||||
|
||||
/**
|
||||
* Deterministic conversion of member composite key to string ID
|
||||
@@ -34,9 +37,65 @@ export default (client: Client) =>
|
||||
* @returns Member
|
||||
*/
|
||||
static get(id: MemberCompositeKey): ServerMember | undefined {
|
||||
return ServerMember.#objects[key(id)];
|
||||
return ServerMember.#objects.get(key(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of stored objects
|
||||
* @returns Size
|
||||
*/
|
||||
static size() {
|
||||
return this.#objects.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterable of keys in the map
|
||||
* @returns Iterable
|
||||
*/
|
||||
static keys() {
|
||||
return this.#objects.keys();
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterable of values in the map
|
||||
* @returns Iterable
|
||||
*/
|
||||
static values() {
|
||||
return this.#objects.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* List of values in the map
|
||||
* @returns List
|
||||
*/
|
||||
static toList() {
|
||||
return [...this.#objects.values()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterable of key, value pairs in the map
|
||||
* @returns Iterable
|
||||
*/
|
||||
static entries() {
|
||||
return this.#objects.entries();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a provided function over each key, value pair in the map
|
||||
* @param cb Callback for each pair
|
||||
* @returns Iterable
|
||||
*/
|
||||
static forEach(
|
||||
cb: (
|
||||
value: InstanceType<typeof this>,
|
||||
key: string,
|
||||
map: ReactiveMap<string, InstanceType<typeof this>>
|
||||
) => void
|
||||
) {
|
||||
return this.#objects.forEach(cb);
|
||||
}
|
||||
// * End Object Map Definition
|
||||
|
||||
/**
|
||||
* Fetch member by ID
|
||||
* @param id Member ID
|
||||
@@ -62,7 +121,7 @@ export default (client: Client) =>
|
||||
*/
|
||||
constructor(id: MemberCompositeKey, data?: ApiMember) {
|
||||
ServerMember.#storage.hydrate(key(id), "serverMember", data);
|
||||
ServerMember.#objects[key(id)] = this;
|
||||
ServerMember.#objects.set(key(id), this);
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
|
||||
+101
-10
@@ -1,7 +1,8 @@
|
||||
import { ReactiveMap } from "@solid-primitives/map";
|
||||
import type { User as ApiUser } from "revolt-api";
|
||||
import { decodeTime } from "ulid";
|
||||
|
||||
import { Client } from "../Client";
|
||||
import { Client, FileArgs } from "../Client";
|
||||
import { HydratedUser } from "../hydration/user";
|
||||
import { ObjectStorage } from "../storage/ObjectStorage";
|
||||
|
||||
@@ -11,24 +12,82 @@ export default (client: Client) =>
|
||||
*/
|
||||
class User {
|
||||
static #storage = new ObjectStorage<HydratedUser>();
|
||||
static #objects: Record<string, User> = {};
|
||||
|
||||
// * Object Map Definition
|
||||
static #objects = new ReactiveMap<string, InstanceType<typeof this>>();
|
||||
|
||||
/**
|
||||
* Get an existing User
|
||||
* @param id User ID
|
||||
* @returns User
|
||||
* Get an existing object
|
||||
* @param id ID
|
||||
* @returns Object
|
||||
*/
|
||||
static get(id: string): User | undefined {
|
||||
return User.#objects[id];
|
||||
static get(id: string): InstanceType<typeof this> | undefined {
|
||||
return this.#objects.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of stored objects
|
||||
* @returns Size
|
||||
*/
|
||||
static size() {
|
||||
return this.#objects.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterable of keys in the map
|
||||
* @returns Iterable
|
||||
*/
|
||||
static keys() {
|
||||
return this.#objects.keys();
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterable of values in the map
|
||||
* @returns Iterable
|
||||
*/
|
||||
static values() {
|
||||
return this.#objects.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* List of values in the map
|
||||
* @returns List
|
||||
*/
|
||||
static toList() {
|
||||
return [...this.#objects.values()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterable of key, value pairs in the map
|
||||
* @returns Iterable
|
||||
*/
|
||||
static entries() {
|
||||
return this.#objects.entries();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a provided function over each key, value pair in the map
|
||||
* @param cb Callback for each pair
|
||||
* @returns Iterable
|
||||
*/
|
||||
static forEach(
|
||||
cb: (
|
||||
value: InstanceType<typeof this>,
|
||||
key: string,
|
||||
map: ReactiveMap<string, InstanceType<typeof this>>
|
||||
) => void
|
||||
) {
|
||||
return this.#objects.forEach(cb);
|
||||
}
|
||||
// * End Object Map Definition
|
||||
|
||||
/**
|
||||
* Fetch user by ID
|
||||
* @param id ID
|
||||
* @returns User
|
||||
*/
|
||||
static async fetch(id: string): Promise<User | undefined> {
|
||||
const user = User.get(id);
|
||||
const user = this.get(id);
|
||||
if (user) return user;
|
||||
|
||||
const data = await client.api.get(`/users/${id as ""}`);
|
||||
@@ -42,9 +101,9 @@ export default (client: Client) =>
|
||||
* @param id User Id
|
||||
*/
|
||||
constructor(id: string, data?: ApiUser) {
|
||||
User.#storage.hydrate(id, "user", data);
|
||||
User.#objects[id] = this;
|
||||
this.id = id;
|
||||
User.#storage.hydrate(id, "user", data);
|
||||
User.#objects.set(id, this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,4 +175,36 @@ export default (client: Client) =>
|
||||
get bot() {
|
||||
return User.#storage.get(this.id).bot;
|
||||
}
|
||||
|
||||
/**
|
||||
* URL to the user's default avatar
|
||||
*/
|
||||
get defaultAvatarURL() {
|
||||
return `${client.baseURL}/users/${this.id}/default_avatar`;
|
||||
}
|
||||
|
||||
/**
|
||||
* URL to the user's avatar
|
||||
*/
|
||||
get avatarURL() {
|
||||
return this.#generateAvatarURL({ max_side: 256 });
|
||||
}
|
||||
|
||||
/**
|
||||
* URL to the user's animated avatar
|
||||
*/
|
||||
get animatedAvatarURL() {
|
||||
return this.#generateAvatarURL({ max_side: 256 }, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate avatar URL
|
||||
* @param args File args
|
||||
* @returns URL
|
||||
*/
|
||||
#generateAvatarURL(...args: FileArgs) {
|
||||
return (
|
||||
client.generateFileURL(this.avatar, ...args) ?? this.defaultAvatarURL
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Accessor, Setter, createSignal } from "solid-js";
|
||||
|
||||
import EventEmitter from "events";
|
||||
import EventEmitter from "eventemitter3";
|
||||
import WebSocket from "isomorphic-ws";
|
||||
import type TypedEmitter from "typed-emitter";
|
||||
|
||||
@@ -37,7 +37,7 @@ class Client<
|
||||
#heartbeatInterval: number;
|
||||
#pongTimeout: number;
|
||||
|
||||
#state: Accessor<ConnectionState>;
|
||||
readonly state: Accessor<ConnectionState>;
|
||||
#setStateSetter: Setter<ConnectionState>;
|
||||
|
||||
#socket: WebSocket | undefined;
|
||||
@@ -65,7 +65,7 @@ class Client<
|
||||
this.#pongTimeout = pongTimeout;
|
||||
|
||||
const [state, setState] = createSignal(ConnectionState.Idle);
|
||||
this.#state = state;
|
||||
this.state = state;
|
||||
this.#setStateSetter = setState;
|
||||
|
||||
this.disconnect = this.disconnect.bind(this);
|
||||
@@ -161,7 +161,7 @@ class Client<
|
||||
return;
|
||||
}
|
||||
|
||||
switch (this.#state()) {
|
||||
switch (this.state()) {
|
||||
case ConnectionState.Connecting:
|
||||
if (event.type === "Authenticated") {
|
||||
// no-op
|
||||
@@ -182,7 +182,7 @@ class Client<
|
||||
default:
|
||||
throw `Unreachable code. Received ${
|
||||
event.type
|
||||
} in state ${this.#state()}.`;
|
||||
} in state ${this.state()}.`;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,5 +217,5 @@ export function createEventClient<
|
||||
transportFormat,
|
||||
heartbeatInterval,
|
||||
pongTimeout
|
||||
) as EventClient<T>;
|
||||
) as never as EventClient<T>;
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ type ExtractOutput<T> = T extends Hydrate<any, infer O> ? O : never;
|
||||
*/
|
||||
export function hydrate<T extends keyof Hydrators>(
|
||||
type: T,
|
||||
input: ExtractInput<Hydrators[T]>
|
||||
input: Partial<ExtractInput<Hydrators[T]>>
|
||||
) {
|
||||
return hydrateInternal(hydrators[type] as never, input) as ExtractOutput<
|
||||
Hydrators[T]
|
||||
|
||||
+4
-2
@@ -1,5 +1,6 @@
|
||||
export {
|
||||
Client,
|
||||
export { Client } from "./Client";
|
||||
|
||||
export type {
|
||||
Emoji,
|
||||
Channel,
|
||||
Server,
|
||||
@@ -8,4 +9,5 @@ export {
|
||||
Session,
|
||||
} from "./Client";
|
||||
|
||||
export * from "./lib/regex";
|
||||
export * as API from "revolt-api";
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Regular expression for mentions.
|
||||
*/
|
||||
export const RE_MENTIONS = /<@([A-z0-9]{26})>/g;
|
||||
|
||||
/**
|
||||
* Regular expression for spoilers.
|
||||
*/
|
||||
export const RE_SPOILER = /!!.+!!/g;
|
||||
+10
-105
@@ -1,109 +1,14 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig to read more about this file */
|
||||
|
||||
/* Projects */
|
||||
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
|
||||
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
||||
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
|
||||
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
|
||||
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
||||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||
|
||||
/* Language and Environment */
|
||||
"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
|
||||
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
||||
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
|
||||
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
|
||||
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
||||
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
||||
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
||||
|
||||
/* Modules */
|
||||
"module": "commonjs" /* Specify what module code is generated. */,
|
||||
"rootDir": "./src" /* Specify the root folder within your source files. */,
|
||||
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
||||
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
|
||||
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
|
||||
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
|
||||
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
|
||||
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
|
||||
// "resolveJsonModule": true, /* Enable importing .json files. */
|
||||
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
|
||||
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
|
||||
|
||||
/* JavaScript Support */
|
||||
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
|
||||
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
|
||||
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
|
||||
|
||||
/* Emit */
|
||||
"declaration": true /* Generate .d.ts files from TypeScript and JavaScript files in your project. */,
|
||||
"declarationMap": true /* Create sourcemaps for d.ts files. */,
|
||||
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
||||
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
||||
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
||||
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
|
||||
"outDir": "./lib" /* Specify an output folder for all emitted files. */,
|
||||
// "removeComments": true, /* Disable emitting comments. */
|
||||
// "noEmit": true, /* Disable emitting files from a compilation. */
|
||||
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
||||
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
|
||||
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
||||
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
||||
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
||||
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
||||
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
|
||||
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
|
||||
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
||||
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
|
||||
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
||||
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
|
||||
|
||||
/* Interop Constraints */
|
||||
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
||||
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
||||
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
|
||||
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
||||
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
|
||||
|
||||
/* Type Checking */
|
||||
"strict": true /* Enable all strict type-checking options. */,
|
||||
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
|
||||
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
||||
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
|
||||
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
||||
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
|
||||
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
|
||||
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
||||
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
|
||||
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
|
||||
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
||||
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
||||
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
|
||||
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
||||
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
|
||||
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
||||
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
||||
|
||||
/* Completeness */
|
||||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
"target": "es2016",
|
||||
"module": "commonjs",
|
||||
"rootDir": "./src",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"outDir": "./lib/cjs",
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user