@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.
- package/dist/comments.d.ts +27 -1
- package/dist/comments.js +12 -0
- package/dist/content.d.ts +11 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +35 -0
- package/dist/messages.d.ts +69 -0
- package/dist/messages.js +13 -0
- package/dist/mood.d.ts +25 -0
- package/dist/mood.js +2 -0
- package/dist/routes.d.ts +1 -0
- package/dist/routes.js +2 -0
- package/dist/telegram-ops.d.ts +15 -0
- package/dist/telegram-ops.js +7 -0
- package/package.json +6 -1
package/dist/comments.d.ts
CHANGED
|
@@ -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
|
-
|
|
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
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
|
+
}
|
package/dist/messages.js
ADDED
|
@@ -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,
|
package/dist/telegram-ops.d.ts
CHANGED
|
@@ -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'];
|
package/dist/telegram-ops.js
CHANGED
|
@@ -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
|
+
"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",
|