@went.tf/discord-bot-framework 2.0.0 → 2.2.0

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 (65) hide show
  1. package/README.md +113 -35
  2. package/build/.tsbuildinfo +1 -1
  3. package/build/commands/build-application-commands-body.d.ts +13 -2
  4. package/build/commands/build-application-commands-body.d.ts.map +1 -1
  5. package/build/commands/build-application-commands-body.js +42 -2
  6. package/build/commands/build-application-commands-body.js.map +1 -1
  7. package/build/commands/schema/application-command-leaf-option.schema.d.ts +9 -9
  8. package/build/commands/schema/application-command-leaf-option.schema.js +9 -9
  9. package/build/commands/schema/application-command-leaf-option.schema.js.map +1 -1
  10. package/build/commands/schema/application-command-leaf-option.schema.json +36 -9
  11. package/build/commands/schema/application-command-subcommand-group.schema.d.ts +1 -1
  12. package/build/commands/schema/application-command-subcommand-group.schema.js +1 -1
  13. package/build/commands/schema/application-command-subcommand-group.schema.js.map +1 -1
  14. package/build/commands/schema/application-command-subcommand-group.schema.json +4 -1
  15. package/build/commands/schema/application-command-subcommand.schema.d.ts +1 -1
  16. package/build/commands/schema/application-command-subcommand.schema.js +1 -1
  17. package/build/commands/schema/application-command-subcommand.schema.js.map +1 -1
  18. package/build/commands/schema/application-command-subcommand.schema.json +4 -1
  19. package/build/commands/schema/application-command-type.schema.d.ts +2 -2
  20. package/build/commands/schema/application-command-type.schema.d.ts.map +1 -1
  21. package/build/commands/schema/application-command-type.schema.js +2 -2
  22. package/build/commands/schema/application-command-type.schema.js.map +1 -1
  23. package/build/commands/schema/application-command-type.schema.json +5 -2
  24. package/build/commands/schema/application-integration-type.schema.d.ts +2 -2
  25. package/build/commands/schema/application-integration-type.schema.d.ts.map +1 -1
  26. package/build/commands/schema/application-integration-type.schema.js +2 -2
  27. package/build/commands/schema/application-integration-type.schema.js.map +1 -1
  28. package/build/commands/schema/application-integration-type.schema.json +4 -2
  29. package/build/commands/schema/channel-type.schema.d.ts +2 -2
  30. package/build/commands/schema/channel-type.schema.d.ts.map +1 -1
  31. package/build/commands/schema/channel-type.schema.js +6 -2
  32. package/build/commands/schema/channel-type.schema.js.map +1 -1
  33. package/build/commands/schema/channel-type.schema.json +12 -2
  34. package/build/commands/schema/chat-input-command.schema.d.ts +1 -1
  35. package/build/commands/schema/chat-input-command.schema.js +1 -1
  36. package/build/commands/schema/chat-input-command.schema.js.map +1 -1
  37. package/build/commands/schema/chat-input-command.schema.json +4 -1
  38. package/build/commands/schema/command-file-entry.schema.d.ts +16 -0
  39. package/build/commands/schema/command-file-entry.schema.d.ts.map +1 -0
  40. package/build/commands/schema/command-file-entry.schema.js +14 -0
  41. package/build/commands/schema/command-file-entry.schema.js.map +1 -0
  42. package/build/commands/schema/command-file-entry.schema.json +11 -0
  43. package/build/commands/schema/commands-file.schema.d.ts +38 -12
  44. package/build/commands/schema/commands-file.schema.d.ts.map +1 -1
  45. package/build/commands/schema/commands-file.schema.js +30 -10
  46. package/build/commands/schema/commands-file.schema.js.map +1 -1
  47. package/build/commands/schema/commands-file.schema.json +25 -10
  48. package/build/commands/schema/context-menu-command.schema.d.ts +1 -1
  49. package/build/commands/schema/context-menu-command.schema.js +1 -1
  50. package/build/commands/schema/context-menu-command.schema.js.map +1 -1
  51. package/build/commands/schema/context-menu-command.schema.json +3 -1
  52. package/build/commands/schema/enum-maps.d.ts +52 -0
  53. package/build/commands/schema/enum-maps.d.ts.map +1 -0
  54. package/build/commands/schema/enum-maps.js +54 -0
  55. package/build/commands/schema/enum-maps.js.map +1 -0
  56. package/build/commands/schema/index.d.ts +58 -4
  57. package/build/commands/schema/index.d.ts.map +1 -1
  58. package/build/commands/schema/index.js +76 -3
  59. package/build/commands/schema/index.js.map +1 -1
  60. package/build/commands/schema/interaction-context-type.schema.d.ts +2 -2
  61. package/build/commands/schema/interaction-context-type.schema.d.ts.map +1 -1
  62. package/build/commands/schema/interaction-context-type.schema.js +2 -2
  63. package/build/commands/schema/interaction-context-type.schema.js.map +1 -1
  64. package/build/commands/schema/interaction-context-type.schema.json +5 -2
  65. package/package.json +1 -1
package/README.md CHANGED
@@ -162,27 +162,53 @@ autocomplete?, modal? }`) no longer describe their own wire shape at all.
162
162
  below):
163
163
 
164
164
  ```json
165
- [
166
- { "type": 1, "name": "ping", "description": "Replies with pong" },
167
- {
168
- "type": 1,
169
- "name": "search",
170
- "description": "Search for something",
171
- "options": [
172
- { "type": 3, "name": "query", "description": "Query string", "required": true }
173
- ]
174
- }
175
- ]
165
+ {
166
+ "$schema": "./commands.schema.json",
167
+ "commands": [
168
+ { "type": "CHAT_INPUT", "name": "ping", "description": "Replies with pong" },
169
+ {
170
+ "type": "CHAT_INPUT",
171
+ "name": "search",
172
+ "description": "Search for something",
173
+ "options": [
174
+ { "type": "STRING", "name": "query", "description": "Query string", "required": true }
175
+ ]
176
+ }
177
+ ]
178
+ }
176
179
  ```
177
180
 
181
+ The `{ "$schema", "commands" }` wrapper is what makes `commands.json`
182
+ editable with real autocomplete/validation in VS Code, JetBrains, or any
183
+ other JSON-Schema-aware editor: `$schema` is only ever valid on a JSON
184
+ *object*, and a bare array can never carry one. A **bare array** (just
185
+ the `commands` value on its own, no wrapper) is still fully supported —
186
+ nothing about the wrapper is required — but you lose the inline `$schema`
187
+ editor hookup if you use it. `buildApplicationCommandsBody` accepts
188
+ either shape directly.
189
+
190
+ `type` (and `contexts`/`integration_types`/`channel_types`) accept either
191
+ Discord's raw numeric value or the UPPER_SNAKE_CASE string alias shown
192
+ above — nobody should have to remember that `3` means `STRING`. Both
193
+ forms, and any mix of the two, are always valid; `buildApplicationCommandsBody`
194
+ resolves whichever form was used to its real numeric value right before
195
+ writing each command/option into the final REST body, using the mapping
196
+ in `./commands/schema`'s `enum-maps.ts` (sourced from `discord-api-types`'
197
+ own enums, not hand-duplicated numbers, so it can't drift). The numeric
198
+ form still works and always will — this is additive, not a replacement.
199
+
178
200
  2. Parse and validate it before doing anything else with it:
179
201
 
180
202
  ```ts
181
203
  import { Ajv } from 'ajv';
182
- import { parseCommandsFile, registerFrameworkSchemas } from '@went.tf/discord-bot-framework/commands/schema';
183
- import myCommandsSchema from './commands.schema.json' with { type: 'json' };
204
+ import { parseCommandsFile, registerFrameworkSchemas, resolveCommandsSchemaRefs } from '@went.tf/discord-bot-framework/commands/schema';
205
+ import myCommandsSchemaRaw from './commands.schema.json' with { type: 'json' };
184
206
  import commandsData from './commands.json' with { type: 'json' };
185
207
 
208
+ // Rewrites your schema's relative-path $refs (into node_modules) to each
209
+ // fragment's real ajv-resolvable identity - see "JSON Schema fragments" below.
210
+ const myCommandsSchema = resolveCommandsSchemaRefs(myCommandsSchemaRaw);
211
+
186
212
  const ajv = new Ajv({ allErrors: true, allowUnionTypes: true });
187
213
  registerFrameworkSchemas(ajv);
188
214
  const validate = ajv.compile(myCommandsSchema);
@@ -233,37 +259,89 @@ This package ships only the **generic, reusable JSON Schema building
233
259
  blocks** mirroring `discord-api-types`' command/option shapes — it does not
234
260
  dictate one rigid schema for your whole `commands.json` file. Compose your
235
261
  own schema on top via `$ref`/`allOf`, e.g. to narrow `name` to an enum of
236
- your bot's actual command names:
262
+ your bot's actual command names. Since a bot's own `commands.schema.json` is
263
+ authored as plain JSON (so external tools can consume it too, not just this
264
+ package's TS composition helpers), supporting **both** the bare-array and
265
+ the `{ $schema, commands }` root shapes over the same narrowed entry uses a
266
+ local `$defs` entry referenced from both branches:
237
267
 
238
268
  ```json
239
269
  {
240
- "$id": "https://schema.your-bot.example/commands-file.json",
241
- "type": "array",
242
- "items": {
243
- "oneOf": [
244
- {
245
- "allOf": [
246
- { "$ref": "https://schema.went.tf/discord-bot-framework/chat-input-command.json" },
247
- { "properties": { "name": { "enum": ["ping", "search"] } } }
248
- ]
270
+ "$defs": {
271
+ "entry": {
272
+ "oneOf": [
273
+ {
274
+ "allOf": [
275
+ { "$ref": "../node_modules/@went.tf/discord-bot-framework/build/commands/schema/chat-input-command.json" },
276
+ { "properties": { "name": { "enum": ["ping", "search"] } } }
277
+ ]
278
+ },
279
+ { "$ref": "../node_modules/@went.tf/discord-bot-framework/build/commands/schema/context-menu-command.json" }
280
+ ]
281
+ }
282
+ },
283
+ "oneOf": [
284
+ { "type": "array", "items": { "$ref": "#/$defs/entry" } },
285
+ {
286
+ "type": "object",
287
+ "properties": {
288
+ "$schema": { "type": "string" },
289
+ "commands": { "type": "array", "items": { "$ref": "#/$defs/entry" } }
249
290
  },
250
- { "$ref": "https://schema.went.tf/discord-bot-framework/context-menu-command.json" }
251
- ]
252
- }
291
+ "required": ["commands"],
292
+ "additionalProperties": false
293
+ }
294
+ ]
253
295
  }
254
296
  ```
255
297
 
256
- Call `registerFrameworkSchemas(ajv)` before compiling your own schema so its
257
- `$ref`s resolve. The fragments this package ships (all under
298
+ `$ref` uses a **real relative filesystem path** into `node_modules` (the
299
+ exact `../` count doesn't have to be exactly right — see below) rather than
300
+ an opaque URL — this is what makes an editor (VS Code, JetBrains, ...)
301
+ actually able to follow it and offer real autocomplete/validation while you
302
+ hand-edit `commands.schema.json`, since it points at a real file: this
303
+ package ships its raw fragment `.json` mirrors precisely so a path like this
304
+ resolves to something real on disk, no network access involved.
305
+
306
+ **ajv** can't follow that same relative path directly — it resolves relative
307
+ `$ref`s via real RFC3986 URI resolution against the referencing schema's own
308
+ `$id`, and `node_modules` is virtualized under a symlinked store by pnpm (and
309
+ similar tools), so there is no `$id` value that makes ajv's own resolution
310
+ land on the right file for every install. `resolveCommandsSchemaRefs()`
311
+ sidesteps this: it rewrites any `$ref` matching a shipped fragment's
312
+ filename to that fragment's canonical `$id` (whatever relative-path prefix
313
+ you used), which `registerFrameworkSchemas(ajv)` has already registered.
314
+ Your own local refs (e.g. `#/$defs/...`) are left untouched:
315
+
316
+ ```ts
317
+ import myCommandsSchemaRaw from './commands.schema.json' with { type: 'json' };
318
+ const myCommandsSchema = resolveCommandsSchemaRefs(myCommandsSchemaRaw);
319
+ registerFrameworkSchemas(ajv); // before ajv.compile(myCommandsSchema)
320
+ ```
321
+
322
+ If you don't need the name-narrowing (or any other bot-specific constraint),
323
+ skip authoring your own schema entirely and validate directly against this
324
+ package's own `commandsFileSchema` — it already accepts both root shapes.
325
+
326
+ The fragments this package ships (all under
258
327
  `@went.tf/discord-bot-framework/commands/schema`, and as real standalone
259
328
  `.json` files under `build/commands/schema/` for non-TS tooling):
260
- `commands-file`, `chat-input-command`, `context-menu-command`,
261
- `application-command-option` (and its `application-command-leaf-option`/
262
- `application-command-subcommand`/`application-command-subcommand-group`
263
- building blocks), `application-command-option-choice`,
264
- `default-member-permissions`, `option-name`, `context-menu-name`,
265
- `application-command-type`, `interaction-context-type`,
266
- `application-integration-type`, `channel-type`.
329
+ `commands-file`, `command-file-entry`, `chat-input-command`,
330
+ `context-menu-command`, `application-command-option` (and its
331
+ `application-command-leaf-option`/`application-command-subcommand`/
332
+ `application-command-subcommand-group` building blocks),
333
+ `application-command-option-choice`, `default-member-permissions`,
334
+ `option-name`, `context-menu-name`, `application-command-type`,
335
+ `interaction-context-type`, `application-integration-type`, `channel-type`.
336
+
337
+ `./commands/schema` also exports `enum-maps.ts`'s `APPLICATION_COMMAND_TYPE_MAP`,
338
+ `APPLICATION_COMMAND_OPTION_TYPE_MAP`, `INTERACTION_CONTEXT_TYPE_MAP`,
339
+ `APPLICATION_INTEGRATION_TYPE_MAP`, `CHANNEL_TYPE_MAP`, and `resolveEnumValue` —
340
+ the same lookup tables `buildApplicationCommandsBody` uses internally to
341
+ resolve `commands.json`'s UPPER_SNAKE_CASE string aliases, exported in case
342
+ other tooling built on top of this package needs the same mapping (e.g. a
343
+ linter or a codemod converting old numeric `commands.json` files to the
344
+ string form).
267
345
 
268
346
  Base fragments use `additionalProperties: false` for strictness — if your
269
347
  bot needs a genuinely new top-level field per command entry, you'll need