@constatic/base 0.0.1-beta.9 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,15 +1,15 @@
1
- # template
1
+ # Constatic Base
2
2
 
3
- To install dependencies:
3
+ Library with structures and functions for creating modern Discord applications.
4
4
 
5
- ```bash
6
- bun install
7
- ```
5
+ It all starts with the bootstrap function.
8
6
 
9
- To run:
7
+ ```ts
8
+ import { bootstrap } from "@constatic/base";
10
9
 
11
- ```bash
12
- bun run ./src/index.ts
10
+ await bootstrap({ meta: import.meta });
13
11
  ```
14
12
 
15
- This project was created using `bun init` in bun v1.3.0. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
13
+ ⚠️ It is recommended to use the [Constant CLI](https://constatic-docs.vercel.app/pt/docs/discord/start) to generate a project instead of doing it manually.
14
+
15
+ [📚 Read the full documentation here](https://constatic-docs.vercel.app/pt/docs)
package/dist/app.js CHANGED
@@ -1,11 +1,11 @@
1
1
  // src/app.ts
2
- import { version } from "./version.js";
3
2
  import { version as djsVersion } from "discord.js";
4
3
  import { styleText } from "node:util";
5
4
  import { CommandManager } from "./creators/commands/manager.js";
6
5
  import { EventManager } from "./creators/events/manager.js";
7
6
  import { ResponderManager } from "./creators/responders/manager.js";
8
7
  import { baseErrorHandler } from "./error.js";
8
+ import { version } from "./version.js";
9
9
  var isBun = typeof Bun !== "undefined";
10
10
 
11
11
  class ConstaticApp {
@@ -2,18 +2,67 @@ import { type Client } from "discord.js";
2
2
  import { type BaseErrorHandler } from "./app.js";
3
3
  import { type CustomClientOptions } from "./client.js";
4
4
  export interface BootstrapOptions extends CustomClientOptions {
5
- token?: string;
5
+ /**
6
+ * The caller module's `import.meta`.
7
+ * Internally used for resolving file paths when dynamically loading modules.
8
+ */
6
9
  meta: ImportMeta;
10
+ /**
11
+ * The Discord bot token.
12
+ * If omitted, bootstrap will attempt to use:
13
+ * - `env.BOT_TOKEN`
14
+ * - `process.env.BOT_TOKEN`
15
+ */
16
+ token?: string;
17
+ /**
18
+ * A custom error handler that overrides the default one
19
+ * configured by `ConstaticApp`.
20
+ *
21
+ * If provided, all global errors such as:
22
+ * - `uncaughtException`
23
+ * - `unhandledRejection`
24
+ *
25
+ * will be handled by this function.
26
+ */
7
27
  errorHandler?: BaseErrorHandler;
28
+ /**
29
+ * A hook executed before loading the modules.
30
+ * Can be used to register services, prepare caches,
31
+ * validate dependencies, or modify the client before initialization.
32
+ */
8
33
  beforeLoad?(client: Client<boolean>): Promise<void>;
34
+ /**
35
+ * Additional glob patterns used to load application modules.
36
+ */
9
37
  modules?: string[];
38
+ /**
39
+ * Whether initialization logs should be displayed.
40
+ * Defaults to `true`.
41
+ */
10
42
  loadLogs?: boolean;
43
+ /**
44
+ * Custom environment variables that may complement or override
45
+ * values from `process.env`.
46
+ */
11
47
  env?: Record<string, any>;
12
48
  }
49
+ /**
50
+ *
51
+ * Bootstraps and initializes a Constatic application, creating the Discord client,
52
+ * loading modules, registering events, and applying global error handlers.
53
+ *
54
+ * @example
55
+ * import { bootstrap } from "@constatic/base";
56
+ *
57
+ * await bootstrap({ meta: import.meta });
58
+ *
59
+ * @example
60
+ * import { env } from "#env";
61
+ * import { bootstrap } from "@constatic/base";
62
+ *
63
+ * await bootstrap({ meta: import.meta, env });
64
+ */
13
65
  export declare function bootstrap(options: BootstrapOptions): Promise<{
14
66
  client: Client<boolean>;
15
- imports: {
16
- module: any;
17
- filepath: string;
18
- }[];
67
+ imports: import("./modules.js").ModuleImported[];
19
68
  }>;
package/dist/client.d.ts CHANGED
@@ -1,3 +1,12 @@
1
1
  import { Client, type ClientOptions } from "discord.js";
2
2
  export type CustomClientOptions = Partial<ClientOptions>;
3
+ /**
4
+ * Creates and configures a Discord.js client instance integrated with ConstaticApp.
5
+ *
6
+ * This function initializes a `Client`, assigns the provided bot token, binds
7
+ * lifecycle events, and automatically wires command handlers, autocomplete
8
+ * handlers, and general interaction responders from the Constatic framework.
9
+ *
10
+ * The client will log a formatted startup message once it becomes ready.
11
+ */
3
12
  export declare function createClient(token: string, options: CustomClientOptions): Client<boolean>;
package/dist/client.js CHANGED
@@ -1,13 +1,15 @@
1
1
  // src/client.ts
2
- import { Client } from "discord.js";
2
+ import { Client, IntentsBitField, Partials } from "discord.js";
3
3
  import { styleText } from "node:util";
4
4
  import { ConstaticApp } from "./app.js";
5
+ var defaultIntents = Object.values(IntentsBitField.Flags).filter((t) => typeof t !== "string");
6
+ var defaultPartials = Object.values(Partials).filter((t) => typeof t !== "string");
5
7
  function createClient(token, options) {
6
8
  const app = ConstaticApp.getInstance();
7
9
  const client = new Client({
8
10
  ...options,
9
- intents: options.intents ?? [],
10
- partials: options.partials ?? [],
11
+ intents: options.intents ?? defaultIntents,
12
+ partials: options.partials ?? defaultPartials,
11
13
  failIfNotExists: options.failIfNotExists ?? false
12
14
  });
13
15
  client.token = token;
@@ -1,9 +1,9 @@
1
- import { ApplicationCommandOptionType, ApplicationCommandType, AutocompleteInteraction, ChatInputCommandInteraction, MessageContextMenuCommandInteraction, UserContextMenuCommandInteraction, type ApplicationCommandOptionAllowedChannelTypes, type ApplicationCommandOptionChoiceData, type BaseApplicationCommandData, type CacheType, type LocalizationMap } from "discord.js";
1
+ import { ApplicationCommandOptionType, ApplicationCommandType, AutocompleteInteraction, ChatInputCommandInteraction, InteractionContextType, MessageContextMenuCommandInteraction, UserContextMenuCommandInteraction, type ApplicationCommandOptionAllowedChannelTypes, type ApplicationCommandOptionChoiceData, type BaseApplicationCommandData, type CacheType, type LocalizationMap } from "discord.js";
2
2
  export type CommandType = Exclude<ApplicationCommandType, ApplicationCommandType.PrimaryEntryPoint>;
3
3
  type AutocompleData<Type> = Promise<readonly ApplicationCommandOptionChoiceData<Type extends (number | string) ? Type : (number | string)>[] | undefined | void>;
4
- export type AutocompleteRun<Type, Perm> = (this: void, interaction: AutocompleteInteraction<CacheMode<Perm>>) => AutocompleData<Type>;
5
- interface AutocompleteOptionData<Type, Perm> {
6
- autocomplete?: true | AutocompleteRun<Type, Perm>;
4
+ export type AutocompleteRun<Type, Contexts> = (this: void, interaction: AutocompleteInteraction<CacheMode<Contexts>>) => AutocompleData<Type>;
5
+ interface AutocompleteOptionData<Type, Contexts> {
6
+ autocomplete?: true | AutocompleteRun<Type, Contexts>;
7
7
  }
8
8
  interface BaseOptionData {
9
9
  name: string;
@@ -12,13 +12,13 @@ interface BaseOptionData {
12
12
  descriptionLocalizations?: LocalizationMap;
13
13
  required?: boolean;
14
14
  }
15
- interface StringOptionData<Perm> extends BaseOptionData, AutocompleteOptionData<string, Perm> {
15
+ interface StringOptionData<Contexts> extends BaseOptionData, AutocompleteOptionData<string, Contexts> {
16
16
  type: ApplicationCommandOptionType.String;
17
17
  choices?: readonly ApplicationCommandOptionChoiceData<string>[];
18
18
  minLength?: number;
19
19
  maxLength?: number;
20
20
  }
21
- interface NumberOptionData<P> extends BaseOptionData, AutocompleteOptionData<number, P> {
21
+ interface NumberOptionData<Contexts> extends BaseOptionData, AutocompleteOptionData<number, Contexts> {
22
22
  type: ApplicationCommandOptionType.Number | ApplicationCommandOptionType.Integer;
23
23
  choices?: readonly ApplicationCommandOptionChoiceData<number>[];
24
24
  minValue?: number;
@@ -31,16 +31,20 @@ interface ChannelOptionData extends BaseOptionData {
31
31
  interface CommonOptionData extends BaseOptionData {
32
32
  type: ApplicationCommandOptionType.Attachment | ApplicationCommandOptionType.Boolean | ApplicationCommandOptionType.Mentionable | ApplicationCommandOptionType.Role | ApplicationCommandOptionType.User;
33
33
  }
34
- export type SlashCommandPrimitiveOptionData<Perm> = StringOptionData<Perm> | NumberOptionData<Perm> | CommonOptionData | ChannelOptionData;
35
- export interface SubCommandOptionData<Perm> extends Omit<BaseOptionData, "required"> {
34
+ export type SlashCommandPrimitiveOptionData<Contexts> = StringOptionData<Contexts> | NumberOptionData<Contexts> | CommonOptionData | ChannelOptionData;
35
+ export interface SubCommandOptionData<Contexts> extends Omit<BaseOptionData, "required"> {
36
36
  type: ApplicationCommandOptionType.Subcommand;
37
- options?: SlashCommandPrimitiveOptionData<Perm>[];
37
+ options?: SlashCommandPrimitiveOptionData<Contexts>[];
38
38
  }
39
- export interface GroupOptionData<Perm> extends Omit<BaseOptionData, "required"> {
39
+ export interface GroupOptionData<Contexts> extends Omit<BaseOptionData, "required"> {
40
40
  type: ApplicationCommandOptionType.SubcommandGroup;
41
- options: SubCommandOptionData<Perm>[];
41
+ options: SubCommandOptionData<Contexts>[];
42
42
  }
43
- type CacheMode<Perm> = Perm extends false ? "cached" : CacheType;
43
+ type CacheMode<Contexts> = Contexts extends readonly InteractionContextType[] ? {
44
+ [InteractionContextType.Guild]: "cached";
45
+ [InteractionContextType.BotDM]: CacheType;
46
+ [InteractionContextType.PrivateChannel]: CacheType;
47
+ }[Contexts[number]] : CacheType;
44
48
  interface CommandRunThis {
45
49
  /**
46
50
  * Blocks the flow of executions
@@ -48,45 +52,45 @@ interface CommandRunThis {
48
52
  block(): never;
49
53
  }
50
54
  type ResolveCommandModuleData<Return> = Return extends void ? undefined : Return;
51
- export type SubCommandModuleData<Perm, Return> = Omit<BaseOptionData, "required"> & {
55
+ export type SubCommandModuleData<Contexts, Return> = Omit<BaseOptionData, "required"> & {
52
56
  group?: string;
53
- run(this: CommandRunThis, interaction: ChatInputCommandInteraction<CacheMode<Perm>>, data: ResolveCommandModuleData<Return>): Promise<void>;
54
- options?: SlashCommandPrimitiveOptionData<Perm>[];
57
+ run(this: CommandRunThis, interaction: ChatInputCommandInteraction<CacheMode<Contexts>>, data: ResolveCommandModuleData<Return>): Promise<void>;
58
+ options?: SlashCommandPrimitiveOptionData<Contexts>[];
55
59
  };
56
- export type SubCommandGroupModuleData<Perm, Return, T> = Omit<BaseOptionData, "required"> & {
57
- options?: Omit<SubCommandOptionData<Perm>, "type">[];
58
- run?(this: CommandRunThis, interaction: ChatInputCommandInteraction<CacheMode<Perm>>, data: ResolveCommandModuleData<Return>): Promise<T>;
60
+ export type SubCommandGroupModuleData<Contexts, Return, T> = Omit<BaseOptionData, "required"> & {
61
+ options?: Omit<SubCommandOptionData<Contexts>, "type">[];
62
+ run?(this: CommandRunThis, interaction: ChatInputCommandInteraction<CacheMode<Contexts>>, data: ResolveCommandModuleData<Return>): Promise<T>;
59
63
  };
60
- type RunInteraction<T, P> = T extends ApplicationCommandType.Message ? MessageContextMenuCommandInteraction<CacheMode<P>> : T extends ApplicationCommandType.User ? UserContextMenuCommandInteraction<CacheMode<P>> : ChatInputCommandInteraction<CacheMode<P>>;
61
- type BaseAppCommandData = Omit<BaseApplicationCommandData, "dmPermission"> & Pick<BaseOptionData, "descriptionLocalizations">;
62
- export interface CommandData<T, P, R> extends BaseAppCommandData {
64
+ type RunInteraction<T, Contexts> = T extends ApplicationCommandType.Message ? MessageContextMenuCommandInteraction<CacheMode<Contexts>> : T extends ApplicationCommandType.User ? UserContextMenuCommandInteraction<CacheMode<Contexts>> : ChatInputCommandInteraction<CacheMode<Contexts>>;
65
+ type BaseAppCommandData = Omit<BaseApplicationCommandData, "contexts"> & Pick<BaseOptionData, "descriptionLocalizations">;
66
+ export interface CommandData<T, Contexts, R> extends BaseAppCommandData {
63
67
  name: string;
64
68
  description?: string;
65
- dmPermission?: P;
69
+ contexts?: Contexts;
66
70
  type?: T;
67
71
  global?: boolean;
68
- run?(this: CommandRunThis, interaction: RunInteraction<T, P>): Promise<R>;
69
- autocomplete?: AutocompleteRun<string | number, P>;
70
- options?: SlashCommandPrimitiveOptionData<P>[] | (GroupOptionData<P> | SubCommandOptionData<P>)[];
72
+ run?(this: CommandRunThis, interaction: RunInteraction<T, Contexts>): Promise<R>;
73
+ autocomplete?: AutocompleteRun<string | number, Contexts>;
74
+ options?: SlashCommandPrimitiveOptionData<Contexts>[] | (GroupOptionData<Contexts> | SubCommandOptionData<Contexts>)[];
71
75
  }
72
- export type SlashCommandOptionData<Perm> = SlashCommandPrimitiveOptionData<Perm> | GroupOptionData<Perm> | SubCommandOptionData<Perm>;
76
+ export type SlashCommandOptionData<Contexts> = SlashCommandPrimitiveOptionData<Contexts> | GroupOptionData<Contexts> | SubCommandOptionData<Contexts>;
73
77
  export type CommandModule = (SubCommandGroupModuleData<unknown, unknown, unknown> & {
74
78
  type: ApplicationCommandOptionType.SubcommandGroup;
75
79
  }) | (SubCommandModuleData<unknown, unknown> & {
76
80
  type: ApplicationCommandOptionType.Subcommand;
77
81
  group?: string;
78
82
  });
79
- declare class GroupCommandModule<Type, Perm, Return, ModuleReturn> {
80
- readonly command: Command<Type, Perm, Return>;
81
- readonly data: SubCommandGroupModuleData<Perm, Return, ModuleReturn>;
82
- constructor(command: Command<Type, Perm, Return>, data: SubCommandGroupModuleData<Perm, Return, ModuleReturn>);
83
- subcommand(data: SubCommandModuleData<Perm, ModuleReturn>): this;
83
+ declare class GroupCommandModule<Type, Contexts extends readonly InteractionContextType[], Return, ModuleReturn> {
84
+ readonly command: Command<Type, Contexts, Return>;
85
+ readonly data: SubCommandGroupModuleData<Contexts, Return, ModuleReturn>;
86
+ constructor(command: Command<Type, Contexts, Return>, data: SubCommandGroupModuleData<Contexts, Return, ModuleReturn>);
87
+ subcommand(data: SubCommandModuleData<Contexts, ModuleReturn>): this;
84
88
  }
85
- export declare class Command<Type, Perm, Return> {
86
- readonly data: CommandData<Type, Perm, Return>;
89
+ export declare class Command<Type, Contexts extends readonly InteractionContextType[], Return> {
90
+ readonly data: CommandData<Type, Contexts, Return>;
87
91
  readonly modules: CommandModule[];
88
- constructor(data: CommandData<Type, Perm, Return>);
89
- group<ModuleReturn>(data: SubCommandGroupModuleData<Perm, Return, ModuleReturn>): GroupCommandModule<Type, Perm, Return, ModuleReturn>;
90
- subcommand<R = Return>(data: SubCommandModuleData<Perm, R>): this;
92
+ constructor(data: CommandData<Type, Contexts, Return>);
93
+ group<ModuleReturn = Return>(data: SubCommandGroupModuleData<Contexts, Return, ModuleReturn>): GroupCommandModule<Type, Contexts, Return, ModuleReturn>;
94
+ subcommand<R = Return>(data: SubCommandModuleData<Contexts, R>): this;
91
95
  }
92
96
  export {};
@@ -1,5 +1,5 @@
1
1
  // src/creators/commands/command.ts
2
- import { ApplicationCommandOptionType, ApplicationCommandType } from "discord.js";
2
+ import { ApplicationCommandOptionType, ApplicationCommandType, InteractionContextType } from "discord.js";
3
3
 
4
4
  class GroupCommandModule {
5
5
  command;
@@ -21,7 +21,6 @@ class Command {
21
21
  constructor(data) {
22
22
  this.data = data;
23
23
  this.data.type ??= ApplicationCommandType.ChatInput;
24
- this.data.dmPermission ??= false;
25
24
  if (this.data.type === ApplicationCommandType.ChatInput) {
26
25
  this.data.description ??= this.data.name;
27
26
  this.data.name = this.data.name.toLowerCase().replaceAll(" ", "");
@@ -29,6 +28,11 @@ class Command {
29
28
  if (this.data.name.length > 32) {
30
29
  this.data.name = this.data.name.slice(0, 32);
31
30
  }
31
+ if (!this.data.contexts) {
32
+ Object.assign(this.data, {
33
+ contexts: [InteractionContextType.Guild]
34
+ });
35
+ }
32
36
  }
33
37
  group(data) {
34
38
  this.modules.push({
@@ -1,4 +1,4 @@
1
- import { ApplicationCommandType, AutocompleteInteraction, Client, CommandInteraction, type ChatInputApplicationCommandData, type MessageApplicationCommandData, type UserApplicationCommandData } from "discord.js";
1
+ import { ApplicationCommandType, AutocompleteInteraction, Client, CommandInteraction, InteractionContextType, type ChatInputApplicationCommandData, type MessageApplicationCommandData, type UserApplicationCommandData } from "discord.js";
2
2
  import { BaseManager } from "../manager.js";
3
3
  import type { Command, CommandType } from "./command.js";
4
4
  type Runner = Function | null | undefined;
@@ -9,7 +9,7 @@ export declare class CommandManager extends BaseManager {
9
9
  private get config();
10
10
  private readonly collection;
11
11
  readonly runners: Map<string, Runner[]>;
12
- set<T, P, R>(command: Command<T, P, R>): void;
12
+ set<T, C extends readonly InteractionContextType[], R>(command: Command<T, C, R>): void;
13
13
  getTitle(type?: CommandType): string[];
14
14
  build(): BuildedCommandData[];
15
15
  private buildOptions;
@@ -1,9 +1,9 @@
1
- import { Client, Collection } from "discord.js";
1
+ import { Client, Collection, type ClientEvents } from "discord.js";
2
2
  import { BaseManager } from "../manager.js";
3
3
  import type { ClientEventKey, Event, EventsCollection, GenericEventArgs } from "./event.js";
4
4
  export declare class EventManager extends BaseManager {
5
5
  private get config();
6
- readonly collection: Collection<keyof import("discord.js").ClientEvents, EventsCollection>;
6
+ readonly collection: Collection<keyof ClientEvents, EventsCollection>;
7
7
  getEvents(key: ClientEventKey): EventsCollection;
8
8
  add(event: Event<ClientEventKey>): void;
9
9
  onEvent(event: Event<ClientEventKey>, args: GenericEventArgs): Promise<void>;
@@ -1,4 +1,4 @@
1
- import type { ApplicationCommandType, CacheType, ClientEvents, PermissionResolvable } from "discord.js";
1
+ import { ApplicationCommandType, InteractionContextType, type CacheType, type ClientEvents, type PermissionResolvable } from "discord.js";
2
2
  import { type BaseCommandsConfig, type BaseEventsConfig, type BaseRespondersConfig } from "../app.js";
3
3
  import { Command, type CommandData, type CommandType } from "./commands/command.js";
4
4
  import { Event, type EventData } from "./events/event.js";
@@ -10,8 +10,31 @@ export interface SetupCreatorsOptions {
10
10
  responders?: Partial<BaseRespondersConfig>;
11
11
  events?: Partial<BaseEventsConfig>;
12
12
  }
13
+ /**
14
+ * Initializes the Constatic command/event/responder creation system.
15
+ *
16
+ * This function configures the Constatic application’s internal registries
17
+ * for commands, events, and responders, and returns a set of factory
18
+ * functions used to create each type of component.
19
+ *
20
+ * It also:
21
+ * - Applies optional default command permissions
22
+ * - Merges user-provided config into the ConstaticApp instance
23
+ * - Automatically injects `process.env.GUILD_ID` into guild-restricted commands
24
+ * - Ensures `"clientReady"` events always run once
25
+ *
26
+ * **Returned creators:**
27
+ * - `createCommand(data)` — Registers a new slash command (or other command type)
28
+ * - `createEvent(data)` — Registers a Discord.js event listener
29
+ * - `createResponder(data)` — Registers an interaction responder (buttons, modals, etc.)
30
+ *
31
+ * @example
32
+ * import { setupCreators } from "@constatic/base";
33
+ *
34
+ * export const { createCommand, createResponder, createEvent } = setupCreators();
35
+ */
13
36
  export declare function setupCreators(options?: SetupCreatorsOptions): {
14
- createCommand<T extends CommandType = ApplicationCommandType.ChatInput, P extends boolean = false, R = void>(data: CommandData<T, P, R>): Command<T, P, R>;
37
+ createCommand: <T extends CommandType = ApplicationCommandType.ChatInput, const C extends readonly InteractionContextType[] = [InteractionContextType.Guild], R = void>(data: CommandData<T, C, R>) => Command<T, C, R>;
15
38
  createEvent: <EventName extends keyof ClientEvents>(data: EventData<EventName>) => Event<EventName>;
16
- createResponder<Path extends string, const Types extends readonly ResponderType[], Parsed, Cache extends CacheType = CacheType>(data: ResponderData<Path, Types, Parsed, Cache>): Responder<Path, Types, Parsed, Cache>;
39
+ createResponder: <Path extends string, const Types extends readonly ResponderType[], Parsed, Cache extends CacheType = CacheType>(data: ResponderData<Path, Types, Parsed, Cache>) => Responder<Path, Types, Parsed, Cache>;
17
40
  };
@@ -13,7 +13,7 @@ function setupCreators(options = {}) {
13
13
  app.config.commands.guilds.push(process.env.GUILD_ID);
14
14
  }
15
15
  return {
16
- createCommand(data) {
16
+ createCommand: function(data) {
17
17
  if (options.commands?.defaultMemberPermissions) {
18
18
  data.defaultMemberPermissions ??= options.commands.defaultMemberPermissions;
19
19
  }
@@ -29,7 +29,7 @@ function setupCreators(options = {}) {
29
29
  app.events.add(event);
30
30
  return event;
31
31
  },
32
- createResponder(data) {
32
+ createResponder: function(data) {
33
33
  const responder = new Responder(data);
34
34
  app.responders.set(responder);
35
35
  return responder;
package/dist/env.d.ts CHANGED
@@ -1,5 +1,28 @@
1
1
  import type { StandardSchemaV1 } from "./utils/schema.js";
2
2
  type Schema = StandardSchemaV1;
3
3
  type Out<T extends Schema> = StandardSchemaV1.InferOutput<T>;
4
+ /**
5
+ * Validates the current process environment variables using a StandardSchema.
6
+ *
7
+ * This function executes the schema validation against `process.env`
8
+ * and ensures all required environment variables follow the expected shape.
9
+ * @example
10
+ * // "env.ts" — Using Zod
11
+ * import { z } from "zod";
12
+ * import { validateEnv } from "@constatic/base";
13
+ *
14
+ * export const env = await validateEnv(z.object({
15
+ * BOT_TOKEN: z.string("BOT_TOKEN is required").min(1)
16
+ * }).passthrough());
17
+ *
18
+ * @example
19
+ * // "env.ts" — Using ArkType
20
+ * import { type } from "arktype";
21
+ * import { validateEnv } from "@constatic/base";
22
+ *
23
+ * export const env = await validateEnv(type({
24
+ * BOT_TOKEN: "string > 0"
25
+ * }));
26
+ */
4
27
  export declare function validateEnv<T extends Schema>(schema: T): Promise<Out<T>>;
5
28
  export {};
package/dist/error.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/error.ts
2
- import { codeBlock, TextDisplayBuilder, time, WebhookClient } from "discord.js";
2
+ import { codeBlock, TextDisplayBuilder, time, parseWebhookURL, REST, Routes } from "discord.js";
3
3
  import console from "node:console";
4
4
  import { styleText } from "node:util";
5
5
 
@@ -31,24 +31,31 @@ async function baseErrorHandler(error, client) {
31
31
  const url = process.env.WEBHOOK_LOGS_URL;
32
32
  if (!url)
33
33
  return;
34
+ const data = parseWebhookURL(url);
35
+ if (!data)
36
+ return;
37
+ const rest = new REST;
38
+ if (process.env.BOT_TOKEN)
39
+ rest.setToken(process.env.BOT_TOKEN);
34
40
  try {
35
- const webhook = new WebhookClient({ url });
36
41
  const username = client?.user?.username;
37
- await webhook.send({
38
- flags: ["IsComponentsV2"],
39
- components: [
40
- new TextDisplayBuilder({
41
- content: [
42
- codeBlock("ansi", text.join(`
42
+ rest.post(Routes.webhook(data.id, data.token), {
43
+ body: {
44
+ flags: ["IsComponentsV2"],
45
+ components: [
46
+ new TextDisplayBuilder({
47
+ content: [
48
+ codeBlock("ansi", text.join(`
43
49
  `)),
44
- time(new Date, "R")
45
- ].join(`
50
+ time(new Date, "R")
51
+ ].join(`
46
52
  `)
47
- })
48
- ],
49
- withComponents: true,
50
- avatarURL: client?.user?.displayAvatarURL({ size: 512 }),
51
- username: username ? `${username} logs` : "Logs"
53
+ })
54
+ ],
55
+ withComponents: true,
56
+ avatarURL: client?.user?.displayAvatarURL({ size: 512 }),
57
+ username: username ? `${username} logs` : "Logs"
58
+ }
52
59
  }).catch(console.error);
53
60
  } catch {
54
61
  console.log();
package/dist/modules.d.ts CHANGED
@@ -1,4 +1,9 @@
1
- export declare function loadModules(meta: ImportMeta, modules?: string[]): Promise<{
1
+ export interface ModuleImported {
2
2
  module: any;
3
3
  filepath: string;
4
- }[]>;
4
+ }
5
+ /**
6
+ * Dynamically loads modules using glob patterns, returning each imported module
7
+ * along with its file path.
8
+ */
9
+ export declare function loadModules(meta: ImportMeta, modules?: string[]): Promise<ModuleImported[]>;
package/dist/modules.js CHANGED
@@ -1,14 +1,17 @@
1
1
  // src/modules.ts
2
- import { glob } from "node:fs/promises";
3
- import path from "node:path";
2
+ import { join } from "node:path";
3
+ import { glob } from "tinyglobby";
4
4
  async function loadModules(meta, modules = []) {
5
- const exclude = modules.filter((path2) => path2.charAt(0) == "!").map((path2) => path2.slice(1));
6
- const filepaths = await Array.fromAsync(glob(modules, { cwd: meta.dirname, exclude }));
7
- const promises = filepaths.map((filepath) => import(path.join(meta.dirname, filepath)).then((imported) => ({
8
- module: imported,
9
- filepath
10
- })));
11
- return Promise.all(promises);
5
+ const ignore = modules.filter((path) => path.charAt(0) == "!").map((path) => path.slice(1));
6
+ const filepaths = await glob(modules, { cwd: meta.dirname, ignore });
7
+ const loadModules2 = [];
8
+ for (const path of filepaths) {
9
+ await import(join(meta.dirname, path)).then((imported) => loadModules2.push({
10
+ module: imported,
11
+ filepath: path
12
+ }));
13
+ }
14
+ return loadModules2;
12
15
  }
13
16
  export {
14
17
  loadModules
package/dist/version.d.ts CHANGED
@@ -1 +1,7 @@
1
+ /**
2
+ * Represents the current lib version.
3
+ *
4
+ * The version follows semantic versioning (SemVer), typically in the format:
5
+ * `"MAJOR.MINOR.PATCH"` — for example: `"1.0.0"`.
6
+ */
1
7
  export declare const version: string;
package/dist/version.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var version = "0.0.1-beta.9";
2
+ var version = "0.0.2";
3
3
  export {
4
4
  version
5
5
  };
package/package.json CHANGED
@@ -1,12 +1,36 @@
1
1
  {
2
2
  "name": "@constatic/base",
3
- "version": "0.0.1-beta.9",
4
- "description": "",
3
+ "version": "0.0.2",
4
+ "description": "Library with structures and functions for creating modern Discord applications.",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "publishConfig": {
8
8
  "access": "public"
9
9
  },
10
+ "keywords": [
11
+ "modern",
12
+ "base",
13
+ "discord",
14
+ "bot",
15
+ "discord bot",
16
+ "discord app",
17
+ "discord application",
18
+ "discord api",
19
+ "discord.js",
20
+ "typescript",
21
+ "app",
22
+ "api",
23
+ "tools",
24
+ "router",
25
+ "handlers",
26
+ "managers",
27
+ "loaders",
28
+ "modules",
29
+ "development",
30
+ "es6",
31
+ "node",
32
+ "bun"
33
+ ],
10
34
  "repository": {
11
35
  "type": "git",
12
36
  "url": "https://github.com/rinckodev/constatic",
@@ -18,8 +42,7 @@
18
42
  },
19
43
  "devDependencies": {
20
44
  "@constatic/config": "*",
21
- "@standard-schema/spec": "^1.0.0",
22
- "typescript": "^5.9.3"
45
+ "typescript": "^5.8.2"
23
46
  },
24
47
  "exports": {
25
48
  ".": {
@@ -39,16 +62,17 @@
39
62
  ]
40
63
  },
41
64
  "scripts": {
65
+ "check": "tsc --noEmit",
42
66
  "typegen": "tsc",
43
67
  "build": "bun run ./build.ts",
44
68
  "prepublish": "bun run build",
45
69
  "dev": "bun run ./playground/index.ts"
46
70
  },
47
71
  "peerDependencies": {
48
- "discord.js": "^14.24.2"
72
+ "discord.js": "^14.25.1"
49
73
  },
50
74
  "dependencies": {
51
- "@discordjs/core": "^2.3.0",
52
- "rou3": "^0.7.10"
75
+ "rou3": "^0.7.12",
76
+ "tinyglobby": "^0.2.15"
53
77
  }
54
78
  }