commandkit 0.1.6 → 0.1.7-dev.20231212150647

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/dist/index.mjs CHANGED
@@ -6,48 +6,52 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
6
6
  throw Error('Dynamic require of "' + x + '" is not supported');
7
7
  });
8
8
 
9
- // src/utils/get-paths.ts
9
+ // src/utils/resolve-file-url.ts
10
10
  import path from "path";
11
- import fs from "fs";
12
- function getFilePaths(directory, nesting) {
11
+ function toFileURL(filePath) {
12
+ const resolvedPath = path.resolve(filePath);
13
+ return "file://" + resolvedPath.replace(/\\\\|\\/g, "/");
14
+ }
15
+
16
+ // src/utils/get-paths.ts
17
+ import path2 from "path";
18
+ import fs from "fs/promises";
19
+ async function getFilePaths(directory, nesting) {
13
20
  let filePaths = [];
14
21
  if (!directory)
15
22
  return filePaths;
16
- const files = fs.readdirSync(directory, { withFileTypes: true });
23
+ const files = await fs.readdir(directory, { withFileTypes: true });
17
24
  for (const file of files) {
18
- const filePath = path.join(directory, file.name);
25
+ const filePath = path2.join(directory, file.name);
19
26
  if (file.isFile()) {
20
27
  filePaths.push(filePath);
21
28
  }
22
29
  if (nesting && file.isDirectory()) {
23
- filePaths = [...filePaths, ...getFilePaths(filePath, true)];
30
+ filePaths = [...filePaths, ...await getFilePaths(filePath, true)];
24
31
  }
25
32
  }
26
33
  return filePaths;
27
34
  }
28
- function getFolderPaths(directory, nesting) {
35
+ async function getFolderPaths(directory, nesting) {
29
36
  let folderPaths = [];
30
37
  if (!directory)
31
38
  return folderPaths;
32
- const folders = fs.readdirSync(directory, { withFileTypes: true });
39
+ const folders = await fs.readdir(directory, { withFileTypes: true });
33
40
  for (const folder of folders) {
34
- const folderPath = path.join(directory, folder.name);
41
+ const folderPath = path2.join(directory, folder.name);
35
42
  if (folder.isDirectory()) {
36
43
  folderPaths.push(folderPath);
37
44
  if (nesting) {
38
- folderPaths = [...folderPaths, ...getFolderPaths(folderPath, true)];
45
+ folderPaths = [...folderPaths, ...await getFolderPaths(folderPath, true)];
39
46
  }
40
47
  }
41
48
  }
42
49
  return folderPaths;
43
50
  }
44
51
 
45
- // src/utils/resolve-file-url.ts
46
- import path2 from "path";
47
- function toFileURL(filePath) {
48
- const resolvedPath = path2.resolve(filePath);
49
- return "file://" + resolvedPath.replace(/\\\\|\\/g, "/");
50
- }
52
+ // src/utils/clone.ts
53
+ import rfdc from "rfdc";
54
+ var clone = rfdc();
51
55
 
52
56
  // src/utils/colors.ts
53
57
  var resetColor = "\x1B[0m";
@@ -331,35 +335,10 @@ async function registerDevCommands(client, commands, guildIds) {
331
335
  }
332
336
  }
333
337
 
334
- // src/handlers/command-handler/validations/botPermissions.ts
335
- function botPermissions_default({ interaction, targetCommand }) {
336
- const botMember = interaction.guild?.members.me;
337
- let commandPermissions = targetCommand.options?.botPermissions;
338
- if (!botMember || !commandPermissions)
339
- return;
340
- if (!Array.isArray(commandPermissions)) {
341
- commandPermissions = [commandPermissions];
342
- }
343
- const missingPermissions = [];
344
- for (const permission of commandPermissions) {
345
- const hasPermission = botMember.permissions.has(permission);
346
- if (!hasPermission) {
347
- missingPermissions.push(`\`${permission.toString()}\``);
348
- }
349
- }
350
- if (missingPermissions.length) {
351
- interaction.reply({
352
- content: `\u274C I do not have enough permissions to execute this command. Missing: ${missingPermissions.join(
353
- ", "
354
- )}`,
355
- ephemeral: true
356
- });
357
- return true;
358
- }
359
- }
360
-
361
338
  // src/handlers/command-handler/validations/devOnly.ts
362
339
  function devOnly_default({ interaction, targetCommand, handlerData }) {
340
+ if (interaction.isAutocomplete())
341
+ return;
363
342
  if (targetCommand.options?.devOnly) {
364
343
  if (interaction.inGuild() && !handlerData.devGuildIds.includes(interaction.guildId)) {
365
344
  interaction.reply({
@@ -387,50 +366,76 @@ function devOnly_default({ interaction, targetCommand, handlerData }) {
387
366
  }
388
367
  }
389
368
 
390
- // src/handlers/command-handler/validations/guildOnly.ts
391
- function guildOnly_default({ interaction, targetCommand }) {
392
- if (targetCommand.options?.guildOnly && !interaction.inGuild()) {
393
- interaction.reply({
394
- content: "\u274C This command can only be used inside a server.",
395
- ephemeral: true
396
- });
397
- return true;
369
+ // src/handlers/command-handler/validations/permissions.ts
370
+ import { EmbedBuilder } from "discord.js";
371
+ function permissions_default({ interaction, targetCommand }) {
372
+ if (interaction.isAutocomplete())
373
+ return;
374
+ const userPermissions = interaction.memberPermissions;
375
+ let userPermissionsRequired = targetCommand.options?.userPermissions;
376
+ let missingUserPermissions = [];
377
+ if (typeof userPermissionsRequired === "string") {
378
+ userPermissionsRequired = [userPermissionsRequired];
398
379
  }
399
- }
400
-
401
- // src/handlers/command-handler/validations/userPermissions.ts
402
- function userPermissions_default({ interaction, targetCommand }) {
403
- const memberPermissions = interaction.memberPermissions;
404
- let commandPermissions = targetCommand.options?.userPermissions;
405
- if (!memberPermissions || !commandPermissions)
380
+ const botPermissions = interaction.guild?.members.me?.permissions;
381
+ let botPermissionsRequired = targetCommand.options?.botPermissions;
382
+ let missingBotPermissions = [];
383
+ if (typeof botPermissionsRequired === "string") {
384
+ botPermissionsRequired = [botPermissionsRequired];
385
+ }
386
+ if (!userPermissionsRequired?.length && !botPermissionsRequired?.length) {
406
387
  return;
407
- if (!Array.isArray(commandPermissions)) {
408
- commandPermissions = [commandPermissions];
409
- }
410
- const missingPermissions = [];
411
- for (const permission of commandPermissions) {
412
- const hasPermission = memberPermissions.has(permission);
413
- if (!hasPermission) {
414
- missingPermissions.push(`\`${permission.toString()}\``);
415
- }
416
- }
417
- if (missingPermissions.length) {
418
- interaction.reply({
419
- content: `\u274C You do not have enough permissions to run this command. Missing: ${missingPermissions.join(
420
- ", "
421
- )}`,
422
- ephemeral: true
423
- });
424
- return true;
425
388
  }
389
+ if (userPermissions && userPermissionsRequired) {
390
+ for (const permission of userPermissionsRequired) {
391
+ const hasPermission = userPermissions.has(permission);
392
+ if (!hasPermission) {
393
+ missingUserPermissions.push(permission);
394
+ }
395
+ }
396
+ }
397
+ if (botPermissions && botPermissionsRequired) {
398
+ for (const permission of botPermissionsRequired) {
399
+ const hasPermission = botPermissions.has(permission);
400
+ if (!hasPermission) {
401
+ missingBotPermissions.push(permission);
402
+ }
403
+ }
404
+ }
405
+ if (!missingUserPermissions.length && !missingBotPermissions.length) {
406
+ return;
407
+ }
408
+ const pattern = /([a-z])([A-Z])|([A-Z]+)([A-Z][a-z])/g;
409
+ missingUserPermissions = missingUserPermissions.map((str) => str.replace(pattern, "$1$3 $2$4"));
410
+ missingBotPermissions = missingBotPermissions.map((str) => str.replace(pattern, "$1$3 $2$4"));
411
+ let embedDescription = "";
412
+ const formatter = new Intl.ListFormat("en", { style: "long", type: "conjunction" });
413
+ const getPermissionWord = (permissions) => permissions.length === 1 ? "permission" : "permissions";
414
+ if (missingUserPermissions.length) {
415
+ const formattedPermissions = missingUserPermissions.map((p) => `\`${p}\``);
416
+ const permissionsString = formatter.format(formattedPermissions);
417
+ embedDescription += `- You must have the ${permissionsString} ${getPermissionWord(
418
+ missingUserPermissions
419
+ )} to be able to run this command.
420
+ `;
421
+ }
422
+ if (missingBotPermissions.length) {
423
+ const formattedPermissions = missingBotPermissions.map((p) => `\`${p}\``);
424
+ const permissionsString = formatter.format(formattedPermissions);
425
+ embedDescription += `- I must have the ${permissionsString} ${getPermissionWord(
426
+ missingBotPermissions
427
+ )} to be able to execute this command.
428
+ `;
429
+ }
430
+ const embed = new EmbedBuilder().setTitle(`:x: Missing permissions!`).setDescription(embedDescription).setColor("Red");
431
+ interaction.reply({ embeds: [embed], ephemeral: true });
432
+ return true;
426
433
  }
427
434
 
428
435
  // src/handlers/command-handler/validations/index.ts
429
- var validations_default = [botPermissions_default, devOnly_default, guildOnly_default, userPermissions_default];
436
+ var validations_default = [devOnly_default, permissions_default];
430
437
 
431
438
  // src/handlers/command-handler/CommandHandler.ts
432
- import rdfc from "rfdc";
433
- var clone = rdfc();
434
439
  var CommandHandler = class {
435
440
  #data;
436
441
  constructor({ ...options }) {
@@ -442,19 +447,19 @@ var CommandHandler = class {
442
447
  }
443
448
  async init() {
444
449
  await this.#buildCommands();
445
- this.#buildValidations();
450
+ this.#buildBuiltInValidations();
446
451
  const devOnlyCommands = this.#data.commands.filter((cmd) => cmd.options?.devOnly);
447
452
  if (devOnlyCommands.length && !this.#data.devGuildIds.length) {
448
453
  console.log(
449
454
  colors_default.yellow(
450
- '\u2139\uFE0F Warning: You have commands marked as "devOnly" but "devGuildIds" has not been set.'
455
+ '\u2139\uFE0F Warning: You have commands marked as "devOnly", but "devGuildIds" have not been set.'
451
456
  )
452
457
  );
453
458
  }
454
459
  if (devOnlyCommands.length && !this.#data.devUserIds.length && !this.#data.devRoleIds.length) {
455
460
  console.log(
456
461
  colors_default.yellow(
457
- '\u2139\uFE0F Warning: You have commands marked as "devOnly" but not "devUserIds" or "devRoleIds" were set.'
462
+ '\u2139\uFE0F Warning: You have commands marked as "devOnly", but "devUserIds" or "devRoleIds" have not been set.'
458
463
  )
459
464
  );
460
465
  }
@@ -475,12 +480,11 @@ var CommandHandler = class {
475
480
  }
476
481
  async #buildCommands() {
477
482
  const allowedExtensions = /\.(js|mjs|cjs|ts)$/i;
478
- const commandFilePaths = getFilePaths(this.#data.commandsPath, true).filter(
479
- (path3) => allowedExtensions.test(path3)
480
- );
483
+ const paths = await getFilePaths(this.#data.commandsPath, true);
484
+ const commandFilePaths = paths.filter((path3) => allowedExtensions.test(path3));
481
485
  for (const commandFilePath of commandFilePaths) {
482
486
  const modulePath = toFileURL(commandFilePath);
483
- let importedObj = await import(`${modulePath}?t=${Date.now()}`);
487
+ const importedObj = await import(`${modulePath}?t=${Date.now()}`);
484
488
  let commandObj = clone(importedObj);
485
489
  if (typeof module !== "undefined" && typeof __require !== "undefined") {
486
490
  delete __require.cache[__require.resolve(commandFilePath)];
@@ -532,24 +536,34 @@ var CommandHandler = class {
532
536
  } else {
533
537
  commandObj.category = commandCategory;
534
538
  }
539
+ if (commandObj.options?.guildOnly) {
540
+ console.log(
541
+ colors_default.yellow(
542
+ `\u2139\uFE0F Deprecation warning: The command "${commandObj.data.name}" uses "options.guildOnly", which will be deprecated soon. Use "data.dm_permission" instead.`
543
+ )
544
+ );
545
+ }
535
546
  this.#data.commands.push(commandObj);
536
547
  }
537
548
  }
538
- #buildValidations() {
539
- for (const validationFunction of validations_default) {
540
- this.#data.builtInValidations.push(validationFunction);
549
+ #buildBuiltInValidations() {
550
+ for (const builtInValidationFunction of validations_default) {
551
+ this.#data.builtInValidations.push(builtInValidationFunction);
541
552
  }
542
553
  }
543
554
  handleCommands() {
544
555
  this.#data.client.on("interactionCreate", async (interaction) => {
545
- if (!interaction.isChatInputCommand() && !interaction.isContextMenuCommand())
556
+ if (!interaction.isChatInputCommand() && !interaction.isContextMenuCommand() && !interaction.isAutocomplete())
546
557
  return;
558
+ const isAutocomplete = interaction.isAutocomplete();
547
559
  const targetCommand = this.#data.commands.find(
548
560
  (cmd) => cmd.data.name === interaction.commandName
549
561
  );
550
562
  if (!targetCommand)
551
563
  return;
552
- const { data, options, run, ...rest } = targetCommand;
564
+ const { data, options, run, autocompleteRun, ...rest } = targetCommand;
565
+ if (isAutocomplete && !autocompleteRun)
566
+ return;
553
567
  const commandObj = {
554
568
  data: targetCommand.data,
555
569
  options: targetCommand.options,
@@ -588,17 +602,23 @@ var CommandHandler = class {
588
602
  }
589
603
  if (!canRun)
590
604
  return;
591
- targetCommand.run({
605
+ const context2 = {
592
606
  interaction,
593
607
  client: this.#data.client,
594
608
  handler: this.#data.commandkitInstance
595
- });
609
+ };
610
+ await targetCommand[isAutocomplete ? "autocompleteRun" : "run"](context2);
596
611
  });
597
612
  }
598
613
  get commands() {
599
614
  return this.#data.commands;
600
615
  }
601
616
  async reloadCommands(type) {
617
+ if (!this.#data.commandsPath) {
618
+ throw new Error(
619
+ 'Cannot reload commands as "commandsPath" was not provided when instantiating CommandKit.'
620
+ );
621
+ }
602
622
  this.#data.commands = [];
603
623
  await this.#buildCommands();
604
624
  if (this.#data.bulkRegister) {
@@ -619,13 +639,9 @@ var CommandHandler = class {
619
639
  });
620
640
  }
621
641
  }
622
- async useUpdatedValidations() {
623
- }
624
642
  };
625
643
 
626
644
  // src/handlers/event-handler/EventHandler.ts
627
- import rdfc2 from "rfdc";
628
- var clone2 = rdfc2();
629
645
  var EventHandler = class {
630
646
  #data;
631
647
  constructor({ ...options }) {
@@ -639,13 +655,12 @@ var EventHandler = class {
639
655
  this.#registerEvents();
640
656
  }
641
657
  async #buildEvents() {
642
- const eventFolderPaths = getFolderPaths(this.#data.eventsPath);
658
+ const eventFolderPaths = await getFolderPaths(this.#data.eventsPath);
643
659
  for (const eventFolderPath of eventFolderPaths) {
644
660
  const eventName = eventFolderPath.replace(/\\\\|\\/g, "/").split("/").pop();
645
661
  const allowedExtensions = /\.(js|mjs|cjs|ts)$/i;
646
- const eventFilePaths = getFilePaths(eventFolderPath, true).filter(
647
- (path3) => allowedExtensions.test(path3)
648
- );
662
+ const eventPaths = await getFilePaths(eventFolderPath, true);
663
+ const eventFilePaths = eventPaths.filter((path3) => allowedExtensions.test(path3));
649
664
  const eventObj = {
650
665
  name: eventName,
651
666
  functions: []
@@ -654,7 +669,7 @@ var EventHandler = class {
654
669
  for (const eventFilePath of eventFilePaths) {
655
670
  const modulePath = toFileURL(eventFilePath);
656
671
  let importedFunction = (await import(`${modulePath}?t=${Date.now()}`)).default;
657
- let eventFunction = clone2(importedFunction);
672
+ let eventFunction = clone(importedFunction);
658
673
  if (typeof module !== "undefined" && typeof __require !== "undefined") {
659
674
  delete __require.cache[__require.resolve(eventFilePath)];
660
675
  }
@@ -692,6 +707,11 @@ var EventHandler = class {
692
707
  return this.#data.events;
693
708
  }
694
709
  async reloadEvents(commandHandler) {
710
+ if (!this.#data.eventsPath) {
711
+ throw new Error(
712
+ 'Cannot reload events as "eventsPath" was not provided when instantiating CommandKit.'
713
+ );
714
+ }
695
715
  this.#data.events = [];
696
716
  await this.#buildEvents();
697
717
  this.#data.client.removeAllListeners();
@@ -701,8 +721,6 @@ var EventHandler = class {
701
721
  };
702
722
 
703
723
  // src/handlers/validation-handler/ValidationHandler.ts
704
- import rdfc3 from "rfdc";
705
- var clone3 = rdfc3();
706
724
  var ValidationHandler = class {
707
725
  #data;
708
726
  constructor({ ...options }) {
@@ -712,17 +730,17 @@ var ValidationHandler = class {
712
730
  };
713
731
  }
714
732
  async init() {
715
- await this.#buildValidations();
733
+ this.#data.validations = await this.#buildValidations();
716
734
  }
717
735
  async #buildValidations() {
718
736
  const allowedExtensions = /\.(js|mjs|cjs|ts)$/i;
719
- const validationFilePaths = getFilePaths(this.#data.validationsPath, true).filter(
720
- (path3) => allowedExtensions.test(path3)
721
- );
737
+ const validationPaths = await getFilePaths(this.#data.validationsPath, true);
738
+ const validationFilePaths = validationPaths.filter((path3) => allowedExtensions.test(path3));
739
+ const validationFunctions = [];
722
740
  for (const validationFilePath of validationFilePaths) {
723
741
  const modulePath = toFileURL(validationFilePath);
724
742
  let importedFunction = (await import(`${modulePath}?t=${Date.now()}`)).default;
725
- let validationFunction = clone3(importedFunction);
743
+ let validationFunction = clone(importedFunction);
726
744
  if (typeof module !== "undefined" && typeof __require !== "undefined") {
727
745
  delete __require.cache[__require.resolve(validationFilePath)];
728
746
  }
@@ -738,21 +756,33 @@ var ValidationHandler = class {
738
756
  );
739
757
  continue;
740
758
  }
741
- this.#data.validations.push(validationFunction);
759
+ validationFunctions.push(validationFunction);
742
760
  }
761
+ return validationFunctions;
743
762
  }
744
763
  get validations() {
745
764
  return this.#data.validations;
746
765
  }
747
766
  async reloadValidations() {
748
- this.#data.validations = [];
749
- await this.#buildValidations();
767
+ if (!this.#data.validationsPath) {
768
+ throw new Error(
769
+ 'Cannot reload validations as "validationsPath" was not provided when instantiating CommandKit.'
770
+ );
771
+ }
772
+ const newValidations = await this.#buildValidations();
773
+ this.#data.validations = newValidations;
750
774
  }
751
775
  };
752
776
 
753
777
  // src/CommandKit.ts
754
778
  var CommandKit = class {
755
779
  #data;
780
+ /**
781
+ * Create a new command and event handler with CommandKit.
782
+ *
783
+ * @param options - The default CommandKit configuration.
784
+ * @see {@link https://commandkit.js.org/docs/commandkit-setup}
785
+ */
756
786
  constructor(options) {
757
787
  if (!options.client) {
758
788
  throw new Error(colors_default.red('"client" is required when instantiating CommandKit.'));
@@ -765,6 +795,9 @@ var CommandKit = class {
765
795
  this.#data = options;
766
796
  this.#init();
767
797
  }
798
+ /**
799
+ * (Private) Initialize CommandKit.
800
+ */
768
801
  async #init() {
769
802
  if (this.#data.eventsPath) {
770
803
  const eventHandler = new EventHandler({
@@ -873,20 +906,150 @@ var CommandKit = class {
873
906
  }
874
907
  };
875
908
 
876
- // src/types/index.ts
877
- var CommandType = /* @__PURE__ */ ((CommandType2) => {
878
- CommandType2[CommandType2["ChatInput"] = 1] = "ChatInput";
879
- CommandType2[CommandType2["Message"] = 3] = "Message";
880
- CommandType2[CommandType2["User"] = 2] = "User";
881
- return CommandType2;
882
- })(CommandType || {});
883
- var ReloadType = /* @__PURE__ */ ((ReloadType2) => {
884
- ReloadType2["Developer"] = "dev";
885
- ReloadType2["Global"] = "global";
886
- return ReloadType2;
887
- })(ReloadType || {});
909
+ // src/components/ButtonKit.ts
910
+ import {
911
+ ButtonStyle,
912
+ ButtonBuilder,
913
+ ComponentType
914
+ } from "discord.js";
915
+ var ButtonKit = class extends ButtonBuilder {
916
+ #onClickHandler = null;
917
+ #contextData = null;
918
+ #collector = null;
919
+ onClick(handler, data) {
920
+ if (this.data.style === ButtonStyle.Link) {
921
+ throw new TypeError('Cannot setup "onClick" handler on link buttons.');
922
+ }
923
+ this.#destroyCollector();
924
+ this.#onClickHandler = handler;
925
+ if (handler && data)
926
+ this.#contextData = data;
927
+ this.#setupInteractionCollector();
928
+ return this;
929
+ }
930
+ #setupInteractionCollector() {
931
+ if (!this.#contextData || !this.#onClickHandler)
932
+ return;
933
+ const message = this.#contextData.message;
934
+ if (!message) {
935
+ throw new TypeError(
936
+ 'Cannot setup "onClick" handler without a message in the context data.'
937
+ );
938
+ }
939
+ if ("customId" in this.data && !this.data.customId) {
940
+ throw new TypeError('Cannot setup "onClick" handler on a button without a custom id.');
941
+ }
942
+ const data = {
943
+ time: 864e5,
944
+ autoReset: true,
945
+ ...this.#contextData
946
+ };
947
+ const collector = this.#collector = message.createMessageComponentCollector({
948
+ filter: (interaction) => interaction.customId === this.data.custom_id && interaction.message.id === message.id,
949
+ componentType: ComponentType.Button,
950
+ ...data
951
+ });
952
+ this.#collector.on("collect", (interaction) => {
953
+ const handler = this.#onClickHandler;
954
+ if (!handler)
955
+ return this.#destroyCollector();
956
+ if (!this.#collector) {
957
+ return collector.stop("destroyed");
958
+ }
959
+ if (data.autoReset) {
960
+ this.#collector.resetTimer();
961
+ }
962
+ return handler(interaction);
963
+ });
964
+ this.#collector.on("end", () => {
965
+ this.#destroyCollector();
966
+ });
967
+ }
968
+ #destroyCollector() {
969
+ this.#onClickHandler?.(null);
970
+ this.#collector?.stop("end");
971
+ this.#collector?.removeAllListeners();
972
+ this.#collector = null;
973
+ this.#contextData = null;
974
+ this.#onClickHandler = null;
975
+ }
976
+ };
977
+
978
+ // src/config.ts
979
+ var globalConfig = {
980
+ envExtra: true,
981
+ outDir: "dist",
982
+ watch: true,
983
+ clearRestartLogs: true,
984
+ minify: false,
985
+ sourcemap: false,
986
+ nodeOptions: [],
987
+ antiCrash: true
988
+ };
989
+ function getConfig() {
990
+ return globalConfig;
991
+ }
992
+ var requiredProps = ["src", "main"];
993
+ function defineConfig(config) {
994
+ for (const prop of requiredProps) {
995
+ if (!config[prop]) {
996
+ throw new Error(`[CommandKit Config] Missing required config property: ${prop}`);
997
+ }
998
+ }
999
+ globalConfig = {
1000
+ ...globalConfig,
1001
+ ...config
1002
+ };
1003
+ return globalConfig;
1004
+ }
1005
+
1006
+ // src/utils/signal.ts
1007
+ var context = [];
1008
+ function createSignal(value) {
1009
+ const subscribers = /* @__PURE__ */ new Set();
1010
+ let disposed = false;
1011
+ let val = value instanceof Function ? value() : value;
1012
+ const getter = () => {
1013
+ if (!disposed) {
1014
+ const running = getCurrentObserver();
1015
+ if (running)
1016
+ subscribers.add(running);
1017
+ }
1018
+ return val;
1019
+ };
1020
+ const setter = (newValue) => {
1021
+ if (disposed)
1022
+ return;
1023
+ val = newValue instanceof Function ? newValue(val) : newValue;
1024
+ for (const subscriber of subscribers) {
1025
+ subscriber();
1026
+ }
1027
+ };
1028
+ const dispose = () => {
1029
+ subscribers.clear();
1030
+ disposed = true;
1031
+ };
1032
+ return [getter, setter, dispose];
1033
+ }
1034
+ function createEffect(callback) {
1035
+ const execute = () => {
1036
+ context.push(execute);
1037
+ try {
1038
+ callback();
1039
+ } finally {
1040
+ context.pop();
1041
+ }
1042
+ };
1043
+ execute();
1044
+ }
1045
+ function getCurrentObserver() {
1046
+ return context[context.length - 1];
1047
+ }
888
1048
  export {
1049
+ ButtonKit,
889
1050
  CommandKit,
890
- CommandType,
891
- ReloadType
1051
+ createEffect,
1052
+ createSignal,
1053
+ defineConfig,
1054
+ getConfig
892
1055
  };