# CustomId

`class` in `custom-id` · v0.2.3

<https://docs.seedcord.org/packages/custom-id/0.2.3/classes/custom-id>

A typed customId. The single source of truth shared by the component that mints it and the handler that reads it. This gives you typed reads on the `.customId` field in components. Values are packed into a compact wire string, which fits more of them inside Discord's 100-char limit.

```ts
class CustomId<
    Prefix extends string,
    Shape extends CustomIdShape = {}
>
```

## Examples

```ts
import { ButtonHandler, ButtonRoute, CustomId } from '@seedcord/gateway';

// declare this in the component file that mints the button
export const Approve = new CustomId('approve').snowflake('userId').oneOf('action', ['approve', 'deny']);

\@ButtonRoute(Approve)
export class ApproveButton extends ButtonHandler<[typeof Approve]> {
    public async execute(): Promise<void> {
        const { userId, action } = this.params;
        // userId: string, action: 'approve' | 'deny'

        await this.reply(`${action} for <@${userId}>`);
    }
}
```

```ts
// Using it outside seedcord:
import { ButtonBuilder, Events } from 'discord.js';
import { CustomId } from '@seedcord/custom-id';

// one declaration, imported by both sides
const Approve = new CustomId('approve').snowflake('userId').oneOf('action', ['approve', 'deny']);

// minting, on the button you send
new ButtonBuilder().setCustomId(Approve.encode({ userId: '123', action: 'deny' })).setLabel('Deny');

// reading, wherever your bot receives the click
client.on(Events.InteractionCreate, (interaction) => {
    if (!interaction.isButton()) return;
    if (!Approve.owns(interaction.customId)) return;

    const { userId, action } = Approve.decode(interaction.customId);
    // userId: string, action: 'approve' | 'deny'
});
```

## Constructors

### constructor

```ts
CustomId(prefix: Prefix, shape?: Shape)
```

Constructs a new instance of the `CustomId` class

## Properties

### prefix

```ts
public readonly prefix: Prefix
```

The stable route prefix, e.g. 'approve'.

### routeKey

```ts
public readonly routeKey: string
```

The prefix plus a short hash of the shape, the part of the wire before the colon.

### shape

```ts
public readonly shape: Shape
```

The field definitions accumulated by the chain, keyed by name.

## Methods

### bool

```ts
public bool<Name, Nullable>(
    name: Name,
    opts?: FieldOptions<Nullable>
): CustomId<
    Prefix,
    Shape &
        Record<
            Name,
            CustomIdField<Nullish<boolean, Nullable>>
        >
>
```

Add a boolean flag.

### decode

```ts
public decode(wire: string): DecodedParams<Shape>
```

Read a wire string back into values.

Throws two different errors. A wire minted before the shape changed throws the stale one. A corrupt wire, or one minted by a different definition, throws the invalid one. Use [`setCustomIdErrors`](/packages/custom-id/0.2.3/functions/set-custom-id-errors) to customize the two thrown Error classes.

### encode

```ts
public encode(values: DecodedParams<Shape>): string
```

Mint a wire string from values. Throws if a value is out of its field's range or the wire is over 100 chars.

### int

```ts
public int<Name, Nullable>(
    name: Name,
    opts?: FieldOptions<Nullable>
): CustomId<
    Prefix,
    Shape &
        Record<
            Name,
            CustomIdField<Nullish<number, Nullable>>
        >
>
```

```ts
public int<Name, Nullable>(
    name: Name,
    min: number,
    max: number,
    opts?: FieldOptions<Nullable>
): CustomId<
    Prefix,
    Shape &
        Record<
            Name,
            CustomIdField<Nullish<number, Nullable>>
        >
>
```

### oneOf

```ts
public oneOf<Name, Choices, Nullable>(
    name: Name,
    choices: Choices,
    opts?: FieldOptions<Nullable>
): CustomId<
    Prefix,
    Shape &
        Record<
            Name,
            CustomIdField<
                Nullish<Choices[number], Nullable>
            >
        >
>
```

Add a field that is one value from a fixed list, decoded as the literal union. No `as const` needed.

### owns

```ts
public owns(wire: string): boolean
```

True if this wire was minted from this customId's prefix, ignoring the shape hash.

Use it to pick which definition a click belongs to before decoding. [`decodeFor`](/packages/custom-id/0.2.3/functions/decode-for) runs this loop for you across several definitions.

### snowflake

```ts
public snowflake<Name, Nullable>(
    name: Name,
    opts?: FieldOptions<Nullable>
): CustomId<
    Prefix,
    Shape &
        Record<
            Name,
            CustomIdField<Nullish<Snowflake, Nullable>>
        >
>
```

Add a Discord ID field, decoded as a string (the `Snowflake` type from discord-api-types).

### someOf

```ts
public someOf<Name, Choices, Nullable>(
    name: Name,
    choices: Choices,
    opts?: FieldOptions<Nullable>
): CustomId<
    Prefix,
    Shape &
        Record<
            Name,
            CustomIdField<
                Nullish<Choices[number][], Nullable>
            >
        >
>
```

Add a field that holds any subset of a fixed list, decoded as an array of the literal union.

A duplicate collapses into one entry. Decode returns the picks in the order the CustomId declares them. One choice costs one bit on the wire.

### str

```ts
public str<Name, Nullable>(
    name: Name,
    opts?: FieldOptions<Nullable>
): CustomId<
    Prefix,
    Shape &
        Record<
            Name,
            CustomIdField<Nullish<string, Nullable>>
        >
>
```

Add a free short text field. Avoid it where possible. It cannot be packed, which makes it the most expensive field on the wire.

### uuid

```ts
public uuid<Name, Nullable>(
    name: Name,
    opts?: FieldOptions<Nullable>
): CustomId<
    Prefix,
    Shape &
        Record<
            Name,
            CustomIdField<Nullish<string, Nullable>>
        >
>
```

Add a UUID field, decoded as a lowercase uuid string.
