@bunizao/contracts 0.1.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/LICENSE +17 -0
- package/README.md +20 -0
- package/dist/admin.d.ts +87 -0
- package/dist/admin.js +0 -0
- package/dist/analytics.d.ts +208 -0
- package/dist/analytics.js +25 -0
- package/dist/content.d.ts +96 -0
- package/dist/content.js +23 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +180 -0
- package/dist/listening.d.ts +26 -0
- package/dist/listening.js +0 -0
- package/dist/mood.d.ts +203 -0
- package/dist/mood.js +7 -0
- package/dist/notify.d.ts +92 -0
- package/dist/notify.js +5 -0
- package/dist/routes.d.ts +24 -0
- package/dist/routes.js +51 -0
- package/dist/telegram-ops.d.ts +122 -0
- package/dist/telegram-ops.js +75 -0
- package/package.json +89 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface ListeningAccent {
|
|
2
|
+
hue: number;
|
|
3
|
+
chromaLight: number;
|
|
4
|
+
chromaDark: number;
|
|
5
|
+
}
|
|
6
|
+
export interface ListeningTrack {
|
|
7
|
+
id: string;
|
|
8
|
+
appleCatalogId: string;
|
|
9
|
+
catalogId?: string;
|
|
10
|
+
title: string;
|
|
11
|
+
artist: string;
|
|
12
|
+
collection: string;
|
|
13
|
+
appleMusicUrl: string;
|
|
14
|
+
artworkUrl: string;
|
|
15
|
+
thumbUrl: string;
|
|
16
|
+
accent: ListeningAccent | null;
|
|
17
|
+
previewUrl: string;
|
|
18
|
+
year: string;
|
|
19
|
+
genre: string;
|
|
20
|
+
releaseKind: 'album' | 'single';
|
|
21
|
+
trackNumber: string;
|
|
22
|
+
trackCount: string;
|
|
23
|
+
sourceUrl: string;
|
|
24
|
+
isNowPlaying: boolean;
|
|
25
|
+
playedAt: string;
|
|
26
|
+
}
|
|
File without changes
|
package/dist/mood.d.ts
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import type { ContentChannelSummary, ContentMediaLayout, ForwardedFrom, MediaItem, QuoteRef, Reaction } from './content';
|
|
2
|
+
export type MoodImageLayout = ContentMediaLayout;
|
|
3
|
+
export type ReactionData = Reaction;
|
|
4
|
+
export type ForwardedFromData = ForwardedFrom;
|
|
5
|
+
export type QuoteData = QuoteRef;
|
|
6
|
+
export type ChannelInfo = ContentChannelSummary;
|
|
7
|
+
export type MoodReaction = Reaction;
|
|
8
|
+
export type MoodForwardedFrom = ForwardedFrom;
|
|
9
|
+
export type MoodQuote = QuoteRef;
|
|
10
|
+
export type MoodChannelSummary = ContentChannelSummary;
|
|
11
|
+
export declare const MOOD_SENTIMENT_LABELS: readonly ['joy', 'calm', 'melancholy', 'anger', 'anxiety', 'neutral'];
|
|
12
|
+
export declare const MOOD_AI_MODELS: readonly ['gpt-5.5', 'gpt-5', 'claude-sonnet-4.6'];
|
|
13
|
+
export type MoodSentimentLabel = (typeof MOOD_SENTIMENT_LABELS)[number];
|
|
14
|
+
export type MoodAiModel = string;
|
|
15
|
+
export interface MoodSentiment {
|
|
16
|
+
label: MoodSentimentLabel;
|
|
17
|
+
score: number;
|
|
18
|
+
model: string;
|
|
19
|
+
at: string;
|
|
20
|
+
}
|
|
21
|
+
export interface MoodStatsActivityBucket {
|
|
22
|
+
date: string;
|
|
23
|
+
count: number;
|
|
24
|
+
}
|
|
25
|
+
export interface MoodStatsSentimentBucket {
|
|
26
|
+
bucketStart: string;
|
|
27
|
+
avgValence: number | null;
|
|
28
|
+
dominantLabel: MoodSentimentLabel | null;
|
|
29
|
+
scoredCount: number;
|
|
30
|
+
}
|
|
31
|
+
export interface MoodStatsSnapshot {
|
|
32
|
+
activity: MoodStatsActivityBucket[];
|
|
33
|
+
rhythm: number[][];
|
|
34
|
+
sentimentTimeline: MoodStatsSentimentBucket[];
|
|
35
|
+
streaks: {
|
|
36
|
+
current: number;
|
|
37
|
+
longest: number;
|
|
38
|
+
};
|
|
39
|
+
media: {
|
|
40
|
+
text: number;
|
|
41
|
+
photo: number;
|
|
42
|
+
video: number;
|
|
43
|
+
other: number;
|
|
44
|
+
};
|
|
45
|
+
totals: {
|
|
46
|
+
posts: number;
|
|
47
|
+
firstPostAt: string | null;
|
|
48
|
+
lastPostAt: string | null;
|
|
49
|
+
};
|
|
50
|
+
generatedAt: string;
|
|
51
|
+
}
|
|
52
|
+
export interface MoodAiConfig {
|
|
53
|
+
primary: MoodAiModel;
|
|
54
|
+
fallback: MoodAiModel;
|
|
55
|
+
updatedAt: string;
|
|
56
|
+
}
|
|
57
|
+
export interface MoodCoverageSummary {
|
|
58
|
+
total: number;
|
|
59
|
+
covered: number;
|
|
60
|
+
percent: number;
|
|
61
|
+
}
|
|
62
|
+
export interface MoodIngestHealth {
|
|
63
|
+
lastIngested: {
|
|
64
|
+
id: string;
|
|
65
|
+
datetime: string;
|
|
66
|
+
} | null;
|
|
67
|
+
liveLatest: {
|
|
68
|
+
id: string;
|
|
69
|
+
datetime?: string;
|
|
70
|
+
} | null;
|
|
71
|
+
drift: {
|
|
72
|
+
messages: number | null;
|
|
73
|
+
seconds: number | null;
|
|
74
|
+
};
|
|
75
|
+
coverage: {
|
|
76
|
+
sentiment: MoodCoverageSummary;
|
|
77
|
+
tags: MoodCoverageSummary;
|
|
78
|
+
};
|
|
79
|
+
replyIntegrity: {
|
|
80
|
+
edges: number;
|
|
81
|
+
unresolvedTargets: number;
|
|
82
|
+
unresolvedPostIds: string[];
|
|
83
|
+
unverifiedPosts: number;
|
|
84
|
+
oldestVerifiedAt: string | null;
|
|
85
|
+
};
|
|
86
|
+
snapshotGeneratedAt: string | null;
|
|
87
|
+
}
|
|
88
|
+
export interface MoodSearchResult {
|
|
89
|
+
id: string;
|
|
90
|
+
datetime: string;
|
|
91
|
+
snippet: string;
|
|
92
|
+
tags: string[];
|
|
93
|
+
sentiment_label: MoodSentimentLabel | null;
|
|
94
|
+
}
|
|
95
|
+
export interface MoodSearchResponse {
|
|
96
|
+
results: MoodSearchResult[];
|
|
97
|
+
}
|
|
98
|
+
export interface MoodFeedQuery {
|
|
99
|
+
before?: string;
|
|
100
|
+
after?: string;
|
|
101
|
+
fresh?: boolean;
|
|
102
|
+
limit?: number;
|
|
103
|
+
tag?: string;
|
|
104
|
+
}
|
|
105
|
+
export interface MoodGalleryItem {
|
|
106
|
+
src: string;
|
|
107
|
+
fallbackSrc: string | null;
|
|
108
|
+
width: number | null;
|
|
109
|
+
height: number | null;
|
|
110
|
+
layout: MoodImageLayout | null;
|
|
111
|
+
alt: string;
|
|
112
|
+
}
|
|
113
|
+
export interface MoodGallery {
|
|
114
|
+
items: MoodGalleryItem[];
|
|
115
|
+
count: number;
|
|
116
|
+
}
|
|
117
|
+
export interface MoodFeedItem {
|
|
118
|
+
id: string;
|
|
119
|
+
groupIds?: string[];
|
|
120
|
+
datetime: string;
|
|
121
|
+
tag: string;
|
|
122
|
+
previewText: string;
|
|
123
|
+
previewHtml: string;
|
|
124
|
+
previewMediaType?: string;
|
|
125
|
+
media: MediaItem[];
|
|
126
|
+
gallery?: MoodGallery | null;
|
|
127
|
+
image?: string | null;
|
|
128
|
+
imageFallback?: string | null;
|
|
129
|
+
imageWidth?: number | null;
|
|
130
|
+
imageHeight?: number | null;
|
|
131
|
+
imageLayout?: MoodImageLayout | null;
|
|
132
|
+
imageKind?: 'sticker' | null;
|
|
133
|
+
mediaHtml: string;
|
|
134
|
+
needsDetailPage: boolean;
|
|
135
|
+
forwardedFrom: MoodForwardedFrom | null;
|
|
136
|
+
quote: MoodQuote | null;
|
|
137
|
+
reactions: MoodReaction[];
|
|
138
|
+
commentsCount: number | string;
|
|
139
|
+
}
|
|
140
|
+
export interface MoodData {
|
|
141
|
+
id: string;
|
|
142
|
+
groupIds?: string[];
|
|
143
|
+
datetime: string;
|
|
144
|
+
tag?: string;
|
|
145
|
+
previewText: string;
|
|
146
|
+
previewHtml?: string;
|
|
147
|
+
previewMediaType?: string;
|
|
148
|
+
media?: MediaItem[];
|
|
149
|
+
gallery?: MoodGallery | null;
|
|
150
|
+
image?: string | null;
|
|
151
|
+
imageFallback?: string | null;
|
|
152
|
+
imageWidth?: number | null;
|
|
153
|
+
imageHeight?: number | null;
|
|
154
|
+
imageLayout?: MoodImageLayout | null;
|
|
155
|
+
imageKind?: 'sticker' | null;
|
|
156
|
+
mediaHtml?: string;
|
|
157
|
+
needsDetailPage?: boolean;
|
|
158
|
+
forwardedFrom?: ForwardedFromData | null;
|
|
159
|
+
quote?: QuoteData | null;
|
|
160
|
+
reactions?: ReactionData[];
|
|
161
|
+
commentsCount?: number | string;
|
|
162
|
+
}
|
|
163
|
+
export interface MoodFeedResponse {
|
|
164
|
+
posts: MoodFeedItem[];
|
|
165
|
+
channel: MoodChannelSummary;
|
|
166
|
+
}
|
|
167
|
+
export interface MoodProbeResult {
|
|
168
|
+
latestId: string;
|
|
169
|
+
}
|
|
170
|
+
export interface MoodImageProbe {
|
|
171
|
+
id: string;
|
|
172
|
+
datetime: string;
|
|
173
|
+
url: string | null;
|
|
174
|
+
r2Ready: boolean;
|
|
175
|
+
}
|
|
176
|
+
export interface MoodImageProbeResponse {
|
|
177
|
+
latestImage: MoodImageProbe | null;
|
|
178
|
+
}
|
|
179
|
+
export interface MoodMetaItem {
|
|
180
|
+
id: string;
|
|
181
|
+
reactions: MoodReaction[];
|
|
182
|
+
commentsCount: number | null;
|
|
183
|
+
}
|
|
184
|
+
export interface MoodLiveCount {
|
|
185
|
+
reactions: MoodReaction[] | null;
|
|
186
|
+
commentsCount: number | null;
|
|
187
|
+
}
|
|
188
|
+
export interface MoodLiveCountsResponse {
|
|
189
|
+
counts: Record<string, MoodLiveCount>;
|
|
190
|
+
}
|
|
191
|
+
export interface MoodComment {
|
|
192
|
+
id: string;
|
|
193
|
+
author: string;
|
|
194
|
+
authorAvatar?: string;
|
|
195
|
+
datetime: string;
|
|
196
|
+
content: string;
|
|
197
|
+
reactions: MoodReaction[];
|
|
198
|
+
}
|
|
199
|
+
export interface MoodCommentsPage {
|
|
200
|
+
comments: MoodComment[];
|
|
201
|
+
hasMore: boolean;
|
|
202
|
+
nextBefore: string;
|
|
203
|
+
}
|
package/dist/mood.js
ADDED
package/dist/notify.d.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
export type SubscriberStatus = 'pending' | 'active' | 'unsubscribed';
|
|
2
|
+
export type DeliveryMode = 'immediate' | 'every_5h' | 'daily';
|
|
3
|
+
export type NotifyChannel = 'mood' | 'blog' | 'privacy' | 'announcement';
|
|
4
|
+
export type NotifyAuditEventType = 'subscribe_requested' | 'subscription_confirmed' | 'unsubscribed' | 'email_change_requested' | 'email_changed' | 'admin_create' | 'admin_update' | 'admin_delete' | 'admin_resend_confirm' | 'broadcast_sent';
|
|
5
|
+
export declare const NOTIFY_CHANNELS: readonly NotifyChannel[];
|
|
6
|
+
export interface SubscriberRecord {
|
|
7
|
+
email: string;
|
|
8
|
+
emailHash: string;
|
|
9
|
+
status: SubscriberStatus;
|
|
10
|
+
channels: NotifyChannel[];
|
|
11
|
+
deliveryMode?: DeliveryMode;
|
|
12
|
+
timezone?: string;
|
|
13
|
+
dailyHour?: number;
|
|
14
|
+
pendingDeliveryMode?: DeliveryMode;
|
|
15
|
+
pendingTimezone?: string;
|
|
16
|
+
pendingDailyHour?: number;
|
|
17
|
+
lastNotifiedAt?: string;
|
|
18
|
+
lastNotifiedPostId?: string;
|
|
19
|
+
createdAt: string;
|
|
20
|
+
updatedAt: string;
|
|
21
|
+
confirmedAt?: string;
|
|
22
|
+
lastConfirmSentAt?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface RetryRecord {
|
|
25
|
+
postId: string;
|
|
26
|
+
email: string;
|
|
27
|
+
emailHash: string;
|
|
28
|
+
subscriberCreatedAt: string;
|
|
29
|
+
attempt: number;
|
|
30
|
+
createdAt: string;
|
|
31
|
+
updatedAt: string;
|
|
32
|
+
nextAttemptAt: string;
|
|
33
|
+
lastError: string;
|
|
34
|
+
}
|
|
35
|
+
export interface SentRecord {
|
|
36
|
+
postId: string;
|
|
37
|
+
emailHash: string;
|
|
38
|
+
sentAt: string;
|
|
39
|
+
resendId?: string;
|
|
40
|
+
}
|
|
41
|
+
export interface NotifyAuditRecord {
|
|
42
|
+
eventType: NotifyAuditEventType;
|
|
43
|
+
email: string;
|
|
44
|
+
emailHash: string;
|
|
45
|
+
source: string;
|
|
46
|
+
userAgent?: string;
|
|
47
|
+
ipHash?: string;
|
|
48
|
+
tokenHash?: string;
|
|
49
|
+
createdAt: string;
|
|
50
|
+
}
|
|
51
|
+
export interface SubscribeResult {
|
|
52
|
+
status: 'confirmation_sent' | 'already_subscribed';
|
|
53
|
+
email: string;
|
|
54
|
+
deliveryMode: DeliveryMode;
|
|
55
|
+
}
|
|
56
|
+
export interface ConfirmResult {
|
|
57
|
+
status: 'subscribed';
|
|
58
|
+
email: string;
|
|
59
|
+
deliveryMode: DeliveryMode;
|
|
60
|
+
/** Short-lived manage-page grant. Confirming is itself proof of the address,
|
|
61
|
+
so the reader is handed the panel instead of a second round trip. Secret:
|
|
62
|
+
never log it and never put it in a JSON response. */
|
|
63
|
+
manageToken: string;
|
|
64
|
+
}
|
|
65
|
+
export interface UnsubscribeResult {
|
|
66
|
+
status: 'unsubscribed';
|
|
67
|
+
email: string;
|
|
68
|
+
}
|
|
69
|
+
export interface DispatchResult {
|
|
70
|
+
postId: string;
|
|
71
|
+
subscribers: number;
|
|
72
|
+
sent: number;
|
|
73
|
+
skipped: number;
|
|
74
|
+
failed: number;
|
|
75
|
+
skippedReason?: string;
|
|
76
|
+
}
|
|
77
|
+
export interface RetryProcessResult {
|
|
78
|
+
scanned: number;
|
|
79
|
+
processed: number;
|
|
80
|
+
sent: number;
|
|
81
|
+
dropped: number;
|
|
82
|
+
failed: number;
|
|
83
|
+
}
|
|
84
|
+
export interface ScheduledDispatchResult {
|
|
85
|
+
postId: string;
|
|
86
|
+
scanned: number;
|
|
87
|
+
due: number;
|
|
88
|
+
sent: number;
|
|
89
|
+
skipped: number;
|
|
90
|
+
failed: number;
|
|
91
|
+
skippedReason?: string;
|
|
92
|
+
}
|
package/dist/notify.js
ADDED
package/dist/routes.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare const API_PREFIX: '/api';
|
|
2
|
+
export declare const HEALTH_PATH: '/health';
|
|
3
|
+
export declare const PING_PATH: '/ping';
|
|
4
|
+
export declare const MOOD_PUBLIC_FEED_PATH: '/api/moods';
|
|
5
|
+
export declare const MOOD_PUBLIC_COMMENTS_PATH: '/api/comments';
|
|
6
|
+
export declare const MOOD_LIVE_FEED_PATH: '/v1/mood';
|
|
7
|
+
export declare const MOOD_LIVE_META_PATH: '/v1/mood/meta';
|
|
8
|
+
export declare const MOOD_ARCHIVE_FEED_PATH: '/v2/mood';
|
|
9
|
+
export declare const MOOD_LIVE_COUNTS_PATH: '/v2/moods/live-counts';
|
|
10
|
+
export declare const MOOD_ARCHIVE_STATS_PATH: '/v2/mood/stats';
|
|
11
|
+
export declare const MOOD_SEARCH_PATH: '/v2/mood/search';
|
|
12
|
+
export declare const MOOD_IMAGE_PROXY_BASE_PATH: '/v2/images';
|
|
13
|
+
export declare const MOOD_MEDIA_PROXY_BASE_PATH: '/v2/media';
|
|
14
|
+
export declare const LISTENING_PATH: '/v2/listening';
|
|
15
|
+
export declare const ADMIN_BASE_PATH: '/admin';
|
|
16
|
+
export declare const NOTIFY_BASE_PATH: '/notify';
|
|
17
|
+
export declare const GHOST_WEBHOOK_PATH: '/webhooks/ghost';
|
|
18
|
+
export declare const TELEGRAM_WEBHOOK_PATH: '/webhooks/telegram';
|
|
19
|
+
export declare const MUSICKIT_TOKEN_PATH: '/musickit/token';
|
|
20
|
+
export declare const LEGACY_ADMIN_BASE_PATH: '/v2/admin';
|
|
21
|
+
export declare const LEGACY_NOTIFY_BASE_PATH: '/v2/notify';
|
|
22
|
+
export declare const LEGACY_GHOST_WEBHOOK_PATH: '/v2/ghost/webhook';
|
|
23
|
+
export declare const LEGACY_MUSICKIT_TOKEN_PATH: '/v2/musickit/token';
|
|
24
|
+
export declare const LEGACY_HEALTH_PATH: '/v2/health';
|
package/dist/routes.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// src/routes.ts
|
|
2
|
+
var API_PREFIX = "/api";
|
|
3
|
+
var HEALTH_PATH = "/health";
|
|
4
|
+
var PING_PATH = "/ping";
|
|
5
|
+
var MOOD_PUBLIC_FEED_PATH = "/api/moods";
|
|
6
|
+
var MOOD_PUBLIC_COMMENTS_PATH = "/api/comments";
|
|
7
|
+
var MOOD_LIVE_FEED_PATH = "/v1/mood";
|
|
8
|
+
var MOOD_LIVE_META_PATH = "/v1/mood/meta";
|
|
9
|
+
var MOOD_ARCHIVE_FEED_PATH = "/v2/mood";
|
|
10
|
+
var MOOD_LIVE_COUNTS_PATH = "/v2/moods/live-counts";
|
|
11
|
+
var MOOD_ARCHIVE_STATS_PATH = "/v2/mood/stats";
|
|
12
|
+
var MOOD_SEARCH_PATH = "/v2/mood/search";
|
|
13
|
+
var MOOD_IMAGE_PROXY_BASE_PATH = "/v2/images";
|
|
14
|
+
var MOOD_MEDIA_PROXY_BASE_PATH = "/v2/media";
|
|
15
|
+
var LISTENING_PATH = "/v2/listening";
|
|
16
|
+
var ADMIN_BASE_PATH = "/admin";
|
|
17
|
+
var NOTIFY_BASE_PATH = "/notify";
|
|
18
|
+
var GHOST_WEBHOOK_PATH = "/webhooks/ghost";
|
|
19
|
+
var TELEGRAM_WEBHOOK_PATH = "/webhooks/telegram";
|
|
20
|
+
var MUSICKIT_TOKEN_PATH = "/musickit/token";
|
|
21
|
+
var LEGACY_ADMIN_BASE_PATH = "/v2/admin";
|
|
22
|
+
var LEGACY_NOTIFY_BASE_PATH = "/v2/notify";
|
|
23
|
+
var LEGACY_GHOST_WEBHOOK_PATH = "/v2/ghost/webhook";
|
|
24
|
+
var LEGACY_MUSICKIT_TOKEN_PATH = "/v2/musickit/token";
|
|
25
|
+
var LEGACY_HEALTH_PATH = "/v2/health";
|
|
26
|
+
export {
|
|
27
|
+
TELEGRAM_WEBHOOK_PATH,
|
|
28
|
+
PING_PATH,
|
|
29
|
+
NOTIFY_BASE_PATH,
|
|
30
|
+
MUSICKIT_TOKEN_PATH,
|
|
31
|
+
MOOD_SEARCH_PATH,
|
|
32
|
+
MOOD_PUBLIC_FEED_PATH,
|
|
33
|
+
MOOD_PUBLIC_COMMENTS_PATH,
|
|
34
|
+
MOOD_MEDIA_PROXY_BASE_PATH,
|
|
35
|
+
MOOD_LIVE_META_PATH,
|
|
36
|
+
MOOD_LIVE_FEED_PATH,
|
|
37
|
+
MOOD_LIVE_COUNTS_PATH,
|
|
38
|
+
MOOD_IMAGE_PROXY_BASE_PATH,
|
|
39
|
+
MOOD_ARCHIVE_STATS_PATH,
|
|
40
|
+
MOOD_ARCHIVE_FEED_PATH,
|
|
41
|
+
LISTENING_PATH,
|
|
42
|
+
LEGACY_NOTIFY_BASE_PATH,
|
|
43
|
+
LEGACY_MUSICKIT_TOKEN_PATH,
|
|
44
|
+
LEGACY_HEALTH_PATH,
|
|
45
|
+
LEGACY_GHOST_WEBHOOK_PATH,
|
|
46
|
+
LEGACY_ADMIN_BASE_PATH,
|
|
47
|
+
HEALTH_PATH,
|
|
48
|
+
GHOST_WEBHOOK_PATH,
|
|
49
|
+
API_PREFIX,
|
|
50
|
+
ADMIN_BASE_PATH
|
|
51
|
+
};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type { AdminSubscriberPatch, BroadcastInput, BroadcastPreviewResult, BroadcastRecord, BroadcastSendResult } from './admin';
|
|
2
|
+
import type { DeliveryMode, NotifyChannel, SubscriberRecord, SubscriberStatus } from './notify';
|
|
3
|
+
export declare const TELEGRAM_OPS_WEBHOOK_PATH: '/webhooks/telegram-ops';
|
|
4
|
+
export declare const NOTIFY_GATE_PATH: '/admin/notify-gate';
|
|
5
|
+
export declare const NOTIFY_GATE_RELEASE_PATH: "/admin/notify-gate/release";
|
|
6
|
+
export declare const NOTIFY_GATE_STATES: readonly ['open', 'held'];
|
|
7
|
+
export type NotifyGateState = (typeof NOTIFY_GATE_STATES)[number];
|
|
8
|
+
export declare const NOTIFY_GATE_DECISIONS: readonly ['digest', 'individual', 'drop'];
|
|
9
|
+
export type NotifyGateDecision = (typeof NOTIFY_GATE_DECISIONS)[number];
|
|
10
|
+
export interface NotifyGateConfig {
|
|
11
|
+
thresholdCount: number;
|
|
12
|
+
thresholdWindowMinutes: number;
|
|
13
|
+
autoReleaseAfterHours: number;
|
|
14
|
+
}
|
|
15
|
+
export interface NotifyGateStatus {
|
|
16
|
+
channel: NotifyChannel;
|
|
17
|
+
state: NotifyGateState;
|
|
18
|
+
heldSince: string | null;
|
|
19
|
+
heldPostIds: string[];
|
|
20
|
+
recentDispatchCount: number;
|
|
21
|
+
config: NotifyGateConfig;
|
|
22
|
+
}
|
|
23
|
+
export interface NotifyGateReleaseInput {
|
|
24
|
+
decision: NotifyGateDecision;
|
|
25
|
+
}
|
|
26
|
+
export interface NotifyGateReleaseResult {
|
|
27
|
+
channel: NotifyChannel;
|
|
28
|
+
decision: NotifyGateDecision;
|
|
29
|
+
releasedPostIds: string[];
|
|
30
|
+
actor: string;
|
|
31
|
+
releasedAt: string;
|
|
32
|
+
}
|
|
33
|
+
export declare const TELEGRAM_OPS_BASE_PATH: '/admin/integrations/telegram-ops';
|
|
34
|
+
export declare const TELEGRAM_OPS_OVERVIEW_PATH: "/admin/integrations/telegram-ops/overview";
|
|
35
|
+
export declare const TELEGRAM_OPS_EVENTS_PATH: "/admin/integrations/telegram-ops/events";
|
|
36
|
+
export declare const TELEGRAM_OPS_SUBSCRIBERS_PATH: "/admin/integrations/telegram-ops/subscribers";
|
|
37
|
+
export declare const TELEGRAM_OPS_BROADCASTS_PATH: "/admin/integrations/telegram-ops/broadcasts";
|
|
38
|
+
export declare const TELEGRAM_OPS_BROADCAST_PREVIEW_PATH: "/admin/integrations/telegram-ops/broadcasts/preview";
|
|
39
|
+
export declare const TELEGRAM_OPS_BROADCAST_SEND_PATH: "/admin/integrations/telegram-ops/broadcasts/send";
|
|
40
|
+
export declare const TELEGRAM_OPS_REMINDERS_PATH: "/admin/integrations/telegram-ops/reminders";
|
|
41
|
+
export declare const TELEGRAM_OPS_REMINDERS_DUE_PATH: "/admin/integrations/telegram-ops/reminders/due";
|
|
42
|
+
export declare function telegramOpsEventPath(id: string): string;
|
|
43
|
+
export declare function telegramOpsEventActionPath(id: string, action: 'publish' | 'cancel'): string;
|
|
44
|
+
export declare function telegramOpsSubscriberPath(emailHash: string): string;
|
|
45
|
+
export declare function telegramOpsReminderDeliveredPath(eventId: string): string;
|
|
46
|
+
export declare const EVENT_STATUSES: readonly ['draft', 'published', 'cancelled'];
|
|
47
|
+
export declare const TELEGRAM_OPS_SUBSCRIBER_STATUSES: readonly ["pending", "active", "unsubscribed"];
|
|
48
|
+
export declare const TELEGRAM_OPS_BROADCAST_CHANNELS: readonly ["mood", "blog", "privacy", "announcement"];
|
|
49
|
+
export declare const TELEGRAM_OPS_BROADCAST_DELIVERY_MODES: readonly ["immediate", "every_5h", "daily"];
|
|
50
|
+
export declare const TELEGRAM_OPS_BROADCAST_STATUSES: readonly ["draft", "sending", "sent", "failed"];
|
|
51
|
+
export type EventStatus = (typeof EVENT_STATUSES)[number];
|
|
52
|
+
export interface AdminEvent {
|
|
53
|
+
id: string;
|
|
54
|
+
title: string;
|
|
55
|
+
startsAt: string;
|
|
56
|
+
endsAt: string | null;
|
|
57
|
+
timezone: string;
|
|
58
|
+
location: string | null;
|
|
59
|
+
notes: string | null;
|
|
60
|
+
status: EventStatus;
|
|
61
|
+
version: number;
|
|
62
|
+
createdBy: string;
|
|
63
|
+
updatedBy: string;
|
|
64
|
+
createdAt: string;
|
|
65
|
+
updatedAt: string;
|
|
66
|
+
}
|
|
67
|
+
export interface CreateEventInput {
|
|
68
|
+
title: string;
|
|
69
|
+
startsAt: string;
|
|
70
|
+
endsAt?: string | null;
|
|
71
|
+
timezone: string;
|
|
72
|
+
location?: string | null;
|
|
73
|
+
notes?: string | null;
|
|
74
|
+
}
|
|
75
|
+
export type UpdateEventInput = Partial<CreateEventInput> & {
|
|
76
|
+
version: number;
|
|
77
|
+
};
|
|
78
|
+
export interface EventActionInput {
|
|
79
|
+
version: number;
|
|
80
|
+
}
|
|
81
|
+
export type TelegramOpsEvent = AdminEvent;
|
|
82
|
+
export type TelegramOpsSubscriberStatus = SubscriberStatus;
|
|
83
|
+
export type TelegramOpsNotifyChannel = NotifyChannel;
|
|
84
|
+
export type TelegramOpsDeliveryMode = DeliveryMode;
|
|
85
|
+
export type TelegramOpsSubscriber = SubscriberRecord;
|
|
86
|
+
export type TelegramOpsSubscriberPatch = AdminSubscriberPatch;
|
|
87
|
+
export type TelegramOpsBroadcast = BroadcastRecord;
|
|
88
|
+
export type TelegramOpsBroadcastAudience = BroadcastInput['audience'];
|
|
89
|
+
export type TelegramOpsBroadcastInput = BroadcastInput;
|
|
90
|
+
export type TelegramOpsBroadcastSendResult = BroadcastSendResult;
|
|
91
|
+
export interface TelegramOpsConfirmedBroadcastInput extends BroadcastInput {
|
|
92
|
+
confirmed: true;
|
|
93
|
+
audienceFingerprint: string;
|
|
94
|
+
}
|
|
95
|
+
export interface TelegramOpsBroadcastPreview extends BroadcastPreviewResult {
|
|
96
|
+
audienceFingerprint: string;
|
|
97
|
+
}
|
|
98
|
+
export type TelegramOpsOverviewBroadcast = Pick<BroadcastRecord, 'id' | 'subject' | 'status' | 'recipientCount' | 'sentCount' | 'failedCount' | 'createdAt' | 'sentAt'>;
|
|
99
|
+
export interface TelegramOpsOverview {
|
|
100
|
+
portalUrl: string;
|
|
101
|
+
subscribers: {
|
|
102
|
+
total: number;
|
|
103
|
+
active: number;
|
|
104
|
+
pending: number;
|
|
105
|
+
unsubscribed: number;
|
|
106
|
+
};
|
|
107
|
+
broadcasts: {
|
|
108
|
+
recentCount: number;
|
|
109
|
+
last: TelegramOpsOverviewBroadcast | null;
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
export interface TelegramOpsDueRemindersResult {
|
|
113
|
+
events: AdminEvent[];
|
|
114
|
+
}
|
|
115
|
+
export interface TelegramOpsReminderDelivery {
|
|
116
|
+
actor: string;
|
|
117
|
+
eventId: string;
|
|
118
|
+
deliveredAt: string;
|
|
119
|
+
}
|
|
120
|
+
export interface TelegramOpsReminderDeliveredResult {
|
|
121
|
+
delivered: TelegramOpsReminderDelivery;
|
|
122
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// src/telegram-ops.ts
|
|
2
|
+
var TELEGRAM_OPS_WEBHOOK_PATH = "/webhooks/telegram-ops";
|
|
3
|
+
var NOTIFY_GATE_PATH = "/admin/notify-gate";
|
|
4
|
+
var NOTIFY_GATE_RELEASE_PATH = `${NOTIFY_GATE_PATH}/release`;
|
|
5
|
+
var NOTIFY_GATE_STATES = ["open", "held"];
|
|
6
|
+
var NOTIFY_GATE_DECISIONS = ["digest", "individual", "drop"];
|
|
7
|
+
var TELEGRAM_OPS_BASE_PATH = "/admin/integrations/telegram-ops";
|
|
8
|
+
var TELEGRAM_OPS_OVERVIEW_PATH = `${TELEGRAM_OPS_BASE_PATH}/overview`;
|
|
9
|
+
var TELEGRAM_OPS_EVENTS_PATH = `${TELEGRAM_OPS_BASE_PATH}/events`;
|
|
10
|
+
var TELEGRAM_OPS_SUBSCRIBERS_PATH = `${TELEGRAM_OPS_BASE_PATH}/subscribers`;
|
|
11
|
+
var TELEGRAM_OPS_BROADCASTS_PATH = `${TELEGRAM_OPS_BASE_PATH}/broadcasts`;
|
|
12
|
+
var TELEGRAM_OPS_BROADCAST_PREVIEW_PATH = `${TELEGRAM_OPS_BROADCASTS_PATH}/preview`;
|
|
13
|
+
var TELEGRAM_OPS_BROADCAST_SEND_PATH = `${TELEGRAM_OPS_BROADCASTS_PATH}/send`;
|
|
14
|
+
var TELEGRAM_OPS_REMINDERS_PATH = `${TELEGRAM_OPS_BASE_PATH}/reminders`;
|
|
15
|
+
var TELEGRAM_OPS_REMINDERS_DUE_PATH = `${TELEGRAM_OPS_REMINDERS_PATH}/due`;
|
|
16
|
+
function telegramOpsEventPath(id) {
|
|
17
|
+
return `${TELEGRAM_OPS_EVENTS_PATH}/${encodeURIComponent(id)}`;
|
|
18
|
+
}
|
|
19
|
+
function telegramOpsEventActionPath(id, action) {
|
|
20
|
+
return `${telegramOpsEventPath(id)}/${action}`;
|
|
21
|
+
}
|
|
22
|
+
function telegramOpsSubscriberPath(emailHash) {
|
|
23
|
+
return `${TELEGRAM_OPS_SUBSCRIBERS_PATH}/${encodeURIComponent(emailHash)}`;
|
|
24
|
+
}
|
|
25
|
+
function telegramOpsReminderDeliveredPath(eventId) {
|
|
26
|
+
return `${TELEGRAM_OPS_REMINDERS_PATH}/${encodeURIComponent(eventId)}/delivered`;
|
|
27
|
+
}
|
|
28
|
+
var EVENT_STATUSES = ["draft", "published", "cancelled"];
|
|
29
|
+
var TELEGRAM_OPS_SUBSCRIBER_STATUSES = [
|
|
30
|
+
"pending",
|
|
31
|
+
"active",
|
|
32
|
+
"unsubscribed"
|
|
33
|
+
];
|
|
34
|
+
var TELEGRAM_OPS_BROADCAST_CHANNELS = [
|
|
35
|
+
"mood",
|
|
36
|
+
"blog",
|
|
37
|
+
"privacy",
|
|
38
|
+
"announcement"
|
|
39
|
+
];
|
|
40
|
+
var TELEGRAM_OPS_BROADCAST_DELIVERY_MODES = [
|
|
41
|
+
"immediate",
|
|
42
|
+
"every_5h",
|
|
43
|
+
"daily"
|
|
44
|
+
];
|
|
45
|
+
var TELEGRAM_OPS_BROADCAST_STATUSES = [
|
|
46
|
+
"draft",
|
|
47
|
+
"sending",
|
|
48
|
+
"sent",
|
|
49
|
+
"failed"
|
|
50
|
+
];
|
|
51
|
+
export {
|
|
52
|
+
telegramOpsSubscriberPath,
|
|
53
|
+
telegramOpsReminderDeliveredPath,
|
|
54
|
+
telegramOpsEventPath,
|
|
55
|
+
telegramOpsEventActionPath,
|
|
56
|
+
TELEGRAM_OPS_WEBHOOK_PATH,
|
|
57
|
+
TELEGRAM_OPS_SUBSCRIBER_STATUSES,
|
|
58
|
+
TELEGRAM_OPS_SUBSCRIBERS_PATH,
|
|
59
|
+
TELEGRAM_OPS_REMINDERS_PATH,
|
|
60
|
+
TELEGRAM_OPS_REMINDERS_DUE_PATH,
|
|
61
|
+
TELEGRAM_OPS_OVERVIEW_PATH,
|
|
62
|
+
TELEGRAM_OPS_EVENTS_PATH,
|
|
63
|
+
TELEGRAM_OPS_BROADCAST_STATUSES,
|
|
64
|
+
TELEGRAM_OPS_BROADCAST_SEND_PATH,
|
|
65
|
+
TELEGRAM_OPS_BROADCAST_PREVIEW_PATH,
|
|
66
|
+
TELEGRAM_OPS_BROADCAST_DELIVERY_MODES,
|
|
67
|
+
TELEGRAM_OPS_BROADCAST_CHANNELS,
|
|
68
|
+
TELEGRAM_OPS_BROADCASTS_PATH,
|
|
69
|
+
TELEGRAM_OPS_BASE_PATH,
|
|
70
|
+
NOTIFY_GATE_STATES,
|
|
71
|
+
NOTIFY_GATE_RELEASE_PATH,
|
|
72
|
+
NOTIFY_GATE_PATH,
|
|
73
|
+
NOTIFY_GATE_DECISIONS,
|
|
74
|
+
EVENT_STATUSES
|
|
75
|
+
};
|