@unbound-app/api 0.11.0 → 1.1.1

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.
Files changed (72) hide show
  1. package/ambient/image-modules.d.ts +58 -0
  2. package/package.json +27 -4
  3. package/src/_internal.d.ts +2775 -139
  4. package/src/{utils.d.ts → _types.d.ts} +10 -0
  5. package/src/assets.d.ts +64 -26
  6. package/src/builtins.d.ts +17 -0
  7. package/src/commands.d.ts +101 -25
  8. package/src/dialogs.d.ts +90 -25
  9. package/src/flux.d.ts +317 -0
  10. package/src/fonts.d.ts +51 -0
  11. package/src/fs.d.ts +15 -24
  12. package/src/global.d.ts +173 -11
  13. package/src/i18n.d.ts +33 -31
  14. package/src/iconPacks.d.ts +43 -0
  15. package/src/index.d.ts +14 -0
  16. package/src/marketplace.d.ts +50 -0
  17. package/src/metro/api.d.ts +8 -0
  18. package/src/metro/common.d.ts +34 -5
  19. package/src/metro/components.d.ts +34 -25
  20. package/src/metro/filters.d.ts +31 -16
  21. package/src/metro/index.d.ts +26079 -83
  22. package/src/metro/stores.d.ts +5 -0
  23. package/src/native.d.ts +77 -5
  24. package/src/patcher.d.ts +214 -57
  25. package/src/plugins.d.ts +55 -0
  26. package/src/settings.d.ts +8 -16
  27. package/src/shims.d.ts +5 -0
  28. package/src/storage.d.ts +80 -224
  29. package/src/sync.d.ts +51 -0
  30. package/src/themes.d.ts +43 -0
  31. package/src/toasts.d.ts +62 -9
  32. package/src/ui.d.ts +650 -0
  33. package/src/updates.d.ts +25 -0
  34. package/src/utils/index.d.ts +53 -0
  35. package/src/utils/react/index.d.ts +82 -0
  36. package/testing/fake-api.ts +256 -0
  37. package/testing/fake-components.ts +183 -0
  38. package/testing/fake-feedback.ts +258 -0
  39. package/testing/fake-fs.ts +54 -0
  40. package/testing/fake-java.ts +513 -0
  41. package/testing/fake-locales.ts +85 -0
  42. package/testing/fake-metro.ts +346 -0
  43. package/testing/fake-native-bridge.ts +98 -0
  44. package/testing/fake-native.ts +211 -0
  45. package/testing/fake-objc.ts +388 -0
  46. package/testing/fake-plugins.ts +176 -0
  47. package/testing/fake-react-native-modules.ts +362 -0
  48. package/testing/fake-react-native.ts +180 -0
  49. package/testing/fake-react.ts +54 -0
  50. package/testing/fake-settings-panel.ts +173 -0
  51. package/testing/fake-settings.ts +428 -0
  52. package/testing/fake-timers.ts +74 -0
  53. package/testing/fake-utils.ts +216 -0
  54. package/testing/icu-format.ts +132 -0
  55. package/testing/icu-parse.ts +277 -0
  56. package/testing/index.ts +42 -0
  57. package/testing/install-addon-globals.ts +260 -0
  58. package/testing/listener-registry.ts +39 -0
  59. package/testing/memory-storage.ts +149 -0
  60. package/testing/plugin-files.ts +155 -0
  61. package/testing/plugin-lifecycle.ts +149 -0
  62. package/testing/plugin-types.ts +34 -0
  63. package/testing/preset.ts +263 -0
  64. package/testing/react-patcher.ts +154 -0
  65. package/testing/react-value.ts +3 -0
  66. package/testing/recorders.ts +183 -0
  67. package/testing/recording-patcher.ts +173 -0
  68. package/testing/render.ts +84 -0
  69. package/testing/session.ts +77 -0
  70. package/testing/test-node.ts +163 -0
  71. package/testing/test-renderer.ts +753 -0
  72. package/testing/unfrozen-elements.ts +49 -0
@@ -4,10 +4,14 @@ import * as ReactModule from 'react';
4
4
  import * as ReactNativeModule from 'react-native';
5
5
  /** Any supported colour string: a {@link HexColor} or {@link RgbaColor}. */
6
6
  export type ColorString = HexColor | RgbaColor;
7
+ /** A Unicode emoji, or a custom emoji's name then `:` and its id. */
8
+ export type EmojiString = string;
7
9
  /** The set of all falsy values. */
8
10
  export type Falsy = false | 0 | '' | null | undefined;
9
11
  /** A hexadecimal colour string prefixed with `#`. */
10
12
  export type HexColor = `#${string}`;
13
+ /** An http or https URL, as a `url` setting holds it. */
14
+ export type HttpUrl = `https://${string}` | `http://${string}`;
11
15
  /**
12
16
  * A string union that keeps `T`'s literals for autocomplete while still accepting any other string,
13
17
  * for Discord's open-ended enums (typography variants, colour tokens, sizes).
@@ -17,6 +21,8 @@ export type LiteralUnion<T extends string> = T | (string & {});
17
21
  export type PredicateResult = Truthy | false | null | undefined;
18
22
  /** An `rgba(...)` colour string. */
19
23
  export type RgbaColor = `rgba(${string})`;
24
+ /** A Discord id. */
25
+ export type Snowflake = `${bigint}`;
20
26
  /** The set of all truthy values. */
21
27
  export type Truthy = true | number | string | object | symbol | bigint;
22
28
  /** Widens a literal type to its primitive base (e.g. `'a'` to `string`, `1` to `number`). */
@@ -27,5 +33,9 @@ export type Widen<T> = T extends number
27
33
  : T extends boolean
28
34
  ? boolean
29
35
  : T;
36
+ /** `T` without the keys `K`. Unlike `Omit`, it keeps the known keys of a type that also has an index signature. */
37
+ export type Without<T, K extends PropertyKey> = {
38
+ [Key in keyof T as Key extends K ? never : Key]: T[Key];
39
+ };
30
40
 
31
41
  export {};
package/src/assets.d.ts CHANGED
@@ -1,51 +1,89 @@
1
1
  // Auto-generated by generate-plugin-sdk.ts - DO NOT EDIT
2
2
 
3
- export type { UnboundAsset } from './_internal';
4
- import type { UnboundAsset } from './_internal';
5
- declare const _default: {
6
- assets: Map<number, UnboundAsset>;
7
- find: typeof find;
8
- getByName: typeof getByName;
9
- getByID: typeof getByID;
10
- getIDByName: typeof getIDByName;
11
- getAll: typeof getAll;
12
- Icons: Record<string, number | undefined>;
13
- };
14
- /** Proxy resolving any property name to its asset id via {@link getIDByName}. */
15
- export declare const Icons: Record<string, number | undefined>;
16
- /** Map of discovered asset ids to their resolved {@link UnboundAsset} record. */
3
+ export type { AssetName, AssetType, DiscordAssetName, UnboundAsset } from './_internal';
4
+ import type { AssetName, AssetType, DiscordAssetName, UnboundAsset } from './_internal';
5
+ /** Map of registered asset ids to their {@link UnboundAsset} record. */
17
6
  export declare const assets: Map<number, UnboundAsset>;
7
+ /** Proxy resolving any property name to its PNG asset id via {@link getIdByName}; Discord's names are suggested. */
8
+ export declare const icons: Readonly<Partial<Record<DiscordAssetName<'png'>, number>>> &
9
+ Readonly<Record<string, number | undefined>>;
18
10
  /**
19
- * @description Finds the first known asset matching the given predicate.
11
+ * @description Finds the first asset matching the given predicate, initializing every asset module first.
20
12
  * @param filter Predicate run against each asset.
21
13
  * @returns The matched {@link UnboundAsset}, or `undefined` if none match.
22
14
  */
23
15
  export declare function find(filter: (asset: UnboundAsset) => boolean): UnboundAsset | undefined;
24
16
  /**
25
- * @description Returns every known asset.
17
+ * @description Returns every asset, initializing every asset module first.
26
18
  * @returns An array of all registered {@link UnboundAsset} records.
27
19
  */
28
20
  export declare function getAll(): UnboundAsset[];
29
21
  /**
30
- * @description Looks up a known asset by its id.
22
+ * @description Looks up a registered asset by its id.
31
23
  * @param id The asset id to look up.
32
24
  * @returns The matched {@link UnboundAsset}, or `undefined` if none is registered for that id.
33
25
  */
34
- export declare function getByID(id: number): UnboundAsset | undefined;
26
+ export declare function getById(id: number): UnboundAsset | undefined;
35
27
  /**
36
- * @description Finds a known asset by its name and type.
28
+ * @description Finds an asset by its name and type, initializing the module that registers it if needed.
29
+ * @template T The asset's file type, which picks the names suggested for `name`.
37
30
  * @param name The asset name to match.
38
- * @param type The asset type to match.
31
+ * @param type The asset type to match, `png` by default.
39
32
  * @returns The matched {@link UnboundAsset}, or `undefined` if none match.
40
33
  */
41
- export declare function getByName(name: string, type?: 'svg' | 'png'): UnboundAsset | undefined;
34
+ export declare function getByName<T extends AssetType = 'png'>(
35
+ name: AssetName<T>,
36
+ type?: T,
37
+ ): UnboundAsset | undefined;
42
38
  /**
43
- * @description Looks up a known asset's id by its name and type.
39
+ * @description Looks up an asset's id by its name and type, initializing the module that registers it if needed.
40
+ * @template T The asset's file type, which picks the names suggested for `name`.
44
41
  * @param name The asset name to match.
45
- * @param type The asset type to match.
42
+ * @param type The asset type to match, `png` by default.
46
43
  * @returns The matched asset's id, or `undefined` if none match.
47
44
  */
48
- export declare function getIDByName(name: string, type?: 'svg' | 'png'): number | undefined;
49
- export { _default as default };
50
-
45
+ export declare function getIdByName<T extends AssetType = 'png'>(
46
+ name: AssetName<T>,
47
+ type?: T,
48
+ ): number | undefined;
49
+ /**
50
+ * @description Calls `listener` with each asset registered from now on.
51
+ * @param listener Receives the asset and its id.
52
+ * @returns A function that removes the listener.
53
+ */
54
+ export declare function onAssetRegistered(listener: AssetRegistrationListener): () => void;
55
+ /**
56
+ * @description Registers an image generated at runtime, such as a `data:` URI or a file the plugin wrote, with
57
+ * Discord's asset registry, so `<Image source={id}>` and Discord's icon props draw it. Images a plugin imports
58
+ * are registered for it. A plugin's names never collide with another's, and its registrations end when it stops.
59
+ * @param options The image: its name, `uri` or `path`, size in points, type and other `scales`.
60
+ * @returns The asset's id, and `unregister`.
61
+ */
62
+ export declare function register(options: AssetRegistration): RegisteredAsset;
63
+ /** An image to register with Discord's asset registry, so `<Image source={id}>` and Discord's icon props draw it. */
64
+ export type AssetRegistration = {
65
+ /** The asset's name; a plugin's names are kept apart from every other plugin's. */
66
+ name: string;
67
+ /** The image's URI at scale 1, such as a `data:` or `file://` URI. */
68
+ uri?: string;
69
+ /** The image file at scale 1, as an absolute path such as `${fs.documentsPath}/MyPlugin/star.png`. */
70
+ path?: string;
71
+ /** Width in points. */
72
+ width: number;
73
+ /** Height in points. */
74
+ height: number;
75
+ /** The file type, such as `png`. */
76
+ type: string;
77
+ /** The image at other pixel densities, as URIs or absolute paths by scale, such as `{ 2: '/…/star@2x.png' }`. */
78
+ scales?: Record<number, string>;
79
+ };
80
+ /** Called with each asset Discord registers, and its id. */
81
+ export type AssetRegistrationListener = (asset: UnboundAsset, id: number) => void;
82
+ /** A registered asset: its id, and the function that takes it out of the registry. */
83
+ export type RegisteredAsset = {
84
+ /** The asset registry id, which an image `source` or an `icon` option takes. */
85
+ id: number;
86
+ /** Takes the asset out of the registry; registering its name again reuses the id. */
87
+ unregister: () => void;
88
+ };
51
89
  export {};
@@ -0,0 +1,17 @@
1
+ // Auto-generated by generate-plugin-sdk.ts - DO NOT EDIT
2
+
3
+ /** Starts a built-in feature under a name, skipping a name already registered. */
4
+ export declare const register: (name: string, builtin: BuiltIn) => void;
5
+ /** Stops the built-in feature registered under a name. */
6
+ export declare const unregister: (name: string) => void;
7
+ /** A built-in feature exposing optional `start`/`stop` lifecycle hooks. */
8
+ export type BuiltIn = {
9
+ /** Runs when the built-in is registered; if it throws, the built-in is logged and left inactive. */
10
+ start?: () => void;
11
+ /** Runs when the built-in is unregistered or the built-ins shut down, in reverse start order. */
12
+ stop?: () => void;
13
+ /** Checked once at initialisation; returning `false` skips registering the built-in. */
14
+ shouldStart?: () => boolean;
15
+ };
16
+
17
+ export {};
package/src/commands.d.ts CHANGED
@@ -1,20 +1,29 @@
1
1
  // Auto-generated by generate-plugin-sdk.ts - DO NOT EDIT
2
2
 
3
- declare const _default: {
4
- createCommands: typeof createCommands;
5
- option: OptionBuilders;
6
- };
7
3
  declare const valueType: unique symbol;
8
- /** Option builders, one per kind: `option.string({ required: true })`, `option.user()`, `option.choice([...])`. */
4
+ /** Option builders, one per kind: `option.string({ required: true })`, `option.user()`, `option.choice({ ... })`. */
9
5
  export declare const option: OptionBuilders;
10
6
  /**
11
7
  * @description Creates the commands handle for one owner, like `createPatcher` does for patches. A plugin passes
12
- * its manifest id, so its commands are removed when it stops; a built-in passes `'unbound'`.
8
+ * its manifest id, so its commands are removed when it stops; a built-in passes `'unbound'`. Text is message keys.
13
9
  * @param owner The plugin id, or `'unbound'` for a built-in.
14
10
  * @param options The owner's own picker section; omitted, the shared Unbound section.
15
11
  * @returns The handle.
16
12
  */
17
13
  export declare function createCommands(owner: string, options?: CommandsOptions): CommandsHandle;
14
+ /**
15
+ * @description Adds commands to the shared Unbound section of the `/` picker. Registering a root name again
16
+ * replaces that whole command; a root name another owner has throws `CommandDefinitionError`.
17
+ * @template T The command tree, inferred from it.
18
+ * @param commands The commands, keyed by root name.
19
+ * @returns A function that removes this call's commands; it is safe to call twice.
20
+ */
21
+ export declare function register<T>(commands: CommandTree<T>): () => void;
22
+ /**
23
+ * @description Removes a root command added with `register`, with its subcommands. Does nothing when there is none.
24
+ * @param name The root command's name.
25
+ */
26
+ export declare function unregister(name: string): void;
18
27
  /** Suggests values for an option while the user types. At most 25 are shown. */
19
28
  export type Autocomplete<V extends string | number> = (
20
29
  query: string,
@@ -28,7 +37,9 @@ export type AutocompleteContext = CommandContext & {
28
37
  export type Awaitable<T> = T | Promise<T>;
29
38
  /** Settings every builder accepts. */
30
39
  export type BuilderInput<K extends OptionKind, R extends boolean> = OptionSettings<K> & {
31
- description?: string;
40
+ /** The message key of the text the picker shows for the option; 1 to 100 characters in en-US. Omitted, its name. */
41
+ description?: CommandMessageKey;
42
+ /** Whether Discord requires the option. Defaults to `false`. */
32
43
  required?: R;
33
44
  };
34
45
  /** Settings of `option.channel`. */
@@ -36,52 +47,74 @@ export type ChannelOptionSettings = {
36
47
  /** Discord channel types the picker offers. */
37
48
  channelTypes?: readonly number[];
38
49
  };
39
- /** A choice or suggestion: a bare value, shown as itself, or a value with a label. */
50
+ /** An autocomplete suggestion: a bare value, shown as itself, or a value with a label. */
40
51
  export type Choice<V extends string | number> = V | ChoiceWithLabel<V>;
41
52
  /** Settings `option.choice` accepts. */
42
53
  export type ChoiceInput<R extends boolean> = {
43
- description?: string;
54
+ /** The message key of the text the picker shows for the option; 1 to 100 characters in en-US. Omitted, its name. */
55
+ description?: CommandMessageKey;
56
+ /** Whether Discord requires the option. Defaults to `false`. */
44
57
  required?: R;
45
58
  };
46
- /** The kind a choice list maps to: strings are a string option, numbers an integer or number option. */
47
- export type ChoiceKind<V extends string | number> = V extends string
48
- ? 'string'
49
- : 'integer' | 'number';
50
- /** A value with the label the picker shows for it. */
59
+ /** Each value `option.choice` allows, mapped to the message key of its label. Labels must differ in en-US. */
60
+ export type ChoiceMap = Readonly<Record<string, CommandMessageKey>>;
61
+ /** An autocomplete suggestion's value with the label the picker shows for it. */
51
62
  export type ChoiceWithLabel<V extends string | number> = {
63
+ /** The text the picker shows: data, such as a name, so it is not a message key. */
52
64
  label: string;
65
+ /** The value the handler receives when this choice is picked. */
53
66
  value: V;
54
67
  };
55
68
  /** A Discord channel, as the channel store returns it. */
56
69
  export type CommandChannel = {
70
+ /** The channel's Discord snowflake id. */
57
71
  id: string;
72
+ /** Discord's numeric channel type, such as `0` for a guild text channel or `1` for a DM. */
58
73
  type: number;
74
+ /** The channel name; DMs may have none. */
59
75
  name?: string;
76
+ /** The id of the guild the channel belongs to; `null` or absent for DMs and group DMs. */
60
77
  guild_id?: string | null;
61
78
  };
62
79
  /** Where a command runs. Discord never runs a command without a channel. */
63
80
  export type CommandContext = {
81
+ /** The channel the command was sent in. */
64
82
  channel: CommandChannel;
83
+ /** The guild of that channel; `undefined` in DMs and group DMs. */
65
84
  guild: CommandGuild | undefined;
66
85
  };
67
86
  /** A command that only groups subcommands: `/root sub` or `/root group sub`. */
68
87
  export type CommandGroup<S> = {
69
- description: string;
88
+ /** The message key of the text the picker shows under the group name; 1 to 100 characters in en-US. */
89
+ description: CommandMessageKey;
90
+ /** The group's commands keyed by name, 1 to 25 of them. */
70
91
  subcommands: CommandTree<S>;
92
+ /** Never set on a group; only a {@link LeafCommand} takes options. */
71
93
  options?: never;
94
+ /** Never set on a group; only a {@link LeafCommand} runs. */
72
95
  execute?: never;
73
96
  };
74
97
  /** A Discord guild. */
75
98
  export type CommandGuild = {
99
+ /** The guild's Discord snowflake id. */
76
100
  id: string;
101
+ /** The guild's display name. */
77
102
  name: string;
78
103
  };
104
+ /**
105
+ * A key of the owner's `i18n/en-US.json`. The picker shows its message in the user's locale, falling back to en-US;
106
+ * a plugin's keys come from its generated `src/unbound-i18n.d.ts`.
107
+ */
108
+ export type CommandMessageKey = Extract<keyof UnboundMessageKeys, string>;
79
109
  /** A leaf or a group. */
80
110
  export type CommandNode<T> = LeafCommand<T> | CommandGroup<T>;
81
111
  /** A Discord guild role. */
82
112
  export type CommandRole = {
113
+ /** The role's Discord snowflake id. */
83
114
  id: string;
115
+ /** The role's display name. */
84
116
  name: string;
117
+ /** The role colour as a 24-bit RGB integer; `0` when the role has no colour. */
85
118
  color?: number;
86
119
  };
87
120
  /**
@@ -93,9 +126,13 @@ export type CommandTree<T> = {
93
126
  };
94
127
  /** A Discord user, as the user store returns it. Only the fields commands rely on. */
95
128
  export type CommandUser = {
129
+ /** The user's Discord snowflake id. */
96
130
  id: string;
131
+ /** The unique account name, without the `@`. */
97
132
  username: string;
133
+ /** The display name the user set; `null` or absent when they set none. */
98
134
  globalName?: string | null;
135
+ /** `true` for bot accounts. */
99
136
  bot?: boolean;
100
137
  };
101
138
  /** The handle `createCommands` returns, scoped to one owner. */
@@ -105,6 +142,8 @@ export type CommandsHandle = {
105
142
  * Returns a function that removes this call's commands; it is safe to call twice or after a sweep.
106
143
  */
107
144
  register<T>(commands: CommandTree<T>): () => void;
145
+ /** Removes this owner's root command `name` with its subcommands. Does nothing when there is none. */
146
+ unregister(name: string): void;
108
147
  /** Removes every command of this owner. */
109
148
  unregisterAll(): void;
110
149
  };
@@ -115,8 +154,11 @@ export type CommandsOptions = {
115
154
  };
116
155
  /** Shown only to the user, as a bot message. */
117
156
  export type EphemeralReply = {
157
+ /** Marks the reply as shown only to the user instead of sent. */
118
158
  ephemeral: true;
159
+ /** The message text; empty when absent. */
119
160
  content?: string;
161
+ /** Embeds shown under the text. */
120
162
  embeds?: readonly ReplyEmbed[];
121
163
  };
122
164
  /** An asset id from `assets.Icons`, or a `data:` or `https:` uri. */
@@ -126,16 +168,24 @@ export type IconSource = number | string;
126
168
  * `execute` uses method syntax so its parameter stays bivariant and the registry can hold it erased.
127
169
  */
128
170
  export type LeafCommand<O> = {
129
- description: string;
171
+ /** The message key of the text the picker shows under the command name; 1 to 100 characters in en-US. */
172
+ description: CommandMessageKey;
173
+ /** The command's options keyed by name, made with the `option` builders. At most 25. */
130
174
  options?: O;
175
+ /** Runs the command with the parsed options. A throw or rejection shows the user an ephemeral error. */
131
176
  execute(args: OptionArgs<O>, context: CommandContext): Awaitable<Reply>;
177
+ /** Never set on a leaf; a command with `subcommands` is a {@link CommandGroup}. */
132
178
  subcommands?: never;
133
179
  };
180
+ /** The settings of an option kind that takes none. */
134
181
  export type NoSettings = Record<never, never>;
135
182
  /** Settings of `option.integer` and `option.number`. */
136
183
  export type NumberOptionSettings = {
184
+ /** The smallest value Discord accepts, inclusive. */
137
185
  minValue?: number;
186
+ /** The largest value Discord accepts, inclusive. */
138
187
  maxValue?: number;
188
+ /** Suggests values while the user types; setting it turns on Discord's autocomplete for the option. */
139
189
  autocomplete?: Autocomplete<number>;
140
190
  };
141
191
  /** A handler's args, derived from its options: a required option is `V`, an optional one `V | undefined`. */
@@ -155,43 +205,50 @@ export type OptionBuilders = {
155
205
  [K in OptionKind]: OptionBuilder<K>;
156
206
  } & {
157
207
  /**
158
- * Restricts an option to listed values; the handler gets their literal union.
159
- * @param choices Values, or `{ label, value }` pairs. 1 to 25, with unique labels.
208
+ * Restricts a string option to listed values; the handler gets their literal union.
209
+ * @param choices Each value mapped to its label's message key, in picker order: `{ heads: 'COIN_HEADS' }`. 1 to 25.
160
210
  * @param settings The option's description and whether it is required.
161
211
  */
162
- choice<const V extends string | number, const R extends boolean = false>(
163
- choices: readonly Choice<V>[],
212
+ choice<const M extends ChoiceMap, const R extends boolean = false>(
213
+ choices: M,
164
214
  settings?: ChoiceInput<R>,
165
- ): OptionSpec<ChoiceKind<V>, R, V>;
215
+ ): OptionSpec<'string', R, keyof M & string>;
166
216
  };
167
217
  /** The option kinds: one builder each on `option`. */
168
218
  export type OptionKind = keyof OptionKindTypes;
169
219
  /** Each option kind's handler value and builder settings. The client's kind table implements every key. */
170
220
  export type OptionKindTypes = {
221
+ /** Free text. */
171
222
  string: {
172
223
  value: string;
173
224
  settings: StringOptionSettings;
174
225
  };
226
+ /** A whole number; a fractional value fails the command. */
175
227
  integer: {
176
228
  value: number;
177
229
  settings: NumberOptionSettings;
178
230
  };
231
+ /** Any finite number. */
179
232
  number: {
180
233
  value: number;
181
234
  settings: NumberOptionSettings;
182
235
  };
236
+ /** True or false. */
183
237
  boolean: {
184
238
  value: boolean;
185
239
  settings: NoSettings;
186
240
  };
241
+ /** A user, resolved from the picked id through Discord's user store. */
187
242
  user: {
188
243
  value: CommandUser;
189
244
  settings: NoSettings;
190
245
  };
246
+ /** A channel, resolved from the picked id through Discord's channel store. */
191
247
  channel: {
192
248
  value: CommandChannel;
193
249
  settings: ChannelOptionSettings;
194
250
  };
251
+ /** A role of the current guild, resolved from the picked id through Discord's role store. */
195
252
  role: {
196
253
  value: CommandRole;
197
254
  settings: NoSettings;
@@ -205,19 +262,28 @@ export type OptionSpec<
205
262
  R extends boolean = boolean,
206
263
  V = OptionValue<K>,
207
264
  > = {
265
+ /** The option kind; `option.choice` derives it from its values. */
208
266
  readonly kind: K;
267
+ /** Whether Discord requires the option. Defaults to `false`; required options are listed first. */
209
268
  readonly required: R;
269
+ /** The message key of the text the picker shows for the option; `undefined` shows the option's name. */
210
270
  readonly description: string | undefined;
271
+ /** The kind-specific settings given to the builder; empty for `option.choice`. */
211
272
  readonly settings: OptionSettings<K>;
212
- readonly choices: readonly Choice<string | number>[] | undefined;
273
+ /** Each value from `option.choice` mapped to its label's message key; `undefined` for every other builder. */
274
+ readonly choices: Readonly<Record<string, string>> | undefined;
275
+ /** Carries the handler's value type for inference only; never set at runtime. */
213
276
  readonly [valueType]?: V;
214
277
  };
215
278
  /** The value a handler receives for a kind. */
216
279
  export type OptionValue<K extends OptionKind> = OptionKindTypes[K]['value'];
217
280
  /** Sent by Discord as a normal message from the user. */
218
281
  export type PublicReply = {
282
+ /** The message text. An empty string sends nothing. */
219
283
  content: string;
284
+ /** Sends the message as text-to-speech. */
220
285
  tts?: boolean;
286
+ /** Absent or `false`; `true` makes the reply an {@link EphemeralReply}. */
221
287
  ephemeral?: false;
222
288
  };
223
289
  /** An option value as Discord passes it. User, channel and role options arrive as id strings. */
@@ -226,30 +292,40 @@ export type RawOptionValue = string | number | boolean;
226
292
  export type Reply = string | PublicReply | EphemeralReply | undefined | void;
227
293
  /** An embed in an ephemeral reply. */
228
294
  export type ReplyEmbed = {
295
+ /** The heading at the top of the embed. */
229
296
  title?: string;
297
+ /** The embed's body text, below the title. */
230
298
  description?: string;
299
+ /** A link the title opens. */
231
300
  url?: string;
301
+ /** The colour of the embed's side bar, as a 24-bit RGB integer such as `0x5865f2`. */
232
302
  color?: number;
303
+ /** Name and value pairs shown below the description. */
233
304
  fields?: readonly ReplyEmbedField[];
234
305
  };
235
306
  /** A field of an embed in an ephemeral reply. */
236
307
  export type ReplyEmbedField = {
308
+ /** The field's heading. */
237
309
  name: string;
310
+ /** The field's body text. */
238
311
  value: string;
312
+ /** Lays the field out beside neighbouring inline fields instead of on its own row. */
239
313
  inline?: boolean;
240
314
  };
241
315
  /** A section of the `/` picker owned by one owner. */
242
316
  export type SectionInput = {
317
+ /** The section's heading in the picker; also the author name on its ephemeral replies. Must not be blank. */
243
318
  name: string;
319
+ /** The section's icon and reply avatar. Omitted, Discord's default application command icon. */
244
320
  icon?: IconSource;
245
321
  };
246
322
  /** Settings of `option.string`. */
247
323
  export type StringOptionSettings = {
324
+ /** The fewest characters Discord accepts for the value. */
248
325
  minLength?: number;
326
+ /** The most characters Discord accepts for the value. */
249
327
  maxLength?: number;
328
+ /** Suggests values while the user types; setting it turns on Discord's autocomplete for the option. */
250
329
  autocomplete?: Autocomplete<string>;
251
330
  };
252
-
253
- export { _default as default };
254
-
255
331
  export {};
package/src/dialogs.d.ts CHANGED
@@ -1,25 +1,46 @@
1
1
  // Auto-generated by generate-plugin-sdk.ts - DO NOT EDIT
2
2
 
3
+ import type { MessageKey, FormatVars as MessageVars } from '@unbound-app/i18n';
3
4
  import * as React$1 from 'react';
4
5
  import { ComponentType } from 'react';
5
-
6
- declare const _default: {
7
- showDialog: typeof showDialog;
8
- confirm: typeof confirm$1;
9
- dismissAll: typeof dismissAll;
10
- start: typeof start;
11
- stop: typeof stop$1;
12
- };
13
6
  /**
14
- * @description Asks a yes-or-no question with a confirm and a cancel button.
15
- * @param options The question and the confirm button's label.
16
- * @returns Whether the user confirmed; closing the dialog any other way counts as no.
7
+ * @description Tells the user something in a dialog with one button, each text a message key.
8
+ * @template T The title's key.
9
+ * @template B The body's key.
10
+ * @param title The dialog's message key.
11
+ * @param options The `body` and `confirm` keys, and `titleVars` and `bodyVars` for keys with placeholders.
12
+ * @returns A promise that resolves once the dialog closes, however it closes.
17
13
  */
18
- declare function confirm$1(options: ConfirmOptions): Promise<boolean>;
19
- /** Closes any dialog still open. */
20
- declare function stop$1(): void;
14
+ declare function alert$1<T extends PlainMessageKey, B extends MessageKey = never>(
15
+ title: T,
16
+ options?: AlertOptions<T, B>,
17
+ ): Promise<void>;
21
18
  /**
22
- * @description Closes every dialog this API opened.
19
+ * @description Tells the user something in a dialog with one button, titled by a key with placeholders.
20
+ * @template T The title's key.
21
+ * @template B The body's key.
22
+ * @param title The dialog's message key.
23
+ * @param options `titleVars`, then the `body` and `confirm` keys, and `bodyVars` for a body with placeholders.
24
+ * @returns A promise that resolves once the dialog closes, however it closes.
25
+ */
26
+ declare function alert$1<T extends VarsMessageKey, B extends MessageKey = never>(
27
+ title: T,
28
+ options: AlertOptions<T, B>,
29
+ ): Promise<void>;
30
+ /**
31
+ * @description Asks a yes-or-no question with a confirm and a cancel button, each text a message key.
32
+ * @template T The title's key.
33
+ * @template B The body's key.
34
+ * @param title The question's message key.
35
+ * @param options The `body`, `confirm` and `cancel` keys, `titleVars` and `bodyVars` for keys with placeholders, and `destructive`.
36
+ * @returns Whether the user confirmed; cancel, the backdrop, the back gesture or a dismiss resolve `false`.
37
+ */
38
+ declare function confirm$1<T extends MessageKey, B extends MessageKey = never>(
39
+ title: T,
40
+ options: ConfirmOptions<T, B>,
41
+ ): Promise<boolean>;
42
+ /**
43
+ * @description Closes every dialog this API opened, running each one's `onDismiss`.
23
44
  */
24
45
  export declare function dismissAll(): void;
25
46
  /**
@@ -30,40 +51,84 @@ export declare function dismissAll(): void;
30
51
  * @returns The dialog's key and a function that closes it.
31
52
  */
32
53
  export declare function showDialog(options: AlertDialogProps): DialogHandle;
33
- /** Starts the dialogs API; it keeps no state until a dialog opens. */
34
- export declare function start(): void;
54
+ /** What {@link showDialog} shows: a title, an optional body and custom content, and buttons. */
35
55
  export type AlertDialogProps = {
56
+ /** The heading at the top of the dialog. */
36
57
  title: string;
58
+ /** Text shown below the title. */
37
59
  body?: string;
38
60
  /** A component rendered below the body, given a way to close the dialog. */
39
61
  content?: React$1.ComponentType<DialogContentProps>;
62
+ /** The action buttons, in order, before the cancel button. */
40
63
  buttons?: DialogButton[];
41
64
  /** Adds a cancel button last; a string sets its label. */
42
65
  cancel?: boolean | string;
43
66
  /** Runs when the cancel button closes the dialog. */
44
67
  onCancel?: () => void;
68
+ /** Runs when the dialog closes without a button: the backdrop, the back gesture, or its handle's `dismiss`. */
69
+ onDismiss?: () => void;
45
70
  };
46
- export type ConfirmOptions = {
47
- title: string;
48
- body?: string;
49
- confirmLabel: string;
50
- cancelLabel?: string;
51
- destructive?: boolean;
52
- };
71
+ /** What `alert` shows after its title key: the body and button keys, and the title's and body's vars. */
72
+ export type AlertOptions<T extends MessageKey, B extends MessageKey = never> = BodyOptions<B> &
73
+ KeyVars<T, 'titleVars'> & {
74
+ /** The key of the button that closes the dialog; Unbound's `OK` when omitted. */
75
+ confirm?: PlainMessageKey;
76
+ };
77
+ /** The optional body key of a dialog, and its vars when the message has placeholders. */
78
+ export type BodyOptions<B extends MessageKey> = {
79
+ /** The key of the text shown below the title. */
80
+ body?: B;
81
+ } & KeyVars<B, 'bodyVars'>;
82
+ /** What `confirm` asks after its title key: the body and button keys, and the title's and body's vars. */
83
+ export type ConfirmOptions<T extends MessageKey, B extends MessageKey = never> = BodyOptions<B> &
84
+ KeyVars<T, 'titleVars'> & {
85
+ /** The key of the button that resolves `true`. */
86
+ confirm: PlainMessageKey;
87
+ /** The key of the button that resolves `false`; Unbound's `Cancel` when omitted. */
88
+ cancel?: PlainMessageKey;
89
+ /** Styles the confirm button as `destructive` instead of `primary`. Use it whenever confirming loses data. */
90
+ destructive?: boolean;
91
+ };
92
+ /** One action button in a dialog opened by {@link showDialog}. */
53
93
  export type DialogButton = {
94
+ /** The text shown on the button. */
54
95
  label: string;
96
+ /** The button's style; `primary` when omitted. */
55
97
  variant?: DialogButtonVariant;
98
+ /** Runs after the press closes the dialog. */
56
99
  onPress?: () => void;
57
100
  };
101
+ /** A dialog button's style; the system alert fallback only distinguishes `destructive`. */
58
102
  export type DialogButtonVariant = 'primary' | 'secondary' | 'destructive';
103
+ /** The props a dialog's custom `content` component receives. */
59
104
  export type DialogContentProps = {
105
+ /** Closes the dialog without running any button's handler. */
60
106
  dismiss: () => void;
61
107
  };
108
+ /** An open dialog, as {@link showDialog} returns it. */
62
109
  export type DialogHandle = {
110
+ /** The `unbound-dialog-<uuid>` key the dialog was opened under in Discord's alert stack. */
63
111
  key: string;
112
+ /** Closes the dialog; does nothing once it is closed or when the system alert fallback showed it. */
64
113
  dismiss: () => void;
65
114
  };
115
+ /** An options field holding a key's placeholder values: required when the key has placeholders, absent otherwise. */
116
+ export type KeyVars<K extends MessageKey, Field extends string> = [K] extends [never]
117
+ ? {
118
+ [P in Field]?: never;
119
+ }
120
+ : K extends keyof MessageVars
121
+ ? {
122
+ [P in Field]: MessageVars[K];
123
+ }
124
+ : {
125
+ [P in Field]?: never;
126
+ };
127
+ /** A message key whose en-US text has no placeholders. */
128
+ export type PlainMessageKey = Exclude<MessageKey, keyof MessageVars>;
129
+ /** A message key whose en-US text has placeholders. */
130
+ export type VarsMessageKey = Extract<MessageKey, keyof MessageVars>;
66
131
 
67
- export { _default as default, confirm$1 as confirm, stop$1 as stop };
132
+ export { alert$1 as alert, confirm$1 as confirm };
68
133
 
69
134
  export {};