aurival 0.4.0 → 0.6.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.
package/README.md CHANGED
@@ -249,10 +249,11 @@ bot.on('member.joined', async (ctx) => {
249
249
 
250
250
  `Embed` is a builder — every `setAuthor`/`setThumbnail`/`addField`/`setFooter` call returns the
251
251
  same instance, so you chain them off the constructor. `Button` is a separate, flat object:
252
- `new Button({ label, id, style })`, where `style` is one of `'primary' | 'secondary' | 'danger'`
253
- — `'link'` isn't supported yet, and passing it throws a plain error naming the bad style. Pass
254
- arrays of both into the existing options-object shape `ctx.reply(text, { embeds, buttons })`,
255
- the same convention `ctx.send(chat, text, { mentions })` already uses:
252
+ `new Button({ label, id, style })`, where `style` is one of
253
+ `'primary' | 'secondary' | 'danger' | 'link'`, and anything else throws a plain error naming the
254
+ bad style. Pass arrays of both into the existing options-object shape
255
+ `ctx.reply(text, { embeds, buttons })`, the same convention `ctx.send(chat, text, { mentions })`
256
+ already uses:
256
257
 
257
258
  ```ts
258
259
  import { Embed, Button } from 'aurival';
@@ -273,10 +274,148 @@ const buttons = [
273
274
  await ctx.reply('Ready when you are.', { embeds: [embed], buttons });
274
275
  ```
275
276
 
276
- There are caps, and the SDK checks them locally before the frame ever goes out, so a bad bot
277
- fails fast with a plain error naming which cap it hit: a message carries at most 3 embeds, an
278
- embed at most 6 fields, a message at most 5 buttons, and a button label is at most 24
279
- characters.
277
+ A card earns its place when there is something to put on it: buttons, fields, an image. A reply
278
+ that one line of text covers — a coin flip, a joke, a status line — reads better as that line,
279
+ and a plate wrapped around it is chrome the reader has to look past.
280
+
281
+ ### A button that opens a link
282
+
283
+ `Button.link({ label, url })` builds a pill that opens a url instead of coming back to your bot.
284
+ It is the only sanctioned way to build one — `style: 'link'` on the plain constructor without a
285
+ url throws, because a link button with nowhere to go is a dead pill:
286
+
287
+ ```ts
288
+ import { Button } from 'aurival';
289
+
290
+ const buttons = [
291
+ Button.link({ label: 'Full lineup', url: 'https://aurival.com/spaces/deepcuts/lineup' }),
292
+ Button.link({ label: 'Set notes', url: 'https://example.com/notes' }),
293
+ new Button({ label: 'Remind me', id: 'remind', style: 'primary' }),
294
+ ];
295
+
296
+ await ctx.reply('Doors at 21:00.', { buttons });
297
+ ```
298
+
299
+ A link button never comes back to you: no `button.pressed` event, ever, and it never flips the
300
+ row to used. It also stays tappable after a sibling is pressed, and while a sibling is still
301
+ waiting on your `ack()` — the row greys out around it, the link does not. `id` still has to be
302
+ there and still has to be unique in the message, and the SDK still slugs it from the label when
303
+ you leave it out, so that `Set notes` pill gets `id: 'set-notes'` like any other button. Link
304
+ buttons count toward the five-button cap, and a message made only of link buttons is fine.
305
+
306
+ A url is `https://` and at most 2048 characters, everywhere a url is a link target. A non-link
307
+ button must not carry a `url`, and passing one throws rather than being quietly dropped — a typo
308
+ you cannot see is worse than an error you can.
309
+
310
+ ### Emoji on a button
311
+
312
+ `emoji` puts one glyph in front of the label, inside the pill:
313
+
314
+ ```ts
315
+ import { Button } from 'aurival';
316
+
317
+ const buttons = [
318
+ new Button({ label: 'Maybe', id: 'maybe', style: 'secondary', emoji: '🤔' }),
319
+ new Button({ label: 'Remind me', id: 'remind', style: 'primary', emoji: '⏰' }),
320
+ ];
321
+
322
+ await ctx.reply('Set starts in an hour.', { buttons });
323
+ ```
324
+
325
+ Exactly one unicode emoji, no custom emoji, no `:shortcode:`, no image url. The emoji does not
326
+ count toward the 24-character label cap — it is its own field, and folding it into the label
327
+ count would make one cap mean two things. The label is still required, so there is no
328
+ emoji-only button: a pill with no words is unguessable to everyone and unreadable to a screen
329
+ reader.
330
+
331
+ ### A footer icon, a linked title, a linked author
332
+
333
+ `setFooter(text, icon)` puts a small image beside the footer text, `url` on the embed makes its
334
+ title tappable, and the third argument to `setAuthor` does the same for the author line:
335
+
336
+ ```ts
337
+ import { Embed } from 'aurival';
338
+
339
+ const embed = new Embed({
340
+ title: "Tonight's set",
341
+ description: 'Deep cuts only, and nothing after midnight.',
342
+ color: '#3E6E8E',
343
+ url: 'https://aurival.com/spaces/deepcuts',
344
+ })
345
+ .setAuthor('Deep Cuts', 'https://cdn.aurival.com/dc.png', 'https://aurival.com/u/deepcuts')
346
+ .setThumbnail('https://cdn.aurival.com/cover.jpg')
347
+ .setFooter('set by deepcuts', 'https://cdn.aurival.com/dc-small.png');
348
+
349
+ await ctx.reply("Tonight's lineup.", { embeds: [embed] });
350
+ ```
351
+
352
+ Each of the three needs the thing it attaches to: a footer icon needs footer text, an embed url
353
+ needs a title to hang the tap on, and an author url needs an author name. Without them there is
354
+ nothing for a reader to press, and dropping the url silently would fail where nobody could see
355
+ it.
356
+
357
+ ### Markdown in the description
358
+
359
+ The description is rendered as markdown. Nothing else on the card is — title, field names, field
360
+ values, footer text and author name are all plain text, so a `**bold**` in a field name arrives
361
+ as four asterisks and two words:
362
+
363
+ ```ts
364
+ import { Embed } from 'aurival';
365
+
366
+ const embed = new Embed({
367
+ title: 'House rules',
368
+ description:
369
+ '**Deep cuts** only. No *requests* after the ~~third~~ second hour.\n' +
370
+ 'Type `!queue` to see what is next.',
371
+ }).addField('Set length', '3 hours', true);
372
+
373
+ await ctx.reply('Welcome in.', { embeds: [embed] });
374
+ ```
375
+
376
+ Supported: bold, italic, bold-italic, strikethrough and inline code. Headings render as bold
377
+ text at body size rather than as larger type, because a card is not a document. Not supported:
378
+ images, tables, code panels and autolink — a fenced block renders as plain styled text, not a
379
+ panel, and a bare URL never becomes a tap target.
380
+
381
+ Italic is `*text*`; underscores are not a delimiter and render as typed.
382
+
383
+ The 1024-character description cap counts the raw markdown source you typed, not what the reader
384
+ sees, so the asterisks and backticks are part of your budget.
385
+
386
+ A markdown link (`[label](https://…)`) or a bare URL is still refused inside the description, and
387
+ inside every other prose field with it. Links live in the structured url fields above, where the
388
+ client knows the target before it paints — in prose, a label can say one thing and go somewhere
389
+ else.
390
+
391
+ ### Where a link goes, and what the reader sees first
392
+
393
+ A tap on a link button, a linked title or a linked author that points outside Aurival shows the
394
+ reader a leaving notice naming the host before anything opens, so nobody hands their IP to a
395
+ stranger by pressing a pill that looked friendly. The host on the notice is read off the real
396
+ url, so what they are shown is what opens. An `aurival.com` link skips the notice and opens in
397
+ the app, because it never left.
398
+
399
+ ### Caps
400
+
401
+ The SDK checks every cap locally before the frame goes out, so a bad bot fails fast with a plain
402
+ error naming which cap it hit.
403
+
404
+ | cap | limit |
405
+ | ------------------------------------------------------ | -------------------------------------------- |
406
+ | embeds per message | 3 |
407
+ | fields per message | 6, summed across every embed |
408
+ | buttons per message | 5 |
409
+ | button label | 24 characters, emoji not counted |
410
+ | button emoji | exactly one unicode emoji |
411
+ | button style | `primary`, `secondary`, `danger` or `link` |
412
+ | embed description | 1024 characters of raw markdown |
413
+ | link url (button, title, author) | 2048 characters, `https://` only |
414
+ | image url (thumbnail, image, author icon, footer icon) | `https://` only, no length cap |
415
+
416
+ One convention, which is ours and not a rule: when one button is the one you want pressed, put
417
+ it last. The server and the client never reorder a row — your order is the order the reader
418
+ sees — so this is a habit the docs suggest, not something enforced anywhere.
280
419
 
281
420
  A press comes back as a `button.pressed` event, handled the same way any other event is:
282
421
 
@@ -344,6 +483,84 @@ code reading other `Message` fields is unaffected.
344
483
  `bot.on('button.pressed', ...)` is a new event a bot can opt into; a bot that never registers a
345
484
  handler for it simply never receives one.
346
485
 
486
+ ### Upgrading from 0.4.x
487
+
488
+ Everything 0.5.0 adds to a card is optional: `url` on the `Embed` init object and as the third
489
+ argument to `setAuthor`, the second argument to `setFooter`, `emoji` and `url` on `Button`, and
490
+ the `Button.link` constructor. A card that uses none of them serialises exactly as it did on
491
+ 0.4.0 — same keys, same bytes, no `url: null` where there was nothing before — so a bot you
492
+ wrote against 0.4.0 needs no edit at all.
493
+
494
+ `'link'` is a real button style now, where 0.4.0 refused it with `link buttons are not supported
495
+ in v1`. Build one with `Button.link({ label, url })`; that static is the sanctioned constructor, and it sets the
496
+ style for you.
497
+
498
+ A link button is not an action button wearing a url. It never produces a `button.pressed` event,
499
+ it never flips `used`, and it is not disabled by a sibling being pending or used — so a row can
500
+ go cold around a link and the link still works. If you were counting on every button in a row
501
+ answering back, count only the ones you did not build with `Button.link`.
502
+
503
+ ### Upgrading from 0.5.x
504
+
505
+ 0.6.0 adds optional fields in two places and takes nothing away. `ctx.edit()` takes an init
506
+ object next to the message, and `ctx.ack()` takes one too, so a press can answer by replacing the
507
+ card it was pressed on instead of stacking a second message under it. A bot written against
508
+ 0.5.0 needs no edit at all: `await ctx.edit(sent, 'done!')` still takes a plain string, and a
509
+ bare `await ctx.ack()` sends exactly the bytes it sent before.
510
+
511
+ Three states, one rule, on both doors:
512
+
513
+ - leave a field out and that part of the card is kept as it was
514
+ - pass a value and that part is replaced
515
+ - pass `[]` or `null` and that part is cleared — both go on the wire as `"embeds": null`
516
+
517
+ `text` is not clearable, because a card always carries text and `''` already means empty. An edit
518
+ with all three left out throws `an edit needs text, embeds or buttons` before anything is sent,
519
+ and the server answers the same sentence as `NothingToEdit`.
520
+
521
+ A trivia round is the whole feature in one pair of handlers. Both cards earn their plate: the
522
+ question card carries buttons, the result card carries a field.
523
+
524
+ ```ts
525
+ import { Button, Embed } from 'aurival';
526
+
527
+ bot.command('trivia', async (ctx) => {
528
+ await ctx.reply({
529
+ embeds: [new Embed({ title: 'Which planet is largest?' })],
530
+ buttons: [
531
+ new Button({ label: 'Mars', style: 'secondary' }),
532
+ new Button({ label: 'Jupiter', style: 'secondary' }),
533
+ ],
534
+ });
535
+ });
536
+
537
+ bot.on('button.pressed', async (ctx) => {
538
+ const correct = ctx.button === 'jupiter';
539
+ const result = new Embed({
540
+ title: correct ? 'Jupiter' : 'Not quite',
541
+ description: 'Jupiter is about eleven Earths across.',
542
+ }).addField('Answered by', ctx.user.handle, true);
543
+ await ctx.ack({
544
+ embeds: [result],
545
+ buttons: [new Button({ id: 'again', label: 'Play again' })],
546
+ });
547
+ });
548
+ ```
549
+
550
+ The ack and the replacement are one request. The question card becomes the result card in place,
551
+ the `Play again` row starts unused, and the message is not marked edited — an interaction
552
+ response is the bot answering the presser, not the author correcting themselves. Reusing button
553
+ ids across replacements is allowed and safe: the server keys the refusal on the interaction, not
554
+ on the id.
555
+
556
+ `edit()` is the other door and it does mark the message edited, so a card can redraw itself
557
+ outside a press:
558
+
559
+ ```ts
560
+ await ctx.edit(sent, { embeds: [new Embed({ title: 'Starting in 3…' })] });
561
+ await ctx.edit(sent, { buttons: [] }); // the row is gone, the plate stays
562
+ ```
563
+
347
564
  ## Shadowed commands
348
565
 
349
566
  A bot can declare up to 50 commands, the SDK refuses to connect past that.
package/dist/caps.d.ts CHANGED
@@ -14,7 +14,9 @@ export declare const MAX_LABEL_RUNES = 24;
14
14
  export declare const MAX_BUTTON_ID_LENGTH = 32;
15
15
  export declare const MAX_TITLE_LENGTH = 256;
16
16
  export declare const MAX_DESCRIPTION_LENGTH = 1024;
17
- export declare const BUTTON_STYLES: readonly ['primary', 'secondary', 'danger'];
17
+ export declare const MAX_BUTTON_EMOJI_RUNES = 16;
18
+ export declare const MAX_LINK_URL_RUNES = 2048;
19
+ export declare const BUTTON_STYLES: readonly ['primary', 'secondary', 'danger', 'link'];
18
20
  export type ButtonStyle = (typeof BUTTON_STYLES)[number];
19
21
  export declare const CAP_TOO_MANY_EMBEDS = "a message carries at most 3 embeds";
20
22
  export declare const CAP_TOO_MANY_FIELDS = "a message carries at most 6 embed fields";
@@ -22,15 +24,49 @@ export declare const CAP_TOO_MANY_BUTTONS = "a message carries at most 5 buttons
22
24
  export declare const CAP_LABEL_TOO_LONG = "a button label is at most 24 characters";
23
25
  export declare const CAP_BUTTON_ID_TOO_LONG = "a button id is at most 32 characters";
24
26
  export declare const CAP_DUPLICATE_BUTTON_ID = "a button id must be unique within a message";
25
- export declare const CAP_BAD_BUTTON_STYLE = "a button style must be one of primary, secondary, danger";
26
- export declare const CAP_LINK_STYLE_DEFERRED = "link buttons are not supported in v1";
27
+ export declare const CAP_BAD_BUTTON_STYLE = "a button style must be one of primary, secondary, danger, link";
27
28
  export declare const CAP_TITLE_TOO_LONG = "an embed title is at most 256 characters";
28
29
  export declare const CAP_DESCRIPTION_TOO_LONG = "an embed description is at most 1024 characters";
29
30
  export declare const CAP_IMAGE_URL_NOT_HTTPS = "an image url must start with https://";
31
+ /**
32
+ * AMENDMENT-06 §5. Link targets live in structured fields, never in prose,
33
+ * and they answer a link mistake with a link sentence: `an image url ...`
34
+ * would tell a bot author to fix the wrong thing. The one sentence that
35
+ * names a number renders it from `MAX_LINK_URL_RUNES`, exactly as the
36
+ * label and title caps above render theirs, because the server's template
37
+ * refuses a digit literal.
38
+ */
39
+ export declare const CAP_LINK_URL_NOT_HTTPS = "a link url must start with https://";
40
+ export declare const CAP_LINK_URL_TOO_LONG = "a link url is at most 2048 characters";
41
+ export declare const CAP_LINK_BUTTON_MISSING_URL = "a link button needs a url";
42
+ export declare const CAP_URL_ON_NON_LINK_BUTTON = "only a link button carries a url";
43
+ export declare const CAP_INVALID_BUTTON_EMOJI = "a button emoji is a single unicode emoji";
44
+ export declare const CAP_EMBED_URL_WITHOUT_TITLE = "an embed url needs a title to attach to";
45
+ export declare const CAP_AUTHOR_URL_WITHOUT_NAME = "an author url needs an author name to attach to";
46
+ export declare const CAP_EMBED_FOOTER_TEXT_REQUIRED = "an embed footer needs text";
47
+ /**
48
+ * The server's `button_missing_field` sentence, rendered for the one field
49
+ * an SDK caller can actually leave empty. AMENDMENT-06 §3 keeps the label
50
+ * required so an emoji-only pill cannot ship: a pill with no words is
51
+ * unreadable to a screen reader and unguessable to everyone else.
52
+ */
53
+ export declare const CAP_BUTTON_MISSING_LABEL = "Every button needs `label`. A button without one cannot be rendered or pressed.";
30
54
  /**
31
55
  * The SDK's own precondition, not one of the server's cap sentences: a send
32
56
  * with no text, no embeds and no buttons has nothing to deliver, so it is
33
57
  * refused here rather than sent for the server to refuse as empty text.
34
58
  */
35
59
  export declare const EMPTY_MESSAGE = "a message needs text, embeds or buttons";
60
+ /**
61
+ * AMENDMENT-07 §7's one new code, `nothing_to_edit`: a PATCH body carrying
62
+ * none of `text`, `embeds` or `buttons` has nothing to change, so the SDK
63
+ * refuses it here rather than spending a round trip on it.
64
+ *
65
+ * The sentence is copied VERBATIM from AMENDMENT-07 §7's table because L1 has
66
+ * not landed `errors_v1.go`'s row yet — when it does, this string and the Go
67
+ * catalogue's must stay byte-identical, as they are for every other sentence
68
+ * shared between `errors_v1.go`, `ERRORS-V1.md` §3, `sdk/python/aurival/caps.py`
69
+ * and this file.
70
+ */
71
+ export declare const NOTHING_TO_EDIT = "an edit needs text, embeds or buttons";
36
72
  //# sourceMappingURL=caps.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"caps.d.ts","sourceRoot":"","sources":["../src/caps.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,UAAU,IAAI,CAAC;AAC5B,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAClC,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,eAAO,MAAM,eAAe,KAAK,CAAC;AAClC,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,eAAO,MAAM,gBAAgB,MAAM,CAAC;AACpC,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAC3C,eAAO,MAAM,aAAa,YAAI,SAAS,EAAE,WAAW,EAAE,QAAQ,CAAU,CAAC;AAEzE,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD,eAAO,MAAM,mBAAmB,uCAAuC,CAAC;AACxE,eAAO,MAAM,mBAAmB,6CAA6C,CAAC;AAC9E,eAAO,MAAM,oBAAoB,wCAAwC,CAAC;AAC1E,eAAO,MAAM,kBAAkB,4CAA4C,CAAC;AAC5E,eAAO,MAAM,sBAAsB,yCAAyC,CAAC;AAC7E,eAAO,MAAM,uBAAuB,gDAAgD,CAAC;AACrF,eAAO,MAAM,oBAAoB,6DAA6D,CAAC;AAC/F,eAAO,MAAM,uBAAuB,yCAAyC,CAAC;AAC9E,eAAO,MAAM,kBAAkB,6CAA6C,CAAC;AAC7E,eAAO,MAAM,wBAAwB,oDAAoD,CAAC;AAC1F,eAAO,MAAM,uBAAuB,0CAA0C,CAAC;AAE/E;;;;GAIG;AACH,eAAO,MAAM,aAAa,4CAA4C,CAAC"}
1
+ {"version":3,"file":"caps.d.ts","sourceRoot":"","sources":["../src/caps.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,UAAU,IAAI,CAAC;AAC5B,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAClC,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,eAAO,MAAM,eAAe,KAAK,CAAC;AAClC,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,eAAO,MAAM,gBAAgB,MAAM,CAAC;AACpC,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAC3C,eAAO,MAAM,sBAAsB,KAAK,CAAC;AACzC,eAAO,MAAM,kBAAkB,OAAO,CAAC;AACvC,eAAO,MAAM,aAAa,YAAI,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAU,CAAC;AAEjF,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD,eAAO,MAAM,mBAAmB,uCAAuC,CAAC;AACxE,eAAO,MAAM,mBAAmB,6CAA6C,CAAC;AAC9E,eAAO,MAAM,oBAAoB,wCAAwC,CAAC;AAC1E,eAAO,MAAM,kBAAkB,4CAA4C,CAAC;AAC5E,eAAO,MAAM,sBAAsB,yCAAyC,CAAC;AAC7E,eAAO,MAAM,uBAAuB,gDAAgD,CAAC;AACrF,eAAO,MAAM,oBAAoB,mEACiC,CAAC;AACnE,eAAO,MAAM,kBAAkB,6CAA6C,CAAC;AAC7E,eAAO,MAAM,wBAAwB,oDAAoD,CAAC;AAC1F,eAAO,MAAM,uBAAuB,0CAA0C,CAAC;AAE/E;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,wCAAwC,CAAC;AAC5E,eAAO,MAAM,qBAAqB,0CAA2D,CAAC;AAC9F,eAAO,MAAM,2BAA2B,8BAA8B,CAAC;AACvE,eAAO,MAAM,0BAA0B,qCAAqC,CAAC;AAC7E,eAAO,MAAM,wBAAwB,6CAA6C,CAAC;AACnF,eAAO,MAAM,2BAA2B,4CAA4C,CAAC;AACrF,eAAO,MAAM,2BAA2B,oDAAoD,CAAC;AAC7F,eAAO,MAAM,8BAA8B,+BAA+B,CAAC;AAE3E;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,oFAC8C,CAAC;AAEpF;;;;GAIG;AACH,eAAO,MAAM,aAAa,4CAA4C,CAAC;AAEvE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,0CAA0C,CAAC"}
package/dist/caps.js CHANGED
@@ -14,22 +14,58 @@ export const MAX_LABEL_RUNES = 24;
14
14
  export const MAX_BUTTON_ID_LENGTH = 32;
15
15
  export const MAX_TITLE_LENGTH = 256;
16
16
  export const MAX_DESCRIPTION_LENGTH = 1024;
17
- export const BUTTON_STYLES = ['primary', 'secondary', 'danger'];
17
+ export const MAX_BUTTON_EMOJI_RUNES = 16;
18
+ export const MAX_LINK_URL_RUNES = 2048;
19
+ export const BUTTON_STYLES = ['primary', 'secondary', 'danger', 'link'];
18
20
  export const CAP_TOO_MANY_EMBEDS = 'a message carries at most 3 embeds';
19
21
  export const CAP_TOO_MANY_FIELDS = 'a message carries at most 6 embed fields';
20
22
  export const CAP_TOO_MANY_BUTTONS = 'a message carries at most 5 buttons';
21
23
  export const CAP_LABEL_TOO_LONG = 'a button label is at most 24 characters';
22
24
  export const CAP_BUTTON_ID_TOO_LONG = 'a button id is at most 32 characters';
23
25
  export const CAP_DUPLICATE_BUTTON_ID = 'a button id must be unique within a message';
24
- export const CAP_BAD_BUTTON_STYLE = 'a button style must be one of primary, secondary, danger';
25
- export const CAP_LINK_STYLE_DEFERRED = 'link buttons are not supported in v1';
26
+ export const CAP_BAD_BUTTON_STYLE = 'a button style must be one of primary, secondary, danger, link';
26
27
  export const CAP_TITLE_TOO_LONG = 'an embed title is at most 256 characters';
27
28
  export const CAP_DESCRIPTION_TOO_LONG = 'an embed description is at most 1024 characters';
28
29
  export const CAP_IMAGE_URL_NOT_HTTPS = 'an image url must start with https://';
30
+ /**
31
+ * AMENDMENT-06 §5. Link targets live in structured fields, never in prose,
32
+ * and they answer a link mistake with a link sentence: `an image url ...`
33
+ * would tell a bot author to fix the wrong thing. The one sentence that
34
+ * names a number renders it from `MAX_LINK_URL_RUNES`, exactly as the
35
+ * label and title caps above render theirs, because the server's template
36
+ * refuses a digit literal.
37
+ */
38
+ export const CAP_LINK_URL_NOT_HTTPS = 'a link url must start with https://';
39
+ export const CAP_LINK_URL_TOO_LONG = `a link url is at most ${MAX_LINK_URL_RUNES} characters`;
40
+ export const CAP_LINK_BUTTON_MISSING_URL = 'a link button needs a url';
41
+ export const CAP_URL_ON_NON_LINK_BUTTON = 'only a link button carries a url';
42
+ export const CAP_INVALID_BUTTON_EMOJI = 'a button emoji is a single unicode emoji';
43
+ export const CAP_EMBED_URL_WITHOUT_TITLE = 'an embed url needs a title to attach to';
44
+ export const CAP_AUTHOR_URL_WITHOUT_NAME = 'an author url needs an author name to attach to';
45
+ export const CAP_EMBED_FOOTER_TEXT_REQUIRED = 'an embed footer needs text';
46
+ /**
47
+ * The server's `button_missing_field` sentence, rendered for the one field
48
+ * an SDK caller can actually leave empty. AMENDMENT-06 §3 keeps the label
49
+ * required so an emoji-only pill cannot ship: a pill with no words is
50
+ * unreadable to a screen reader and unguessable to everyone else.
51
+ */
52
+ export const CAP_BUTTON_MISSING_LABEL = 'Every button needs `label`. A button without one cannot be rendered or pressed.';
29
53
  /**
30
54
  * The SDK's own precondition, not one of the server's cap sentences: a send
31
55
  * with no text, no embeds and no buttons has nothing to deliver, so it is
32
56
  * refused here rather than sent for the server to refuse as empty text.
33
57
  */
34
58
  export const EMPTY_MESSAGE = 'a message needs text, embeds or buttons';
59
+ /**
60
+ * AMENDMENT-07 §7's one new code, `nothing_to_edit`: a PATCH body carrying
61
+ * none of `text`, `embeds` or `buttons` has nothing to change, so the SDK
62
+ * refuses it here rather than spending a round trip on it.
63
+ *
64
+ * The sentence is copied VERBATIM from AMENDMENT-07 §7's table because L1 has
65
+ * not landed `errors_v1.go`'s row yet — when it does, this string and the Go
66
+ * catalogue's must stay byte-identical, as they are for every other sentence
67
+ * shared between `errors_v1.go`, `ERRORS-V1.md` §3, `sdk/python/aurival/caps.py`
68
+ * and this file.
69
+ */
70
+ export const NOTHING_TO_EDIT = 'an edit needs text, embeds or buttons';
35
71
  //# sourceMappingURL=caps.js.map
package/dist/caps.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"caps.js","sourceRoot":"","sources":["../src/caps.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC;AAC5B,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAClC,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC;AAC7B,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,CAAC;AAClC,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AACvC,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAC;AACpC,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,CAAC;AAC3C,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,SAAS,EAAE,WAAW,EAAE,QAAQ,CAAU,CAAC;AAIzE,MAAM,CAAC,MAAM,mBAAmB,GAAG,oCAAoC,CAAC;AACxE,MAAM,CAAC,MAAM,mBAAmB,GAAG,0CAA0C,CAAC;AAC9E,MAAM,CAAC,MAAM,oBAAoB,GAAG,qCAAqC,CAAC;AAC1E,MAAM,CAAC,MAAM,kBAAkB,GAAG,yCAAyC,CAAC;AAC5E,MAAM,CAAC,MAAM,sBAAsB,GAAG,sCAAsC,CAAC;AAC7E,MAAM,CAAC,MAAM,uBAAuB,GAAG,6CAA6C,CAAC;AACrF,MAAM,CAAC,MAAM,oBAAoB,GAAG,0DAA0D,CAAC;AAC/F,MAAM,CAAC,MAAM,uBAAuB,GAAG,sCAAsC,CAAC;AAC9E,MAAM,CAAC,MAAM,kBAAkB,GAAG,0CAA0C,CAAC;AAC7E,MAAM,CAAC,MAAM,wBAAwB,GAAG,iDAAiD,CAAC;AAC1F,MAAM,CAAC,MAAM,uBAAuB,GAAG,uCAAuC,CAAC;AAE/E;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,yCAAyC,CAAC"}
1
+ {"version":3,"file":"caps.js","sourceRoot":"","sources":["../src/caps.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC;AAC5B,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAClC,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC;AAC7B,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,CAAC;AAClC,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AACvC,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAC;AACpC,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,CAAC;AAC3C,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,CAAC;AACzC,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC;AACvC,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAU,CAAC;AAIjF,MAAM,CAAC,MAAM,mBAAmB,GAAG,oCAAoC,CAAC;AACxE,MAAM,CAAC,MAAM,mBAAmB,GAAG,0CAA0C,CAAC;AAC9E,MAAM,CAAC,MAAM,oBAAoB,GAAG,qCAAqC,CAAC;AAC1E,MAAM,CAAC,MAAM,kBAAkB,GAAG,yCAAyC,CAAC;AAC5E,MAAM,CAAC,MAAM,sBAAsB,GAAG,sCAAsC,CAAC;AAC7E,MAAM,CAAC,MAAM,uBAAuB,GAAG,6CAA6C,CAAC;AACrF,MAAM,CAAC,MAAM,oBAAoB,GAC/B,gEAAgE,CAAC;AACnE,MAAM,CAAC,MAAM,kBAAkB,GAAG,0CAA0C,CAAC;AAC7E,MAAM,CAAC,MAAM,wBAAwB,GAAG,iDAAiD,CAAC;AAC1F,MAAM,CAAC,MAAM,uBAAuB,GAAG,uCAAuC,CAAC;AAE/E;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,qCAAqC,CAAC;AAC5E,MAAM,CAAC,MAAM,qBAAqB,GAAG,yBAAyB,kBAAkB,aAAa,CAAC;AAC9F,MAAM,CAAC,MAAM,2BAA2B,GAAG,2BAA2B,CAAC;AACvE,MAAM,CAAC,MAAM,0BAA0B,GAAG,kCAAkC,CAAC;AAC7E,MAAM,CAAC,MAAM,wBAAwB,GAAG,0CAA0C,CAAC;AACnF,MAAM,CAAC,MAAM,2BAA2B,GAAG,yCAAyC,CAAC;AACrF,MAAM,CAAC,MAAM,2BAA2B,GAAG,iDAAiD,CAAC;AAC7F,MAAM,CAAC,MAAM,8BAA8B,GAAG,4BAA4B,CAAC;AAE3E;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GACnC,iFAAiF,CAAC;AAEpF;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,yCAAyC,CAAC;AAEvE;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,uCAAuC,CAAC"}
package/dist/embeds.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  /**
2
- * Discord-shaped `Embed` and `Button` builders (AMENDMENT-05). Mirrors
2
+ * Discord-shaped `Embed` and `Button` builders (AMENDMENT-05, extended by
3
+ * AMENDMENT-06 with a footer icon, a button emoji and the three structured
4
+ * link targets). Mirrors
3
5
  * python's builders field for field; the wire shape and every cap sentence
4
6
  * are contractual (`caps.ts`) and must not drift between the two SDKs.
5
7
  *
@@ -23,6 +25,7 @@ export interface EmbedFieldValue {
23
25
  export interface EmbedAuthorValue {
24
26
  name: string;
25
27
  icon?: string;
28
+ url?: string;
26
29
  }
27
30
  export interface EmbedThumbnailValue {
28
31
  url: string;
@@ -32,11 +35,13 @@ export interface EmbedImageValue {
32
35
  }
33
36
  export interface EmbedFooterValue {
34
37
  text: string;
38
+ icon?: string;
35
39
  }
36
40
  export interface EmbedInit {
37
41
  title?: string;
38
42
  description?: string;
39
43
  color?: string;
44
+ url?: string;
40
45
  }
41
46
  /**
42
47
  * `Embed().addField(...)` builder. Every mutation is validated immediately
@@ -48,6 +53,7 @@ export declare class Embed {
48
53
  title?: string;
49
54
  description?: string;
50
55
  color?: string;
56
+ url?: string;
51
57
  author?: EmbedAuthorValue;
52
58
  thumbnail?: EmbedThumbnailValue;
53
59
  image?: EmbedImageValue;
@@ -57,10 +63,10 @@ export declare class Embed {
57
63
  constructor(init?: EmbedInit);
58
64
  /** Refuses the 7th field on ONE embed — the whole-message cap (summed across embeds) is enforced by `serialiseEmbeds`. */
59
65
  addField(name: string, value: string, inline?: boolean): this;
60
- setAuthor(name: string, icon?: string): this;
66
+ setAuthor(name: string, icon?: string, url?: string): this;
61
67
  setThumbnail(url: string): this;
62
68
  setImage(url: string): this;
63
- setFooter(text: string): this;
69
+ setFooter(text: string, icon?: string): this;
64
70
  /** A `Date` becomes UTC RFC3339 (`Z`); a string is assumed already in that form. */
65
71
  setTimestamp(value: Date | string): this;
66
72
  toJSON(): Record<string, unknown>;
@@ -76,13 +82,30 @@ export interface ButtonInit {
76
82
  label: string;
77
83
  id?: string;
78
84
  style?: string;
85
+ emoji?: string;
86
+ url?: string;
79
87
  }
80
88
  /** `new Button({ label: 'Pacific' })` — `id` defaults to a slug of `label`, `style` defaults to `'primary'`. */
81
89
  export declare class Button {
82
90
  label: string;
83
91
  id: string;
84
92
  style: string;
93
+ emoji?: string;
94
+ url?: string;
85
95
  constructor(init: ButtonInit);
96
+ /**
97
+ * The sanctioned way to build a link pill (AMENDMENT-06 §11): a url is not
98
+ * optional here, so the shape that raises `a link button needs a url` is
99
+ * one a caller has to go out of their way to write. A tap opens the url on
100
+ * the device and stops — a link button never round-trips as `button.pressed`
101
+ * and never flips the row.
102
+ */
103
+ static link(init: {
104
+ label: string;
105
+ url: string;
106
+ id?: string;
107
+ emoji?: string;
108
+ }): Button;
86
109
  toJSON(): Record<string, unknown>;
87
110
  /** Tolerant decode — never throws. See `Embed.fromJSON` for why. */
88
111
  static fromJSON(data: unknown): Button;
@@ -1 +1 @@
1
- {"version":3,"file":"embeds.d.ts","sourceRoot":"","sources":["../src/embeds.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"embeds.d.ts","sourceRoot":"","sources":["../src/embeds.ts"],"names":[],"mappings":"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"}