Files
discord.js/packages/structures/src/entitlements/Entitlement.ts
Asad 3d74122215 feat(structures): add entitlement structure (#11377)
* feat(structures): add entitlement structure

* feat(structures): create and update barrel exports

* chore: reword comment for entitlment deleted getter to be clearer

* feat(structures): add symbols to optimise ends_at, starts_at fields

* feat(structures): optimise starts_at and ends_at fields

* feat(structures): manage Date and Discord ISOs appropriately

* chore: remove accidental whitespace

* chore: correct name styles on symbols (remove 'at')

* chore: correct name styles on AtTimestamp fields (remove 'at')

* chore: call super.toJSON on toJSON override

* chore: run prettier to clear linting/formatter errors

* chore: correct usage of optimizeData

* chore: update DataTemplate override for Entitlement

* chore: update class default type param, update DataTemplate doc

* Apply suggestions from code review

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

---------

Co-authored-by: Almeida <github@almeidx.dev>
Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
2026-01-15 23:43:39 +00:00

177 lines
4.1 KiB
TypeScript

import { DiscordSnowflake } from '@sapphire/snowflake';
import type { APIEntitlement } from 'discord-api-types/v10';
import { Structure } from '../Structure.js';
import { dateToDiscordISOTimestamp } from '../utils/optimization.js';
import { kData, kStartsTimestamp, kEndsTimestamp } from '../utils/symbols.js';
import { isIdSet } from '../utils/type-guards.js';
import type { Partialize } from '../utils/types.js';
/**
* Represents any entitlement on Discord.
*
* @typeParam Omitted - Specify the properties that will not be stored in the raw data field as a union, implement via `DataTemplate`
*/
export class Entitlement<Omitted extends keyof APIEntitlement | '' = 'ends_at' | 'starts_at'> extends Structure<
APIEntitlement,
Omitted
> {
/**
* The template used for removing data from the raw data stored for each entitlement
*
* @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<APIEntitlement> = {
set starts_at(_: string) {},
set ends_at(_: string) {},
};
protected [kStartsTimestamp]: number | null = null;
protected [kEndsTimestamp]: number | null = null;
/**
* @param data - The raw data received from the API for the entitlement
*/
public constructor(data: Partialize<APIEntitlement, Omitted>) {
super(data);
this.optimizeData(data);
}
/**
* {@inheritDoc Structure.optimizeData}
*/
protected override optimizeData(data: Partial<APIEntitlement>) {
if (data.starts_at) {
this[kStartsTimestamp] = Date.parse(data.starts_at);
}
if (data.ends_at) {
this[kEndsTimestamp] = Date.parse(data.ends_at);
}
}
/**
* The id of the entitlement
*/
public get id() {
return this[kData].id;
}
/**
* The id of the SKU
*/
public get skuId() {
return this[kData].sku_id;
}
/**
* The id of the parent application
*/
public get applicationId() {
return this[kData].application_id;
}
/**
* The id of the user that is granted access to the entitlement's SKU
*/
public get userId() {
return this[kData].user_id;
}
/**
* Type of entitlement
*
* @see {@link https://discord.com/developers/docs/resources/entitlement#entitlement-object-entitlement-types}
*/
public get type() {
return this[kData].type;
}
/**
* Whether the entitlement was deleted
*/
public get deleted() {
return this[kData].deleted;
}
/**
* Start date at which the entitlement is valid
*/
public get startsAt() {
const timestamp = this.startsTimestamp;
return timestamp ? new Date(timestamp) : null;
}
/**
* Timestamp of the start date at which the entitlement is valid
*/
public get startsTimestamp() {
return this[kStartsTimestamp];
}
/**
* End date at which the entitlement is valid
*/
public get endsAt() {
const timestamp = this.endsTimestamp;
return timestamp ? new Date(timestamp) : null;
}
/**
* Timestamp of the end date at which the entitlement is valid
*/
public get endsTimestamp() {
return this[kEndsTimestamp];
}
/**
* Id of the guild that is granted access to the entitlement's SKU
*/
public get guildId() {
return this[kData].guild_id;
}
/**
* For consumable items, whether the entitlement has been consumed
*/
public get consumed() {
return this[kData].consumed;
}
/**
* The timestamp the entitlement was created at
*/
public get createdTimestamp() {
return isIdSet(this.id) ? DiscordSnowflake.timestampFrom(this.id) : null;
}
/**
* The time the entitlement was created at
*/
public get createdAt() {
const createdTimestamp = this.createdTimestamp;
return createdTimestamp ? new Date(createdTimestamp) : null;
}
/**
* {@inheritDoc Structure.toJSON}
*/
public override toJSON() {
const clone = super.toJSON();
const startsAtTimestamp = this[kStartsTimestamp];
const endsAtTimestamp = this[kEndsTimestamp];
if (startsAtTimestamp) {
clone.starts_at = dateToDiscordISOTimestamp(new Date(startsAtTimestamp));
}
if (endsAtTimestamp) {
clone.ends_at = dateToDiscordISOTimestamp(new Date(endsAtTimestamp));
}
return clone;
}
}