tangled
alpha
login
or
join now
leaflet.pub
/
leaflet
289
fork
atom
a tool for shared writing and social publishing
289
fork
atom
overview
issues
27
pulls
pipelines
fix analytics pipeline
awarm.space
1 day ago
394a1113
93976e3d
+30
-15
2 changed files
expand all
collapse all
unified
split
app
api
rpc
[command]
get_publication_analytics.ts
lib
tinybird.ts
+14
-7
app/api/rpc/[command]/get_publication_analytics.ts
···
21
21
{ supabase }: Pick<Env, "supabase">,
22
22
) => {
23
23
const identity = await getIdentityData();
24
24
-
if (!identity?.atp_did || !identity.entitlements?.publication_analytics || !identity.entitlements?.pro_plan_visible) {
24
24
+
if (
25
25
+
!identity?.atp_did ||
26
26
+
!identity.entitlements?.publication_analytics ||
27
27
+
!identity.entitlements?.pro_plan_visible
28
28
+
) {
25
29
return { error: "unauthorized" as const };
26
30
}
27
31
···
32
36
.eq("uri", publication_uri)
33
37
.single();
34
38
35
35
-
if (!publication || publication.identity_did !== identity.atp_did) {
39
39
+
if (!publication) {
36
40
return { error: "not_found" as const };
37
41
}
38
42
39
39
-
const domain = publication.publication_domains?.[0]?.domain;
40
40
-
if (!domain) {
43
43
+
const domains = (publication.publication_domains ?? [])
44
44
+
.map((d) => d.domain)
45
45
+
.filter(Boolean)
46
46
+
.join(",");
47
47
+
if (!domains) {
41
48
return {
42
49
result: { traffic: [], topReferrers: [], topPages: [] },
43
50
};
···
45
52
46
53
const [trafficResult, referrersResult, pagesResult] = await Promise.all([
47
54
tinybird.publicationTraffic.query({
48
48
-
domain,
55
55
+
domains,
49
56
...(from ? { date_from: from } : {}),
50
57
...(to ? { date_to: to } : {}),
51
58
...(path ? { path } : {}),
52
59
}),
53
60
tinybird.publicationTopReferrers.query({
54
54
-
domain,
61
61
+
domains,
55
62
...(from ? { date_from: from } : {}),
56
63
...(to ? { date_to: to } : {}),
57
64
...(path ? { path } : {}),
58
65
limit: 10,
59
66
}),
60
67
tinybird.publicationTopPages.query({
61
61
-
domain,
68
68
+
domains,
62
69
...(from ? { date_from: from } : {}),
63
70
...(to ? { date_to: to } : {}),
64
71
limit: 20,
+16
-8
lib/tinybird.ts
···
19
19
type InferRow,
20
20
type InferParams,
21
21
type InferOutputRow,
22
22
+
TokenDefinition,
22
23
} from "@tinybirdco/sdk";
24
24
+
25
25
+
const PROD_READ_TOKEN = { name: "prod_read_token_v1", scopes: ["READ"] };
23
26
24
27
// ============================================================================
25
28
// Datasources
···
87
90
export const publicationTraffic = defineEndpoint("publication_traffic", {
88
91
description: "Daily pageview time series for a publication domain",
89
92
params: {
90
90
-
domain: p.string(),
93
93
+
domains: p.string(),
91
94
date_from: p.string().optional(),
92
95
date_to: p.string().optional(),
93
96
path: p.string().optional(),
94
97
},
98
98
+
tokens: [PROD_READ_TOKEN],
95
99
nodes: [
96
100
node({
97
101
name: "endpoint",
···
102
106
uniq(deviceId) AS visitors
103
107
FROM analytics_events
104
108
WHERE eventType = 'pageview'
105
105
-
AND domain(origin) = {{String(domain)}}
109
109
+
AND domain(origin) IN splitByChar(',', {{String(domains)}})
106
110
{% if defined(date_from) %}
107
111
AND fromUnixTimestamp64Milli(timestamp) >= parseDateTimeBestEffort({{String(date_from)}})
108
112
{% end %}
···
125
129
});
126
130
127
131
export type PublicationTrafficParams = InferParams<typeof publicationTraffic>;
128
128
-
export type PublicationTrafficOutput = InferOutputRow<typeof publicationTraffic>;
132
132
+
export type PublicationTrafficOutput = InferOutputRow<
133
133
+
typeof publicationTraffic
134
134
+
>;
129
135
130
136
/**
131
137
* publication_top_referrers – top referring domains for a publication.
···
133
139
export const publicationTopReferrers = defineEndpoint(
134
140
"publication_top_referrers",
135
141
{
142
142
+
tokens: [PROD_READ_TOKEN],
136
143
description: "Top referrers for a publication domain",
137
144
params: {
138
138
-
domain: p.string(),
145
145
+
domains: p.string(),
139
146
date_from: p.string().optional(),
140
147
date_to: p.string().optional(),
141
148
path: p.string().optional(),
···
150
157
count() AS pageviews
151
158
FROM analytics_events
152
159
WHERE eventType = 'pageview'
153
153
-
AND domain(origin) = {{String(domain)}}
160
160
+
AND domain(origin) IN splitByChar(',', {{String(domains)}})
154
161
AND referrer != ''
155
155
-
AND domain(referrer) != {{String(domain)}}
162
162
+
AND domain(referrer) NOT IN splitByChar(',', {{String(domains)}})
156
163
{% if defined(date_from) %}
157
164
AND fromUnixTimestamp64Milli(timestamp) >= parseDateTimeBestEffort({{String(date_from)}})
158
165
{% end %}
···
187
194
*/
188
195
export const publicationTopPages = defineEndpoint("publication_top_pages", {
189
196
description: "Top pages for a publication domain",
197
197
+
tokens: [PROD_READ_TOKEN],
190
198
params: {
191
191
-
domain: p.string(),
199
199
+
domains: p.string(),
192
200
date_from: p.string().optional(),
193
201
date_to: p.string().optional(),
194
202
limit: p.int32().optional(10),
···
202
210
count() AS pageviews
203
211
FROM analytics_events
204
212
WHERE eventType = 'pageview'
205
205
-
AND domain(origin) = {{String(domain)}}
213
213
+
AND domain(origin) IN splitByChar(',', {{String(domains)}})
206
214
{% if defined(date_from) %}
207
215
AND fromUnixTimestamp64Milli(timestamp) >= parseDateTimeBestEffort({{String(date_from)}})
208
216
{% end %}