@bunizao/contracts 0.3.0 → 0.5.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.
@@ -21,6 +21,25 @@ export declare const READER_GRADES: readonly ['l0', 'l1', 'l2'];
21
21
  export type ReaderGrade = (typeof READER_GRADES)[number];
22
22
  export declare const COMMENT_STATUSES: readonly ['published', 'held', 'rejected', 'deleted'];
23
23
  export type CommentStatus = (typeof COMMENT_STATUSES)[number];
24
+ /** Where a comment was written. `blog` rows key on Ghost post ids; `mood`
25
+ rows key on the Telegram channel message id and are bridged into the
26
+ channel's discussion group by the ops bot — plans/mood-comments-bridge.md. */
27
+ export declare const COMMENT_SURFACES: readonly ['blog', 'mood'];
28
+ export type CommentSurface = (typeof COMMENT_SURFACES)[number];
29
+ /** Length of the anchor token derived from a comment id. */
30
+ export declare const COMMENT_ANCHOR_TOKEN_LENGTH = 12;
31
+ /**
32
+ * Stable, unguessable-enough anchor for a comment: the first 12 hex chars of
33
+ * sha256(commentId). It rides in the bridged Telegram message's link
34
+ * (`/mood/<postId>#c-<token>`), in the owner card's View URL, and as the
35
+ * `id="c-<token>"` of the rendered row. The read path matches bridged
36
+ * messages back to their rows by this string, so it must be computed the
37
+ * same way everywhere — hence one helper here. Async because it uses Web
38
+ * Crypto, which is what Workers, Node >= 20, and browsers share.
39
+ */
40
+ export declare function commentAnchorToken(commentId: string): Promise<string>;
41
+ /** Matches `#c-<token>` anywhere in a URL or text; group 1 is the token. */
42
+ export declare const COMMENT_ANCHOR_PATTERN: RegExp;
24
43
  export declare const MODERATION_ACTIONS: readonly ['publish', 'hold', 'reject', 'unsure'];
25
44
  export type ModerationAction = (typeof MODERATION_ACTIONS)[number];
26
45
  export declare const MODERATION_REASONS: readonly ['ok', 'spam', 'promotional', 'abuse', 'off_topic', 'personal_info'];
@@ -154,8 +173,12 @@ export interface CommentAuthor {
154
173
  }
155
174
  export interface Comment {
156
175
  id: string;
157
- /** Ghost's post.id, stable across slug renames. */
176
+ surface: CommentSurface;
177
+ /** `blog`: Ghost's post.id, stable across slug renames. `mood`: the
178
+ Telegram channel message id, the same value `/mood/[id]` routes on. */
158
179
  postId: string;
180
+ /** `commentAnchorToken(id)`, precomputed so clients never hash. */
181
+ anchorToken: string;
159
182
  /** Always a root comment id, or null. Threading is one level deep. */
160
183
  parentId: string | null;
161
184
  author: CommentAuthor;
@@ -189,6 +212,9 @@ export interface CommentListResult {
189
212
  total: number;
190
213
  }
191
214
  export interface CommentCreateInput {
215
+ /** Defaults to `blog`. `mood` requires the post to have a linked
216
+ discussion thread (`MoodContentDocument.discussionLinked`). */
217
+ surface?: CommentSurface;
192
218
  postId: string;
193
219
  body: string;
194
220
  /** Root comment id this replies to. Omitted or null for a root comment. */
package/dist/comments.js CHANGED
@@ -3,6 +3,14 @@ var READER_PROVIDERS = ["email", "github", "google"];
3
3
  var COMMENT_LOCALES = ["zh", "en"];
4
4
  var READER_GRADES = ["l0", "l1", "l2"];
5
5
  var COMMENT_STATUSES = ["published", "held", "rejected", "deleted"];
6
+ var COMMENT_SURFACES = ["blog", "mood"];
7
+ var COMMENT_ANCHOR_TOKEN_LENGTH = 12;
8
+ async function commentAnchorToken(commentId) {
9
+ const bytes = new TextEncoder().encode(commentId);
10
+ const digest = await crypto.subtle.digest("SHA-256", bytes);
11
+ return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("").slice(0, COMMENT_ANCHOR_TOKEN_LENGTH);
12
+ }
13
+ var COMMENT_ANCHOR_PATTERN = /#c-([0-9a-f]{12})\b/;
6
14
  var MODERATION_ACTIONS = ["publish", "hold", "reject", "unsure"];
7
15
  var MODERATION_REASONS = [
8
16
  "ok",
@@ -54,10 +62,13 @@ function commentPolicyFromTags(tags, base = DEFAULT_COMMENT_POLICY) {
54
62
  var acceptsComments = (policy) => policy.mode === "open";
55
63
  export {
56
64
  COMMENTS_MODES,
65
+ COMMENT_ANCHOR_PATTERN,
66
+ COMMENT_ANCHOR_TOKEN_LENGTH,
57
67
  COMMENT_CREATE_OUTCOMES,
58
68
  COMMENT_LOCALES,
59
69
  COMMENT_POLICY_TAGS,
60
70
  COMMENT_STATUSES,
71
+ COMMENT_SURFACES,
61
72
  DEFAULT_COMMENT_POLICY,
62
73
  DEFAULT_REACTION_EMOJI,
63
74
  MODERATION_ACTIONS,
@@ -68,5 +79,6 @@ export {
68
79
  READER_PROVIDERS,
69
80
  READER_VERIFY_OUTCOMES,
70
81
  acceptsComments,
82
+ commentAnchorToken,
71
83
  commentPolicyFromTags
72
84
  };
package/dist/content.d.ts CHANGED
@@ -79,6 +79,17 @@ export interface MoodContentDocument extends ContentDocument {
79
79
  source: 'mood';
80
80
  groupIds?: string[];
81
81
  channel?: ContentChannelSummary;
82
+ /** True when the post's copy in the Telegram discussion group is known
83
+ (`mood_posts.discussion_message_id`) and mood comments are enabled, so
84
+ the compose box can post into the thread. False or absent: the page
85
+ keeps the "Leave a comment on Telegram" link instead. */
86
+ discussionLinked?: boolean;
87
+ /** True once the read path has verified, from live traffic, that the
88
+ embed's comment ids are the group's message ids, which is what a
89
+ web reply to a Telegram-origin comment needs to thread correctly.
90
+ Gates reply-to on `telegram` items only; replies to `web` items are
91
+ always allowed. */
92
+ discussionRepliesEnabled?: boolean;
82
93
  }
83
94
  export interface PostContentDocument extends ContentDocument {
84
95
  source: 'post';
package/dist/index.d.ts CHANGED
@@ -3,6 +3,7 @@ export * from './admin';
3
3
  export * from './comments';
4
4
  export * from './content';
5
5
  export * from './listening';
6
+ export * from './messages';
6
7
  export * from './mood';
7
8
  export * from './notify';
8
9
  export * from './routes';
package/dist/index.js CHANGED
@@ -16,6 +16,14 @@ var READER_PROVIDERS = ["email", "github", "google"];
16
16
  var COMMENT_LOCALES = ["zh", "en"];
17
17
  var READER_GRADES = ["l0", "l1", "l2"];
18
18
  var COMMENT_STATUSES = ["published", "held", "rejected", "deleted"];
19
+ var COMMENT_SURFACES = ["blog", "mood"];
20
+ var COMMENT_ANCHOR_TOKEN_LENGTH = 12;
21
+ async function commentAnchorToken(commentId) {
22
+ const bytes = new TextEncoder().encode(commentId);
23
+ const digest = await crypto.subtle.digest("SHA-256", bytes);
24
+ return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("").slice(0, COMMENT_ANCHOR_TOKEN_LENGTH);
25
+ }
26
+ var COMMENT_ANCHOR_PATTERN = /#c-([0-9a-f]{12})\b/;
19
27
  var MODERATION_ACTIONS = ["publish", "hold", "reject", "unsure"];
20
28
  var MODERATION_REASONS = [
21
29
  "ok",
@@ -85,9 +93,17 @@ function parsePostLocaleTag(tagName) {
85
93
  }
86
94
  return canonicalSlug ? { locale, canonicalSlug } : { locale };
87
95
  }
96
+ // src/messages.ts
97
+ var MESSAGE_LOCALES = ["zh", "en"];
98
+ var MESSAGE_MIN_BODY_LENGTH = 2;
99
+ var MESSAGE_MAX_BODY_LENGTH = 4000;
100
+ var MESSAGE_MAX_NAME_LENGTH = 32;
101
+ var MESSAGE_STATES = ["new", "read", "replied", "archived", "spam"];
102
+
88
103
  // src/mood.ts
89
104
  var MOOD_SENTIMENT_LABELS = ["joy", "calm", "melancholy", "anger", "anxiety", "neutral"];
90
105
  var MOOD_AI_MODELS = ["gpt-5.5", "gpt-5", "claude-sonnet-4.6"];
106
+ var MOOD_COMMENT_ORIGINS = ["telegram", "web"];
91
107
 
92
108
  // src/notify.ts
93
109
  var NOTIFY_CHANNELS = ["mood", "blog", "privacy", "announcement"];
@@ -109,6 +125,7 @@ var MOOD_MEDIA_PROXY_BASE_PATH = "/v2/media";
109
125
  var LISTENING_PATH = "/v2/listening";
110
126
  var COMMENTS_PATH = "/v2/comments";
111
127
  var COMMENT_PATH_PREFIX = "/v2/comments/";
128
+ var OWNER_MESSAGES_PATH = "/v2/messages";
112
129
  var REACTIONS_PATH = "/v2/reactions";
113
130
  var REACTIONS_TOGGLE_PATH = "/v2/reactions/toggle";
114
131
  var READER_ME_PATH = "/v2/reader/me";
@@ -133,6 +150,12 @@ var LEGACY_HEALTH_PATH = "/v2/health";
133
150
 
134
151
  // src/telegram-ops.ts
135
152
  var TELEGRAM_OPS_WEBHOOK_PATH = "/webhooks/telegram-ops";
153
+ var TELEGRAM_OPS_COMMENT_CALLBACK_PREFIXES = {
154
+ reply: "comment:reply:",
155
+ approve: "comment:approve:",
156
+ hide: "comment:hide:",
157
+ delete: "comment:delete:"
158
+ };
136
159
  var NOTIFY_GATE_PATH = "/admin/notify-gate";
137
160
  var NOTIFY_GATE_RELEASE_PATH = `${NOTIFY_GATE_PATH}/release`;
138
161
  var NOTIFY_GATE_STATES = ["open", "held"];
@@ -194,11 +217,14 @@ export {
194
217
  BLOG_ANALYTICS_SUMMARY_ENDPOINT,
195
218
  COMMENTS_MODES,
196
219
  COMMENTS_PATH,
220
+ COMMENT_ANCHOR_PATTERN,
221
+ COMMENT_ANCHOR_TOKEN_LENGTH,
197
222
  COMMENT_CREATE_OUTCOMES,
198
223
  COMMENT_LOCALES,
199
224
  COMMENT_PATH_PREFIX,
200
225
  COMMENT_POLICY_TAGS,
201
226
  COMMENT_STATUSES,
227
+ COMMENT_SURFACES,
202
228
  CONTENT_DOCUMENT_SOURCES,
203
229
  DEFAULT_COMMENT_POLICY,
204
230
  DEFAULT_REACTION_EMOJI,
@@ -212,11 +238,17 @@ export {
212
238
  LEGACY_NOTIFY_BASE_PATH,
213
239
  LISTENING_ANALYTICS_EVENT_ENDPOINT,
214
240
  LISTENING_PATH,
241
+ MESSAGE_LOCALES,
242
+ MESSAGE_MAX_BODY_LENGTH,
243
+ MESSAGE_MAX_NAME_LENGTH,
244
+ MESSAGE_MIN_BODY_LENGTH,
245
+ MESSAGE_STATES,
215
246
  MODERATION_ACTIONS,
216
247
  MODERATION_REASONS,
217
248
  MOOD_AI_MODELS,
218
249
  MOOD_ARCHIVE_FEED_PATH,
219
250
  MOOD_ARCHIVE_STATS_PATH,
251
+ MOOD_COMMENT_ORIGINS,
220
252
  MOOD_IMAGE_PROXY_BASE_PATH,
221
253
  MOOD_LIVE_COUNTS_PATH,
222
254
  MOOD_LIVE_FEED_PATH,
@@ -235,6 +267,7 @@ export {
235
267
  NOTIFY_GATE_PATH,
236
268
  NOTIFY_GATE_RELEASE_PATH,
237
269
  NOTIFY_GATE_STATES,
270
+ OWNER_MESSAGES_PATH,
238
271
  PING_PATH,
239
272
  REACTIONS_PATH,
240
273
  REACTIONS_TOGGLE_PATH,
@@ -259,6 +292,7 @@ export {
259
292
  TELEGRAM_OPS_BROADCAST_PREVIEW_PATH,
260
293
  TELEGRAM_OPS_BROADCAST_SEND_PATH,
261
294
  TELEGRAM_OPS_BROADCAST_STATUSES,
295
+ TELEGRAM_OPS_COMMENT_CALLBACK_PREFIXES,
262
296
  TELEGRAM_OPS_EVENTS_PATH,
263
297
  TELEGRAM_OPS_OVERVIEW_PATH,
264
298
  TELEGRAM_OPS_REMINDERS_DUE_PATH,
@@ -268,6 +302,7 @@ export {
268
302
  TELEGRAM_OPS_WEBHOOK_PATH,
269
303
  TELEGRAM_WEBHOOK_PATH,
270
304
  acceptsComments,
305
+ commentAnchorToken,
271
306
  commentPolicyFromTags,
272
307
  parsePostLocaleTag,
273
308
  telegramOpsEventActionPath,
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Owner messages — the standalone form at /message.
3
+ *
4
+ * This is deliberately NOT the comments contract. A message is private by
5
+ * construction, not by moderation state: there is no `published`, no thread,
6
+ * no parent, no reactions, and no public read endpoint anywhere in this file.
7
+ * The comments stack answers "who may see this row"; here the answer is fixed
8
+ * at the storage layer, so a mis-written WHERE clause cannot leak one.
9
+ *
10
+ * What it does share with comments is everything that lives above the table:
11
+ * Turnstile, the honeypot and dwell tripwires, Akismet, the risk heuristics,
12
+ * reader identity, and the ops-bot notification. See site-api's
13
+ * features/messages/server/message-service.ts.
14
+ */
15
+ export declare const MESSAGE_LOCALES: readonly ['zh', 'en'];
16
+ export type MessageLocale = (typeof MESSAGE_LOCALES)[number];
17
+ /** Body bounds, shared by the form's client-side validation and the service. */
18
+ export declare const MESSAGE_MIN_BODY_LENGTH = 2;
19
+ export declare const MESSAGE_MAX_BODY_LENGTH = 4000;
20
+ export declare const MESSAGE_MAX_NAME_LENGTH = 32;
21
+ /**
22
+ * Triage, not moderation. Every value here is private; none of them makes a
23
+ * message visible to anyone but the owner, which is why there is no
24
+ * `published` member to accidentally set.
25
+ *
26
+ * new — landed, not yet looked at
27
+ * read — the owner has seen it
28
+ * replied — answered from Telegram; `repliedAt` is set
29
+ * archived — filed away by the owner
30
+ * spam — the risk stack or Akismet called it; never notified loudly
31
+ */
32
+ export declare const MESSAGE_STATES: readonly ['new', 'read', 'replied', 'archived', 'spam'];
33
+ export type MessageState = (typeof MESSAGE_STATES)[number];
34
+ export interface OwnerMessageCreateInput {
35
+ /** Plain text, MESSAGE_MIN_BODY_LENGTH–MESSAGE_MAX_BODY_LENGTH characters. */
36
+ body: string;
37
+ displayName: string;
38
+ /**
39
+ * Required. The comment box channels rather than blocks, because a comment
40
+ * that nobody can answer is still worth publishing; a private message that
41
+ * nobody can answer is a dead letter. Supplying one triggers the shared
42
+ * lazy-verification mail, and only a verified address can ever receive the
43
+ * owner's reply — so this is necessary for a reply, not sufficient.
44
+ */
45
+ email: string;
46
+ turnstileToken: string;
47
+ /** Minted by the form on load; proves the submit was not instant. */
48
+ dwellToken: string;
49
+ /** Honeypot. Any non-empty value is a silent drop. */
50
+ website?: string;
51
+ locale?: MessageLocale;
52
+ }
53
+ export interface OwnerMessageCreateResult {
54
+ id: string;
55
+ createdAt: string;
56
+ /**
57
+ * Whether the owner's reply can actually reach the sender. True only when
58
+ * the address belongs to a verified reader — an address typed into a public
59
+ * form is not proof that its owner sent anything, so an unverified one is
60
+ * never mailed. False also when no address was given at all; the form uses
61
+ * this to decide whether the receipt promises a reply or not.
62
+ */
63
+ replyable: boolean;
64
+ /**
65
+ * A verification mail just went out to a not-yet-verified address. The
66
+ * receipt tells the sender to click it if they want an answer.
67
+ */
68
+ verificationSent: boolean;
69
+ }
@@ -0,0 +1,13 @@
1
+ // src/messages.ts
2
+ var MESSAGE_LOCALES = ["zh", "en"];
3
+ var MESSAGE_MIN_BODY_LENGTH = 2;
4
+ var MESSAGE_MAX_BODY_LENGTH = 4000;
5
+ var MESSAGE_MAX_NAME_LENGTH = 32;
6
+ var MESSAGE_STATES = ["new", "read", "replied", "archived", "spam"];
7
+ export {
8
+ MESSAGE_LOCALES,
9
+ MESSAGE_MAX_BODY_LENGTH,
10
+ MESSAGE_MAX_NAME_LENGTH,
11
+ MESSAGE_MIN_BODY_LENGTH,
12
+ MESSAGE_STATES
13
+ };
package/dist/mood.d.ts CHANGED
@@ -188,13 +188,38 @@ export interface MoodLiveCount {
188
188
  export interface MoodLiveCountsResponse {
189
189
  counts: Record<string, MoodLiveCount>;
190
190
  }
191
+ /**
192
+ * The parent a comment replies to, read from the t.me reply block.
193
+ * `id` is the parent comment id; `text` is a plain-text preview, not HTML.
194
+ */
195
+ export interface MoodCommentReplyTo {
196
+ id: string;
197
+ author: string;
198
+ text: string;
199
+ }
200
+ /** Where a thread item came from. `telegram`: a group member wrote it in
201
+ the discussion thread. `web`: written on /mood/[id]; the group holds the
202
+ ops bot's bridged copy, and the read path re-attributes that copy to the
203
+ reader — plans/mood-comments-bridge.md "Read path: scrape plus overlay". */
204
+ export declare const MOOD_COMMENT_ORIGINS: readonly ['telegram', 'web'];
205
+ export type MoodCommentOrigin = (typeof MOOD_COMMENT_ORIGINS)[number];
191
206
  export interface MoodComment {
207
+ /** Discussion-group message id as the t.me embed reports it. */
192
208
  id: string;
193
209
  author: string;
194
210
  authorAvatar?: string;
195
211
  datetime: string;
196
212
  content: string;
197
213
  reactions: MoodReaction[];
214
+ replyTo?: MoodCommentReplyTo;
215
+ /** Omitted means `telegram`. */
216
+ origin?: MoodCommentOrigin;
217
+ /** The site comment row behind a `web` item (`Comment.id`). Lets the
218
+ browser mark rows it wrote and offer edit/delete through /v2/comments. */
219
+ commentId?: string;
220
+ /** `commentAnchorToken(commentId)`; the row renders as `id="c-<token>"`
221
+ so the bridged Telegram link and the owner card land on it. */
222
+ anchorToken?: string;
198
223
  }
199
224
  export interface MoodCommentsPage {
200
225
  comments: MoodComment[];
package/dist/mood.js CHANGED
@@ -1,7 +1,9 @@
1
1
  // src/mood.ts
2
2
  var MOOD_SENTIMENT_LABELS = ["joy", "calm", "melancholy", "anger", "anxiety", "neutral"];
3
3
  var MOOD_AI_MODELS = ["gpt-5.5", "gpt-5", "claude-sonnet-4.6"];
4
+ var MOOD_COMMENT_ORIGINS = ["telegram", "web"];
4
5
  export {
5
6
  MOOD_AI_MODELS,
7
+ MOOD_COMMENT_ORIGINS,
6
8
  MOOD_SENTIMENT_LABELS
7
9
  };
package/dist/routes.d.ts CHANGED
@@ -14,6 +14,7 @@ export declare const MOOD_MEDIA_PROXY_BASE_PATH: '/v2/media';
14
14
  export declare const LISTENING_PATH: '/v2/listening';
15
15
  export declare const COMMENTS_PATH: '/v2/comments';
16
16
  export declare const COMMENT_PATH_PREFIX: '/v2/comments/';
17
+ export declare const OWNER_MESSAGES_PATH: '/v2/messages';
17
18
  export declare const REACTIONS_PATH: '/v2/reactions';
18
19
  export declare const REACTIONS_TOGGLE_PATH: '/v2/reactions/toggle';
19
20
  export declare const READER_ME_PATH: '/v2/reader/me';
package/dist/routes.js CHANGED
@@ -15,6 +15,7 @@ var MOOD_MEDIA_PROXY_BASE_PATH = "/v2/media";
15
15
  var LISTENING_PATH = "/v2/listening";
16
16
  var COMMENTS_PATH = "/v2/comments";
17
17
  var COMMENT_PATH_PREFIX = "/v2/comments/";
18
+ var OWNER_MESSAGES_PATH = "/v2/messages";
18
19
  var REACTIONS_PATH = "/v2/reactions";
19
20
  var REACTIONS_TOGGLE_PATH = "/v2/reactions/toggle";
20
21
  var READER_ME_PATH = "/v2/reader/me";
@@ -61,6 +62,7 @@ export {
61
62
  MOOD_SEARCH_PATH,
62
63
  MUSICKIT_TOKEN_PATH,
63
64
  NOTIFY_BASE_PATH,
65
+ OWNER_MESSAGES_PATH,
64
66
  PING_PATH,
65
67
  REACTIONS_PATH,
66
68
  REACTIONS_TOGGLE_PATH,
@@ -1,6 +1,21 @@
1
1
  import type { AdminSubscriberPatch, BroadcastInput, BroadcastPreviewResult, BroadcastRecord, BroadcastSendResult } from './admin';
2
2
  import type { DeliveryMode, NotifyChannel, SubscriberRecord, SubscriberStatus } from './notify';
3
3
  export declare const TELEGRAM_OPS_WEBHOOK_PATH: '/webhooks/telegram-ops';
4
+ /**
5
+ * Callback data and message tokens the ops bot uses for comment cards. The
6
+ * comment id no longer lives in an expiring pending-action token: every
7
+ * card and every reply prompt carries `#c-<anchorToken>` in its View URL
8
+ * and as a text link, so replying to the card resolves the comment for as
9
+ * long as the card exists — plans/mood-comments-bridge.md "Owner reply
10
+ * flow". Group messages (the discussion group's automatic forwards and
11
+ * replies to the bot's bridged comments) are expected on this webhook too.
12
+ */
13
+ export declare const TELEGRAM_OPS_COMMENT_CALLBACK_PREFIXES: {
14
+ readonly reply: 'comment:reply:';
15
+ readonly approve: 'comment:approve:';
16
+ readonly hide: 'comment:hide:';
17
+ readonly delete: 'comment:delete:';
18
+ };
4
19
  export declare const NOTIFY_GATE_PATH: '/admin/notify-gate';
5
20
  export declare const NOTIFY_GATE_RELEASE_PATH: "/admin/notify-gate/release";
6
21
  export declare const NOTIFY_GATE_STATES: readonly ['open', 'held'];
@@ -1,5 +1,11 @@
1
1
  // src/telegram-ops.ts
2
2
  var TELEGRAM_OPS_WEBHOOK_PATH = "/webhooks/telegram-ops";
3
+ var TELEGRAM_OPS_COMMENT_CALLBACK_PREFIXES = {
4
+ reply: "comment:reply:",
5
+ approve: "comment:approve:",
6
+ hide: "comment:hide:",
7
+ delete: "comment:delete:"
8
+ };
3
9
  var NOTIFY_GATE_PATH = "/admin/notify-gate";
4
10
  var NOTIFY_GATE_RELEASE_PATH = `${NOTIFY_GATE_PATH}/release`;
5
11
  var NOTIFY_GATE_STATES = ["open", "held"];
@@ -61,6 +67,7 @@ export {
61
67
  TELEGRAM_OPS_BROADCAST_PREVIEW_PATH,
62
68
  TELEGRAM_OPS_BROADCAST_SEND_PATH,
63
69
  TELEGRAM_OPS_BROADCAST_STATUSES,
70
+ TELEGRAM_OPS_COMMENT_CALLBACK_PREFIXES,
64
71
  TELEGRAM_OPS_EVENTS_PATH,
65
72
  TELEGRAM_OPS_OVERVIEW_PATH,
66
73
  TELEGRAM_OPS_REMINDERS_DUE_PATH,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bunizao/contracts",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Shared TypeScript contracts for buxx.me services and clients.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -53,6 +53,11 @@
53
53
  "import": "./dist/listening.js",
54
54
  "default": "./dist/listening.js"
55
55
  },
56
+ "./messages": {
57
+ "types": "./dist/messages.d.ts",
58
+ "import": "./dist/messages.js",
59
+ "default": "./dist/messages.js"
60
+ },
56
61
  "./mood": {
57
62
  "types": "./dist/mood.d.ts",
58
63
  "import": "./dist/mood.js",