@bunizao/contracts 0.12.0 → 0.14.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/admin.d.ts +3 -1
- package/dist/analytics.d.ts +153 -0
- package/dist/analytics.js +32 -1
- package/dist/index.js +33 -0
- package/dist/listening.d.ts +15 -0
- package/dist/notify.d.ts +14 -0
- package/dist/notify.js +3 -1
- package/package.json +1 -1
package/dist/admin.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ClientFingerprint, CommentAuthAtWrite, CommentClaimMethod, CommentsMode, CommentStatus, CommentSurface, Interaction } from './comments';
|
|
2
2
|
import type { MessageLocale, MessageState } from './messages';
|
|
3
|
-
import type { DeliveryMode, NotifyAuditEventType, NotifyChannel, SubscriberRecord, SubscriberStatus } from './notify';
|
|
3
|
+
import type { DeliveryMode, NotifyAuditEventType, NotifyChannel, SubscriberRecord, SubscriberStatus, SubscriptionSource } from './notify';
|
|
4
4
|
export interface SubscriberChannelCount {
|
|
5
5
|
total: number;
|
|
6
6
|
pendingCount: number;
|
|
@@ -24,6 +24,8 @@ export interface SubscriberListResult {
|
|
|
24
24
|
activeCount: number;
|
|
25
25
|
unsubscribedCount: number;
|
|
26
26
|
channelCounts?: SubscriberChannelCounts;
|
|
27
|
+
/** Acquisition counts, kept separate from the subscribed channels. */
|
|
28
|
+
acquisitionCounts?: Record<SubscriptionSource | 'unknown', SubscriberChannelCount>;
|
|
27
29
|
}
|
|
28
30
|
export interface AuditEntry {
|
|
29
31
|
id: number;
|
package/dist/analytics.d.ts
CHANGED
|
@@ -206,3 +206,156 @@ export interface BlogAnalyticsArticleDetailResult {
|
|
|
206
206
|
countries: BlogAnalyticsBreakdown[];
|
|
207
207
|
scrollBuckets: BlogAnalyticsScrollBucket[];
|
|
208
208
|
}
|
|
209
|
+
export declare const SITE_ANALYTICS_COLLECT_ENDPOINT: '/api/analytics/collect';
|
|
210
|
+
export declare const SITE_ANALYTICS_REPORT_ENDPOINT: '/api/analytics/site';
|
|
211
|
+
export declare const SITE_ANALYTICS_ENGAGED_DWELL_MS = 10000;
|
|
212
|
+
export declare const SITE_ANALYTICS_SESSION_IDLE_MS: number;
|
|
213
|
+
export declare const SITE_ANALYTICS_SURFACES: readonly ['home', 'legacy', 'not_found', 'blog_index', 'blog_tags', 'blog_tag', 'blog_post', 'mood_feed', 'mood_post', 'mood_embed', 'projects', 'message', 'privacy', 'subscribe_manage', 'reader', 'docs', 'components', 'other'];
|
|
214
|
+
export type SiteAnalyticsSurface = typeof SITE_ANALYTICS_SURFACES[number];
|
|
215
|
+
export type SiteAnalyticsClickKind = 'link_internal' | 'link_outbound' | 'button' | 'panel';
|
|
216
|
+
export type SiteAnalyticsTrafficClass = 'human' | 'bot' | 'owner';
|
|
217
|
+
export interface SiteAnalyticsClick {
|
|
218
|
+
name: string;
|
|
219
|
+
kind: SiteAnalyticsClickKind;
|
|
220
|
+
href: string;
|
|
221
|
+
region: string;
|
|
222
|
+
label: string;
|
|
223
|
+
position: number;
|
|
224
|
+
tMs: number;
|
|
225
|
+
}
|
|
226
|
+
export interface SiteAnalyticsCollectInput {
|
|
227
|
+
v: 1;
|
|
228
|
+
viewId: string;
|
|
229
|
+
visitorId: string;
|
|
230
|
+
sessionId: string;
|
|
231
|
+
seq: number;
|
|
232
|
+
owner?: true;
|
|
233
|
+
page: {
|
|
234
|
+
surface: SiteAnalyticsSurface;
|
|
235
|
+
entity: string;
|
|
236
|
+
path: string;
|
|
237
|
+
locale: string;
|
|
238
|
+
referrer: string;
|
|
239
|
+
utm: [string, string, string];
|
|
240
|
+
};
|
|
241
|
+
client: {
|
|
242
|
+
tz: string;
|
|
243
|
+
langs: string[];
|
|
244
|
+
vw: number;
|
|
245
|
+
vh: number;
|
|
246
|
+
dpr: number;
|
|
247
|
+
navType: 0 | 1 | 2 | 3;
|
|
248
|
+
isEntry: boolean;
|
|
249
|
+
isNewVisitor: boolean;
|
|
250
|
+
webdriver: boolean;
|
|
251
|
+
};
|
|
252
|
+
progress: {
|
|
253
|
+
dwellMs: number;
|
|
254
|
+
scrollDepth: number;
|
|
255
|
+
interactions: number;
|
|
256
|
+
firstInputMs: number;
|
|
257
|
+
hiddenCount: number;
|
|
258
|
+
metric1: number;
|
|
259
|
+
metric2: number;
|
|
260
|
+
};
|
|
261
|
+
clicks: SiteAnalyticsClick[];
|
|
262
|
+
}
|
|
263
|
+
export declare const SITE_ANALYTICS_REPORTS: readonly ['overview', 'pages', 'clicks', 'sources', 'audience', 'quality', 'log', 'visitor'];
|
|
264
|
+
export type SiteAnalyticsReportName = typeof SITE_ANALYTICS_REPORTS[number];
|
|
265
|
+
export interface SiteAnalyticsMetrics {
|
|
266
|
+
views: number;
|
|
267
|
+
engaged: number;
|
|
268
|
+
visitors: number;
|
|
269
|
+
sessions: number;
|
|
270
|
+
bounces: number;
|
|
271
|
+
entries: number;
|
|
272
|
+
exits: number;
|
|
273
|
+
reads: number;
|
|
274
|
+
completions: number;
|
|
275
|
+
clicks: number;
|
|
276
|
+
medianDwellMs: number;
|
|
277
|
+
scrollDepth: number;
|
|
278
|
+
metric1: number;
|
|
279
|
+
metric2: number;
|
|
280
|
+
}
|
|
281
|
+
export interface SiteAnalyticsPageRow extends SiteAnalyticsMetrics {
|
|
282
|
+
day: string;
|
|
283
|
+
surface: string;
|
|
284
|
+
entity: string;
|
|
285
|
+
}
|
|
286
|
+
export interface SiteAnalyticsClickRow {
|
|
287
|
+
day: string;
|
|
288
|
+
surface: string;
|
|
289
|
+
entity: string;
|
|
290
|
+
name: string;
|
|
291
|
+
href: string;
|
|
292
|
+
clicks: number;
|
|
293
|
+
visitors: number;
|
|
294
|
+
medianTimeMs: number | null;
|
|
295
|
+
clickThrough: number;
|
|
296
|
+
}
|
|
297
|
+
export interface SiteAnalyticsDimensionRow {
|
|
298
|
+
day: string;
|
|
299
|
+
surface: string;
|
|
300
|
+
dim: string;
|
|
301
|
+
key: string;
|
|
302
|
+
views: number;
|
|
303
|
+
visitors: number;
|
|
304
|
+
engaged: number;
|
|
305
|
+
dwellMsSum: number;
|
|
306
|
+
}
|
|
307
|
+
export interface SiteAnalyticsTrafficRow {
|
|
308
|
+
day: string;
|
|
309
|
+
surface: string;
|
|
310
|
+
class: SiteAnalyticsTrafficClass;
|
|
311
|
+
reason: string;
|
|
312
|
+
views: number;
|
|
313
|
+
visitors: number;
|
|
314
|
+
}
|
|
315
|
+
export interface SiteAnalyticsViewRecord {
|
|
316
|
+
viewId: string;
|
|
317
|
+
visitorId: string;
|
|
318
|
+
sessionId: string;
|
|
319
|
+
startedAt: string;
|
|
320
|
+
updatedAt: string;
|
|
321
|
+
class: SiteAnalyticsTrafficClass;
|
|
322
|
+
reason: string;
|
|
323
|
+
weight: number;
|
|
324
|
+
page: SiteAnalyticsCollectInput['page'];
|
|
325
|
+
client: SiteAnalyticsCollectInput['client'];
|
|
326
|
+
progress: SiteAnalyticsCollectInput['progress'];
|
|
327
|
+
clicks: SiteAnalyticsClick[];
|
|
328
|
+
country: string;
|
|
329
|
+
region: string;
|
|
330
|
+
city: string;
|
|
331
|
+
ip: string;
|
|
332
|
+
ua: string;
|
|
333
|
+
browser: string;
|
|
334
|
+
os: string;
|
|
335
|
+
device: string;
|
|
336
|
+
platform: string;
|
|
337
|
+
network: string;
|
|
338
|
+
refSource: string;
|
|
339
|
+
refHost: string;
|
|
340
|
+
clickCount: number;
|
|
341
|
+
}
|
|
342
|
+
export interface SiteAnalyticsReportResult {
|
|
343
|
+
report: SiteAnalyticsReportName;
|
|
344
|
+
from: string;
|
|
345
|
+
to: string;
|
|
346
|
+
timezone: 'Australia/Melbourne';
|
|
347
|
+
sampled: boolean;
|
|
348
|
+
visitors: number | null;
|
|
349
|
+
visitorBasis: 'distinct' | 'sampled_distinct' | 'sum_monthly' | 'unavailable';
|
|
350
|
+
pages: SiteAnalyticsPageRow[];
|
|
351
|
+
clicks: SiteAnalyticsClickRow[];
|
|
352
|
+
dimensions: SiteAnalyticsDimensionRow[];
|
|
353
|
+
traffic: SiteAnalyticsTrafficRow[];
|
|
354
|
+
events: SiteAnalyticsViewRecord[];
|
|
355
|
+
nextCursor: string | null;
|
|
356
|
+
rum: Array<{
|
|
357
|
+
surface: string;
|
|
358
|
+
loads: number;
|
|
359
|
+
}> | null;
|
|
360
|
+
notices: string[];
|
|
361
|
+
}
|
package/dist/analytics.js
CHANGED
|
@@ -10,6 +10,31 @@ var BLOG_ANALYTICS_EVENTS_DEFAULT_LIMIT = 50;
|
|
|
10
10
|
var BLOG_ANALYTICS_READ_THRESHOLD_MS = 5000;
|
|
11
11
|
var BLOG_ANALYTICS_COMPLETION_SCROLL_DEPTH = 0.9;
|
|
12
12
|
var BLOG_ANALYTICS_RANGE_OPTIONS = [7, 30, 90];
|
|
13
|
+
var SITE_ANALYTICS_COLLECT_ENDPOINT = "/api/analytics/collect";
|
|
14
|
+
var SITE_ANALYTICS_REPORT_ENDPOINT = "/api/analytics/site";
|
|
15
|
+
var SITE_ANALYTICS_ENGAGED_DWELL_MS = 1e4;
|
|
16
|
+
var SITE_ANALYTICS_SESSION_IDLE_MS = 30 * 60000;
|
|
17
|
+
var SITE_ANALYTICS_SURFACES = [
|
|
18
|
+
"home",
|
|
19
|
+
"legacy",
|
|
20
|
+
"not_found",
|
|
21
|
+
"blog_index",
|
|
22
|
+
"blog_tags",
|
|
23
|
+
"blog_tag",
|
|
24
|
+
"blog_post",
|
|
25
|
+
"mood_feed",
|
|
26
|
+
"mood_post",
|
|
27
|
+
"mood_embed",
|
|
28
|
+
"projects",
|
|
29
|
+
"message",
|
|
30
|
+
"privacy",
|
|
31
|
+
"subscribe_manage",
|
|
32
|
+
"reader",
|
|
33
|
+
"docs",
|
|
34
|
+
"components",
|
|
35
|
+
"other"
|
|
36
|
+
];
|
|
37
|
+
var SITE_ANALYTICS_REPORTS = ["overview", "pages", "clicks", "sources", "audience", "quality", "log", "visitor"];
|
|
13
38
|
export {
|
|
14
39
|
BLOG_ANALYTICS_ARTICLE_ENDPOINT,
|
|
15
40
|
BLOG_ANALYTICS_COMPLETION_SCROLL_DEPTH,
|
|
@@ -21,5 +46,11 @@ export {
|
|
|
21
46
|
BLOG_ANALYTICS_SUMMARY_ENDPOINT,
|
|
22
47
|
LISTENING_ANALYTICS_EVENT_ENDPOINT,
|
|
23
48
|
NEWSLETTER_ANALYTICS_CLICK_ENDPOINT,
|
|
24
|
-
NEWSLETTER_ANALYTICS_OPEN_ENDPOINT
|
|
49
|
+
NEWSLETTER_ANALYTICS_OPEN_ENDPOINT,
|
|
50
|
+
SITE_ANALYTICS_COLLECT_ENDPOINT,
|
|
51
|
+
SITE_ANALYTICS_ENGAGED_DWELL_MS,
|
|
52
|
+
SITE_ANALYTICS_REPORTS,
|
|
53
|
+
SITE_ANALYTICS_REPORT_ENDPOINT,
|
|
54
|
+
SITE_ANALYTICS_SESSION_IDLE_MS,
|
|
55
|
+
SITE_ANALYTICS_SURFACES
|
|
25
56
|
};
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,31 @@ var BLOG_ANALYTICS_EVENTS_DEFAULT_LIMIT = 50;
|
|
|
10
10
|
var BLOG_ANALYTICS_READ_THRESHOLD_MS = 5000;
|
|
11
11
|
var BLOG_ANALYTICS_COMPLETION_SCROLL_DEPTH = 0.9;
|
|
12
12
|
var BLOG_ANALYTICS_RANGE_OPTIONS = [7, 30, 90];
|
|
13
|
+
var SITE_ANALYTICS_COLLECT_ENDPOINT = "/api/analytics/collect";
|
|
14
|
+
var SITE_ANALYTICS_REPORT_ENDPOINT = "/api/analytics/site";
|
|
15
|
+
var SITE_ANALYTICS_ENGAGED_DWELL_MS = 1e4;
|
|
16
|
+
var SITE_ANALYTICS_SESSION_IDLE_MS = 30 * 60000;
|
|
17
|
+
var SITE_ANALYTICS_SURFACES = [
|
|
18
|
+
"home",
|
|
19
|
+
"legacy",
|
|
20
|
+
"not_found",
|
|
21
|
+
"blog_index",
|
|
22
|
+
"blog_tags",
|
|
23
|
+
"blog_tag",
|
|
24
|
+
"blog_post",
|
|
25
|
+
"mood_feed",
|
|
26
|
+
"mood_post",
|
|
27
|
+
"mood_embed",
|
|
28
|
+
"projects",
|
|
29
|
+
"message",
|
|
30
|
+
"privacy",
|
|
31
|
+
"subscribe_manage",
|
|
32
|
+
"reader",
|
|
33
|
+
"docs",
|
|
34
|
+
"components",
|
|
35
|
+
"other"
|
|
36
|
+
];
|
|
37
|
+
var SITE_ANALYTICS_REPORTS = ["overview", "pages", "clicks", "sources", "audience", "quality", "log", "visitor"];
|
|
13
38
|
// src/admin.ts
|
|
14
39
|
var ADMIN_COMMENT_REJECT_REASONS = ["spam", "promotional", "abuse", "off_topic", "personal_info"];
|
|
15
40
|
var ADMIN_ACTIVITY_EVENTS = [
|
|
@@ -131,6 +156,7 @@ var MOOD_AI_MODELS = ["gpt-5.5", "gpt-5", "claude-sonnet-4.6"];
|
|
|
131
156
|
var MOOD_COMMENT_ORIGINS = ["telegram", "web"];
|
|
132
157
|
// src/notify.ts
|
|
133
158
|
var NOTIFY_CHANNELS = ["mood", "blog", "privacy", "announcement"];
|
|
159
|
+
var SUBSCRIPTION_SOURCES = ["desk", "blog", "mood"];
|
|
134
160
|
// src/routes.ts
|
|
135
161
|
var API_PREFIX = "/api";
|
|
136
162
|
var HEALTH_PATH = "/health";
|
|
@@ -319,6 +345,13 @@ export {
|
|
|
319
345
|
READER_RESEND_PATH,
|
|
320
346
|
READER_VERIFY_OUTCOMES,
|
|
321
347
|
READER_VERIFY_PATH,
|
|
348
|
+
SITE_ANALYTICS_COLLECT_ENDPOINT,
|
|
349
|
+
SITE_ANALYTICS_ENGAGED_DWELL_MS,
|
|
350
|
+
SITE_ANALYTICS_REPORTS,
|
|
351
|
+
SITE_ANALYTICS_REPORT_ENDPOINT,
|
|
352
|
+
SITE_ANALYTICS_SESSION_IDLE_MS,
|
|
353
|
+
SITE_ANALYTICS_SURFACES,
|
|
354
|
+
SUBSCRIPTION_SOURCES,
|
|
322
355
|
TELEGRAM_OPS_BASE_PATH,
|
|
323
356
|
TELEGRAM_OPS_BROADCASTS_PATH,
|
|
324
357
|
TELEGRAM_OPS_BROADCAST_CHANNELS,
|
package/dist/listening.d.ts
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
/** Site playback totals in a rolling seven-day window, not Apple Music history. */
|
|
2
|
+
export interface ListeningStats {
|
|
3
|
+
generatedAt: string;
|
|
4
|
+
window: {
|
|
5
|
+
from: string;
|
|
6
|
+
to: string;
|
|
7
|
+
};
|
|
8
|
+
totals: {
|
|
9
|
+
plays: number;
|
|
10
|
+
};
|
|
11
|
+
topArtist: {
|
|
12
|
+
name: string;
|
|
13
|
+
plays: number;
|
|
14
|
+
} | null;
|
|
15
|
+
}
|
|
1
16
|
export interface ListeningAccent {
|
|
2
17
|
hue: number;
|
|
3
18
|
chromaLight: number;
|
package/dist/notify.d.ts
CHANGED
|
@@ -4,6 +4,16 @@ export type DeliveryMode = 'immediate' | 'every_5h' | 'daily';
|
|
|
4
4
|
export type NotifyChannel = 'mood' | 'blog' | 'privacy' | 'announcement';
|
|
5
5
|
export type NotifyAuditEventType = 'subscribe_requested' | 'subscription_confirmed' | 'unsubscribed' | 'email_change_requested' | 'email_changed' | 'admin_create' | 'admin_update' | 'admin_delete' | 'admin_resend_confirm' | 'broadcast_sent';
|
|
6
6
|
export declare const NOTIFY_CHANNELS: readonly NotifyChannel[];
|
|
7
|
+
export declare const SUBSCRIPTION_SOURCES: readonly ['desk', 'blog', 'mood'];
|
|
8
|
+
export type SubscriptionSource = (typeof SUBSCRIPTION_SOURCES)[number];
|
|
9
|
+
/** Public counts of active, confirmed, deliverable email subscriptions. */
|
|
10
|
+
export interface SubscriberCounts {
|
|
11
|
+
generatedAt: string;
|
|
12
|
+
channels: {
|
|
13
|
+
blog: number;
|
|
14
|
+
mood: number;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
7
17
|
/** Optional risk evidence preserves compatibility with existing clients. */
|
|
8
18
|
export interface SubscribeRequest extends ClientEvidence {
|
|
9
19
|
email: string;
|
|
@@ -14,6 +24,8 @@ export interface SubscribeRequest extends ClientEvidence {
|
|
|
14
24
|
dailyHour?: number;
|
|
15
25
|
website?: string;
|
|
16
26
|
dwellToken?: string;
|
|
27
|
+
/** First subscription surface. Unknown values are ignored by the server. */
|
|
28
|
+
source?: SubscriptionSource;
|
|
17
29
|
}
|
|
18
30
|
export interface SubscriberRecord {
|
|
19
31
|
email: string;
|
|
@@ -32,6 +44,8 @@ export interface SubscriberRecord {
|
|
|
32
44
|
updatedAt: string;
|
|
33
45
|
confirmedAt?: string;
|
|
34
46
|
lastConfirmSentAt?: string;
|
|
47
|
+
/** First recorded subscription surface; absent for historical subscribers. */
|
|
48
|
+
source?: SubscriptionSource;
|
|
35
49
|
}
|
|
36
50
|
export interface RetryRecord {
|
|
37
51
|
postId: string;
|
package/dist/notify.js
CHANGED