@bunizao/contracts 0.7.2 → 0.8.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.
@@ -60,6 +60,9 @@ export interface ReaderMe {
60
60
  provider: ReaderProvider;
61
61
  displayName: string;
62
62
  avatarUrl: string;
63
+ /** Seed of the drawn face shown when `avatarUrl` is empty. Null until one
64
+ has been handed out -- the client then draws from the name. */
65
+ avatarSeed: number | null;
63
66
  notifyReplies: boolean;
64
67
  /** Whether this address holds an active newsletter subscription. */
65
68
  subscribed: boolean;
@@ -131,6 +134,8 @@ export declare const DEFAULT_REACTION_EMOJI = "\u2764\uFE0F";
131
134
  export interface ReactorChip {
132
135
  name: string;
133
136
  avatarUrl: string | null;
137
+ /** Drawn-face seed; absent from servers older than 0.8.0. */
138
+ avatarSeed?: number | null;
134
139
  }
135
140
  export interface ReactionSummary {
136
141
  emoji: string;
@@ -304,6 +309,10 @@ export interface CommentAuthor {
304
309
  any key it does not know, so a path emitted for every address would make
305
310
  every face an identicon. */
306
311
  avatarUrl: string;
312
+ /** Seed of the drawn face for an empty `avatarUrl`: the writer's reader
313
+ seed when they have one, else the seed the comment was posted with.
314
+ Null or absent (servers older than 0.8.0) means draw from the name. */
315
+ avatarSeed?: number | null;
307
316
  /** True when this row's writer is the blog owner. */
308
317
  byAuthor: boolean;
309
318
  }
@@ -361,6 +370,9 @@ export interface CommentCreateInput {
361
370
  Omitted or empty: the comment is owned by its anon session only and
362
371
  the client renders an identicon. */
363
372
  email?: string;
373
+ /** The drawn face the writer picked in the compose box, from
374
+ `READER_AVATAR_SEED_PATH`. Ignored when it is not an `isAvatarSeed`. */
375
+ avatarSeed?: number;
364
376
  turnstileToken: string;
365
377
  /** Visually-hidden honeypot field. Must arrive empty. */
366
378
  website?: string;
@@ -523,3 +535,29 @@ export interface CommentTelemetryInput {
523
535
  outcome: 'accepted' | 'http_error' | 'network_error' | 'challenge_failed';
524
536
  challenges: number;
525
537
  }
538
+ /** A drawn face's colour pair is `seed % AVATAR_CLASSES`: five palette
539
+ colours as background, times the four others as head. The pair is what
540
+ tells two faces apart at stack size, so it is the unit the server balances
541
+ when it hands out a seed and the unit a re-roll must change. The palette
542
+ itself is a rendering concern and lives with the client. */
543
+ export declare const AVATAR_CLASSES = 20;
544
+ export declare const MAX_AVATAR_SEED = 4294967295;
545
+ export declare function isAvatarSeed(value: unknown): value is number;
546
+ export declare function avatarClass(seed: number): number;
547
+ /** A seed in colour class `cls`; `variety` fills the digits that pick the
548
+ expression, pose and head shape. */
549
+ export declare function seedInClass(cls: number, variety: number): number;
550
+ /** POST body for `READER_AVATAR_SEED_PATH`. */
551
+ export interface AvatarSeedInput {
552
+ /** The seed on screen now. The answer is always in a different colour
553
+ class, so every re-roll visibly changes the face. */
554
+ current?: number | null;
555
+ }
556
+ export interface AvatarSeedResult {
557
+ /** In the least-used colour class across the site, never `current`'s. */
558
+ seed: number;
559
+ /** True when the caller is a verified reader and the seed is now theirs
560
+ everywhere. False for anyone else: the client keeps it and sends it as
561
+ `CommentCreateInput.avatarSeed`. */
562
+ persisted: boolean;
563
+ }
package/dist/comments.js CHANGED
@@ -61,7 +61,20 @@ function commentPolicyFromTags(tags, base = DEFAULT_COMMENT_POLICY) {
61
61
  return policy;
62
62
  }
63
63
  var acceptsComments = (policy) => policy.mode === "open";
64
+ var AVATAR_CLASSES = 20;
65
+ var MAX_AVATAR_SEED = 4294967295;
66
+ function isAvatarSeed(value) {
67
+ return Number.isInteger(value) && value >= 0 && value <= MAX_AVATAR_SEED;
68
+ }
69
+ function avatarClass(seed) {
70
+ return seed % AVATAR_CLASSES;
71
+ }
72
+ function seedInClass(cls, variety) {
73
+ const span = Math.floor(MAX_AVATAR_SEED / AVATAR_CLASSES);
74
+ return Math.abs(Math.trunc(variety)) % span * AVATAR_CLASSES + Math.abs(Math.trunc(cls)) % AVATAR_CLASSES;
75
+ }
64
76
  export {
77
+ AVATAR_CLASSES,
65
78
  COMMENTS_MODES,
66
79
  COMMENT_ANCHOR_PATTERN,
67
80
  COMMENT_ANCHOR_TOKEN_LENGTH,
@@ -72,6 +85,7 @@ export {
72
85
  COMMENT_SURFACES,
73
86
  DEFAULT_COMMENT_POLICY,
74
87
  DEFAULT_REACTION_EMOJI,
88
+ MAX_AVATAR_SEED,
75
89
  MODERATION_ACTIONS,
76
90
  MODERATION_REASONS,
77
91
  REACTION_TARGET_TYPES,
@@ -80,6 +94,9 @@ export {
80
94
  READER_PROVIDERS,
81
95
  READER_VERIFY_OUTCOMES,
82
96
  acceptsComments,
97
+ avatarClass,
83
98
  commentAnchorToken,
84
- commentPolicyFromTags
99
+ commentPolicyFromTags,
100
+ isAvatarSeed,
101
+ seedInClass
85
102
  };
package/dist/index.js CHANGED
@@ -73,6 +73,18 @@ function commentPolicyFromTags(tags, base = DEFAULT_COMMENT_POLICY) {
73
73
  return policy;
74
74
  }
75
75
  var acceptsComments = (policy) => policy.mode === "open";
76
+ var AVATAR_CLASSES = 20;
77
+ var MAX_AVATAR_SEED = 4294967295;
78
+ function isAvatarSeed(value) {
79
+ return Number.isInteger(value) && value >= 0 && value <= MAX_AVATAR_SEED;
80
+ }
81
+ function avatarClass(seed) {
82
+ return seed % AVATAR_CLASSES;
83
+ }
84
+ function seedInClass(cls, variety) {
85
+ const span = Math.floor(MAX_AVATAR_SEED / AVATAR_CLASSES);
86
+ return Math.abs(Math.trunc(variety)) % span * AVATAR_CLASSES + Math.abs(Math.trunc(cls)) % AVATAR_CLASSES;
87
+ }
76
88
  // src/content.ts
77
89
  var CONTENT_DOCUMENT_SOURCES = ["mood", "post"];
78
90
  var POST_LOCALE_RE = /^[a-z]{2,8}(?:-[a-z0-9]{1,8})*$/;
@@ -130,6 +142,7 @@ var READER_RESEND_PATH = "/v2/reader/resend";
130
142
  var READER_PREFERENCES_PATH = "/v2/reader/preferences";
131
143
  var READER_MUTE_PATH = "/v2/reader/mute";
132
144
  var READER_AVATAR_PATH_PREFIX = "/v2/reader/avatar/";
145
+ var READER_AVATAR_SEED_PATH = "/v2/reader/avatar-seed";
133
146
  var READER_OAUTH_PATH_PREFIX = "/oauth/reader/";
134
147
  var READER_CONFIRM_PATH = "/reader/confirm";
135
148
  var READER_MUTE_PAGE_PATH = "/reader/mute";
@@ -203,6 +216,7 @@ var TELEGRAM_OPS_BROADCAST_STATUSES = [
203
216
  export {
204
217
  ADMIN_BASE_PATH,
205
218
  API_PREFIX,
219
+ AVATAR_CLASSES,
206
220
  BLOG_ANALYTICS_ARTICLE_ENDPOINT,
207
221
  BLOG_ANALYTICS_COMPLETION_SCROLL_DEPTH,
208
222
  BLOG_ANALYTICS_EVENTS_DEFAULT_LIMIT,
@@ -234,6 +248,7 @@ export {
234
248
  LEGACY_NOTIFY_BASE_PATH,
235
249
  LISTENING_ANALYTICS_EVENT_ENDPOINT,
236
250
  LISTENING_PATH,
251
+ MAX_AVATAR_SEED,
237
252
  MESSAGE_LOCALES,
238
253
  MESSAGE_MAX_BODY_LENGTH,
239
254
  MESSAGE_MAX_NAME_LENGTH,
@@ -269,6 +284,7 @@ export {
269
284
  REACTIONS_TOGGLE_PATH,
270
285
  REACTION_TARGET_TYPES,
271
286
  READER_AVATAR_PATH_PREFIX,
287
+ READER_AVATAR_SEED_PATH,
272
288
  READER_CONFIRM_PATH,
273
289
  READER_GRADES,
274
290
  READER_ME_PATH,
@@ -298,9 +314,12 @@ export {
298
314
  TELEGRAM_OPS_WEBHOOK_PATH,
299
315
  TELEGRAM_WEBHOOK_PATH,
300
316
  acceptsComments,
317
+ avatarClass,
301
318
  commentAnchorToken,
302
319
  commentPolicyFromTags,
320
+ isAvatarSeed,
303
321
  parsePostLocaleTag,
322
+ seedInClass,
304
323
  telegramOpsEventActionPath,
305
324
  telegramOpsEventPath,
306
325
  telegramOpsReminderDeliveredPath,
package/dist/routes.d.ts CHANGED
@@ -23,6 +23,7 @@ export declare const READER_RESEND_PATH: '/v2/reader/resend';
23
23
  export declare const READER_PREFERENCES_PATH: '/v2/reader/preferences';
24
24
  export declare const READER_MUTE_PATH: '/v2/reader/mute';
25
25
  export declare const READER_AVATAR_PATH_PREFIX: '/v2/reader/avatar/';
26
+ export declare const READER_AVATAR_SEED_PATH: '/v2/reader/avatar-seed';
26
27
  export declare const READER_OAUTH_PATH_PREFIX: '/oauth/reader/';
27
28
  export declare const READER_CONFIRM_PATH: '/reader/confirm';
28
29
  export declare const READER_MUTE_PAGE_PATH: '/reader/mute';
package/dist/routes.js CHANGED
@@ -24,6 +24,7 @@ var READER_RESEND_PATH = "/v2/reader/resend";
24
24
  var READER_PREFERENCES_PATH = "/v2/reader/preferences";
25
25
  var READER_MUTE_PATH = "/v2/reader/mute";
26
26
  var READER_AVATAR_PATH_PREFIX = "/v2/reader/avatar/";
27
+ var READER_AVATAR_SEED_PATH = "/v2/reader/avatar-seed";
27
28
  var READER_OAUTH_PATH_PREFIX = "/oauth/reader/";
28
29
  var READER_CONFIRM_PATH = "/reader/confirm";
29
30
  var READER_MUTE_PAGE_PATH = "/reader/mute";
@@ -67,6 +68,7 @@ export {
67
68
  REACTIONS_PATH,
68
69
  REACTIONS_TOGGLE_PATH,
69
70
  READER_AVATAR_PATH_PREFIX,
71
+ READER_AVATAR_SEED_PATH,
70
72
  READER_CONFIRM_PATH,
71
73
  READER_ME_PATH,
72
74
  READER_MUTE_PAGE_PATH,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bunizao/contracts",
3
- "version": "0.7.2",
3
+ "version": "0.8.0",
4
4
  "description": "Shared TypeScript contracts for buxx.me services and clients.",
5
5
  "type": "module",
6
6
  "sideEffects": false,