Files
discord.js/packages/structures/src/invites/Invite.ts
Qjuh 3cff4d7412 feat: @discordjs/structures (#10900)
* chore: init /structures

* feat: base structure

* feat: initial structures design attempt

* refactor(Structure): use unknown to store in kData

* feat(Structure): add Invite

refactor(Structure): patch to _patch

* refactor: symbol names and override location

* fix: don't possibly return 0 if discord borks

Co-authored-by: Synbulat Biishev <signin@syjalo.dev>

* refactor: use getter value instead of api

Co-authored-by: Synbulat Biishev <signin@syjalo.dev>

* refactor: cache createdTimestamp value

Co-authored-by: Qjuh <76154676+Qjuh@users.noreply.github.com>

* docs: better docs for what's done so far

* feat: add Mixin

* refactor(User): remove bitfield getters and add displayName

* feat(structures): add Connection

* feat(structures): add Channel base

* refactor(Mixin): trace prototype chain, allow construction

* fix(structures): fix mixin behavior

* fix(structures): data optimization call behavior from perf testing

* feat: channel mixins

* chore: update deps

* feat: channels and mixins

* chore: more typeguard tests

* fix: tests and some other issues

* feat: add ChannelWebhookMixin

* fix: more tests

* chore: tests and docs

* chore: docs

* fix: remove unneccessary omitted

* chore: apply code suggestions

* refactor: change how extended invite works

* fix: type imports

* Apply suggestions from code review

Co-authored-by: Almeida <github@almeidx.dev>

* fix: tests

* chore: add jsdoc

* refactor: apply code suggestions

* fix: don't instantiate sub-structures

* fix: don't do null default twice

* chore: use formatters, add _cache

* chore: lockfile

* chore: move MixinTypes to declaratiion file

* fix: tests

* fix: don't include source d.ts files for docs

* feat: bitfields

* feat: more bitfields

* refactor: remove DirectoryChannel structure

* chore: apply suggestions from code review

* chore: remove unused import

* refactor: use symbol for mixin toJSON, remove _ prefix

* chore: apply suggestions from code review

* refactor: remove bitfield casts

* refactor: remove special case for threadchannel types

* fix: apply code review suggestions

* refactor: bitfields always store bigint

* fix: tests

* chore: apply suggestions from code review

* fix: lint

* refactor: conditional structuredClone

* Apply suggestions from code review

Co-authored-by: ckohen <chaikohen@gmail.com>

* fix: code review errors

* fix: lint

* chore: bump dtypes

* Update packages/structures/cliff.toml

Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>

* docs: link to VideoQualityMode

* chore: typo in comment

* chore: small nits in docs links

* chore: small nits

* docs: forgot one

* chore: update template

* chore: typos and things

* chore: apply suggestions from code review

* fix: tests and typeguards

* chore: don't clone appliedTags

* refactor: use a symbol for patch method

* fix: add missing readonly

* chore: remove todo comment

* refactor: use symbol for clone

* fix: add constraint to DataType

* chore: apply suggestions

* fix: dtypes bump

* chore: fix comment

* chore: add todo comment

* chore: mark bitfield as todo
chore: mark bit field as todo and edit readme

---------

Co-authored-by: ckohen <chaikohen@gmail.com>
Co-authored-by: Synbulat Biishev <signin@syjalo.dev>
Co-authored-by: Almeida <github@almeidx.dev>
Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2025-07-12 18:24:30 +00:00

221 lines
5.2 KiB
TypeScript

import { type APIInvite, type APIExtendedInvite, RouteBases } from 'discord-api-types/v10';
import { Structure } from '../Structure.js';
import { kData, kExpiresTimestamp, kCreatedTimestamp, kPatch } from '../utils/symbols.js';
import type { Partialize } from '../utils/types.js';
export interface APIActualInvite extends APIInvite, Partial<Omit<APIExtendedInvite, keyof APIInvite>> {}
/**
* Represents an invitation to a Discord channel
*
* @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`
*/
export class Invite<Omitted extends keyof APIActualInvite | '' = 'created_at' | 'expires_at'> extends Structure<
APIActualInvite,
Omitted
> {
/**
* The template used for removing data from the raw data stored for each Invite
*
* @remarks This template has defaults, if you want to remove additional data and keep the defaults,
* use `Object.defineProperties`. To override the defaults, set this value directly.
*/
public static override readonly DataTemplate: Partial<APIActualInvite> = {
set created_at(_: string) {},
set expires_at(_: string) {},
};
/**
* Optimized storage of {@link discord-api-types/v10#(APIActualInvite:interface).expires_at}
*
* @internal
*/
protected [kExpiresTimestamp]: number | null = null;
/**
* Optimized storage of {@link discord-api-types/v10#(APIActualInvite:interface).created_at}
*
* @internal
*/
protected [kCreatedTimestamp]: number | null = null;
/**
* @param data - The raw data received from the API for the invite
*/
public constructor(data: Partialize<APIActualInvite, Omitted>) {
super(data);
this.optimizeData(data);
}
/**
* {@inheritDoc Structure.[kPatch]}
*
* @internal
*/
public override [kPatch](data: Partial<APIActualInvite>) {
super[kPatch](data);
return this;
}
/**
* {@inheritDoc Structure.optimizeData}
*
* @internal
*/
protected override optimizeData(data: Partial<APIActualInvite>) {
if (data.expires_at) {
this[kExpiresTimestamp] = Date.parse(data.expires_at);
}
if (data.created_at) {
this[kCreatedTimestamp] = Date.parse(data.created_at);
}
}
/**
* The code for this invite
*/
public get code() {
return this[kData].code;
}
/**
* The target type (for voice channel invites)
*/
public get targetType() {
return this[kData].target_type;
}
/**
* The type of this invite
*/
public get type() {
return this[kData].type;
}
/**
* The approximate number of online members of the guild this invite is for
*
* @remarks Only available when the invite was fetched from `GET /invites/<code>` with counts
*/
public get approximatePresenceCount() {
return this[kData].approximate_presence_count;
}
/**
* The approximate total number of members of the guild this invite is for
*
* @remarks Only available when the invite was fetched from `GET /invites/<code>` with counts
*/
public get approximateMemberCount() {
return this[kData].approximate_member_count;
}
/**
* The timestamp this invite will expire at
*/
public get expiresTimestamp() {
if (this[kExpiresTimestamp]) {
return this[kExpiresTimestamp];
}
const createdTimestamp = this.createdTimestamp;
const maxAge = this.maxAge;
if (createdTimestamp && maxAge) {
this[kExpiresTimestamp] = createdTimestamp + (maxAge as number) * 1_000;
}
return this[kExpiresTimestamp];
}
/**
* The time the invite will expire at
*/
public get expiresAt() {
const expiresTimestamp = this.expiresTimestamp;
return expiresTimestamp ? new Date(expiresTimestamp) : null;
}
/**
* The number of times this invite has been used
*/
public get uses() {
return this[kData].uses;
}
/**
* The maximum number of times this invite can be used
*/
public get maxUses() {
return this[kData].max_uses;
}
/**
* The maximum age of the invite, in seconds, 0 for non-expiring
*/
public get maxAge() {
return this[kData].max_age;
}
/**
* Whether this invite only grants temporary membership
*/
public get temporary() {
return this[kData].temporary;
}
/**
* The timestamp this invite was created at
*/
public get createdTimestamp() {
return this[kCreatedTimestamp];
}
/**
* The time the invite was created at
*/
public get createdAt() {
const createdTimestamp = this.createdTimestamp;
return createdTimestamp ? new Date(createdTimestamp) : null;
}
/**
* The URL to the invite
*/
public get url() {
return this.code ? `${RouteBases.invite}/${this.code}` : null;
}
/**
* When concatenated with a string, this automatically concatenates the invite's URL instead of the object.
*
* @returns The URL to the invite or an empty string if it doesn't have a code
*/
public override toString() {
return this.url ?? '';
}
/**
* {@inheritDoc Structure.toJSON}
*/
public override toJSON() {
const clone = super.toJSON();
if (this[kExpiresTimestamp]) {
clone.expires_at = new Date(this[kExpiresTimestamp]).toISOString();
}
if (this[kCreatedTimestamp]) {
clone.created_at = new Date(this[kCreatedTimestamp]).toISOString();
}
return clone;
}
/**
* Returns the primitive value of the specified object.
*/
public override valueOf() {
return this.code ?? super.valueOf();
}
}