@voltro/plugin-tinybird 0.85.0 → 0.87.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/CHANGELOG.md +5987 -0
- package/README.md +27 -0
- package/THIRD-PARTY-NOTICES.md +864 -253
- package/dist/index.js +14 -145
- package/dist/sink.js +137 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,157 +1,26 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
var n = "tinybird", r = (r) => e.mapError((e) => new t({
|
|
5
|
-
provider: n,
|
|
6
|
-
operation: r,
|
|
7
|
-
cause: e instanceof Error ? `${e.name}: ${e.message}` : String(e)
|
|
8
|
-
})), i = /^[A-Za-z_][A-Za-z0-9_]*$/, a = (e, r) => {
|
|
9
|
-
if (!i.test(e)) throw new t({
|
|
10
|
-
provider: n,
|
|
11
|
-
operation: "config",
|
|
12
|
-
cause: `invalid ${r} ${JSON.stringify(e)} — must match ${i.source} (letters, digits, underscore; no dots/slashes/quotes/spaces)`
|
|
13
|
-
});
|
|
14
|
-
return e;
|
|
15
|
-
}, o = /['\\]/, s = (e) => {
|
|
16
|
-
for (let t = 0; t < e.length; t++) if (e.charCodeAt(t) < 32) return !0;
|
|
17
|
-
return !1;
|
|
18
|
-
}, c = (e) => {
|
|
19
|
-
if (o.test(e) || s(e)) throw Error(`tinybird: invalid property key ${JSON.stringify(e)} — must not contain quotes, backslashes, or control characters`);
|
|
20
|
-
return e;
|
|
21
|
-
}, l = (e, t) => {
|
|
22
|
-
let n = [];
|
|
23
|
-
if (t != null && n.push(`tenant_id = '${t.replace(/'/g, "''")}'`), e) for (let [t, r] of Object.entries(e)) {
|
|
24
|
-
let e = String(r).replace(/'/g, "''");
|
|
25
|
-
n.push(`JSONExtractString(properties, '${c(t)}') = '${e}'`);
|
|
26
|
-
}
|
|
27
|
-
return n.length === 0 ? "" : ` AND ${n.join(" AND ")}`;
|
|
28
|
-
}, u = (e) => e === "count" ? "count()" : e === "unique" ? "uniqExact(subject_id)" : "sum" in e ? `sum(JSONExtractFloat(properties, '${c(e.sum)}'))` : `avg(JSONExtractFloat(properties, '${c(e.avg)}'))`, d = async (e, t, n) => {
|
|
29
|
-
let r = new URL(`${e.apiUrl}/v0/pipes/${t}.json`);
|
|
30
|
-
for (let [e, t] of Object.entries(n)) r.searchParams.set(e, String(t));
|
|
31
|
-
let i = await fetch(r.toString(), { headers: { authorization: `Bearer ${e.token}` } });
|
|
32
|
-
if (!i.ok) {
|
|
33
|
-
let e = await i.text().catch(() => "");
|
|
34
|
-
throw Error(`tinybird pipe ${t} returned HTTP ${i.status}: ${e}`);
|
|
35
|
-
}
|
|
36
|
-
return i.json();
|
|
37
|
-
}, f = (t) => ({
|
|
38
|
-
info: {
|
|
39
|
-
provider: n,
|
|
40
|
-
capabilities: {
|
|
41
|
-
track: !0,
|
|
42
|
-
aggregate: !0,
|
|
43
|
-
timeseries: !0,
|
|
44
|
-
topN: !0,
|
|
45
|
-
mirror: !1
|
|
46
|
-
},
|
|
47
|
-
detail: {
|
|
48
|
-
apiUrl: t.apiUrl,
|
|
49
|
-
datasource: t.datasource,
|
|
50
|
-
pipes: t.pipes
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
track: (n) => e.gen(function* () {
|
|
54
|
-
let r = `${t.apiUrl}/v0/events?name=${encodeURIComponent(t.datasource)}`, i = JSON.stringify({
|
|
55
|
-
name: n.name,
|
|
56
|
-
subject_id: n.subjectId ?? null,
|
|
57
|
-
tenant_id: n.tenantId ?? null,
|
|
58
|
-
properties: JSON.stringify(n.properties),
|
|
59
|
-
occurred_at: (n.occurredAt ?? /* @__PURE__ */ new Date()).toISOString()
|
|
60
|
-
}), a = yield* e.tryPromise({
|
|
61
|
-
try: () => fetch(r, {
|
|
62
|
-
method: "POST",
|
|
63
|
-
headers: {
|
|
64
|
-
authorization: `Bearer ${t.token}`,
|
|
65
|
-
"content-type": "application/json"
|
|
66
|
-
},
|
|
67
|
-
body: i
|
|
68
|
-
}),
|
|
69
|
-
catch: (e) => e
|
|
70
|
-
});
|
|
71
|
-
if (!a.ok) {
|
|
72
|
-
let t = yield* e.tryPromise({
|
|
73
|
-
try: () => a.text(),
|
|
74
|
-
catch: () => "no body"
|
|
75
|
-
});
|
|
76
|
-
return yield* e.fail(/* @__PURE__ */ Error(`tinybird events API returned HTTP ${a.status}: ${t}`));
|
|
77
|
-
}
|
|
78
|
-
}).pipe(r("track")),
|
|
79
|
-
aggregate: (n) => e.gen(function* () {
|
|
80
|
-
let { data: r } = yield* e.tryPromise({
|
|
81
|
-
try: () => d(t, t.pipes.aggregate, {
|
|
82
|
-
event: n.event,
|
|
83
|
-
from: n.range.from.toISOString(),
|
|
84
|
-
to: (n.range.to ?? /* @__PURE__ */ new Date()).toISOString(),
|
|
85
|
-
metric_expr: u(n.metric),
|
|
86
|
-
filter_sql: l(n.filter, n.tenantId)
|
|
87
|
-
}),
|
|
88
|
-
catch: (e) => e
|
|
89
|
-
}), i = r[0]?.value ?? 0;
|
|
90
|
-
return typeof i == "number" ? i : Number(i ?? 0);
|
|
91
|
-
}).pipe(r("aggregate")),
|
|
92
|
-
timeseries: (n) => e.gen(function* () {
|
|
93
|
-
let { data: r } = yield* e.tryPromise({
|
|
94
|
-
try: () => d(t, t.pipes.timeseries, {
|
|
95
|
-
event: n.event,
|
|
96
|
-
from: n.range.from.toISOString(),
|
|
97
|
-
to: (n.range.to ?? /* @__PURE__ */ new Date()).toISOString(),
|
|
98
|
-
metric_expr: u(n.metric),
|
|
99
|
-
filter_sql: l(n.filter, n.tenantId),
|
|
100
|
-
bucket_fn: p(n.bucket)
|
|
101
|
-
}),
|
|
102
|
-
catch: (e) => e
|
|
103
|
-
});
|
|
104
|
-
return r.map((e) => ({
|
|
105
|
-
bucketStart: new Date(e.bucket_start),
|
|
106
|
-
value: typeof e.value == "number" ? e.value : Number(e.value ?? 0)
|
|
107
|
-
}));
|
|
108
|
-
}).pipe(r("timeseries")),
|
|
109
|
-
topN: (n) => e.gen(function* () {
|
|
110
|
-
let { data: r } = yield* e.tryPromise({
|
|
111
|
-
try: () => d(t, t.pipes.topN, {
|
|
112
|
-
event: n.event,
|
|
113
|
-
from: n.range.from.toISOString(),
|
|
114
|
-
to: (n.range.to ?? /* @__PURE__ */ new Date()).toISOString(),
|
|
115
|
-
group_expr: `JSONExtractString(properties, '${c(n.groupBy)}')`,
|
|
116
|
-
metric_expr: n.metric === "count" ? "count()" : `sum(JSONExtractFloat(properties, '${c(n.metric.sum)}'))`,
|
|
117
|
-
filter_sql: l(n.filter, n.tenantId),
|
|
118
|
-
limit: Math.max(1, Math.floor(n.n))
|
|
119
|
-
}),
|
|
120
|
-
catch: (e) => e
|
|
121
|
-
});
|
|
122
|
-
return r.filter((e) => e.key !== null).map((e) => ({
|
|
123
|
-
key: e.key,
|
|
124
|
-
value: typeof e.value == "number" ? e.value : Number(e.value ?? 0)
|
|
125
|
-
}));
|
|
126
|
-
}).pipe(r("topN"))
|
|
127
|
-
}), p = (e) => {
|
|
128
|
-
switch (e) {
|
|
129
|
-
case "minute": return "toStartOfMinute";
|
|
130
|
-
case "hour": return "toStartOfHour";
|
|
131
|
-
case "day": return "toStartOfDay";
|
|
132
|
-
case "week": return "toStartOfWeek";
|
|
133
|
-
case "month": return "toStartOfMonth";
|
|
134
|
-
}
|
|
135
|
-
}, m = {
|
|
1
|
+
import { assertIdentifier as e, buildTinybirdSink as t } from "./sink.js";
|
|
2
|
+
//#region src/index.ts
|
|
3
|
+
var n = {
|
|
136
4
|
eu: "https://api.tinybird.co",
|
|
137
5
|
"us-east": "https://api.us-east.tinybird.co",
|
|
138
6
|
"us-west": "https://api.us-west.tinybird.co",
|
|
139
7
|
"asia-southeast": "https://api.tinybird.co"
|
|
140
|
-
},
|
|
141
|
-
let
|
|
142
|
-
token:
|
|
143
|
-
apiUrl:
|
|
144
|
-
datasource:
|
|
8
|
+
}, r = (r) => {
|
|
9
|
+
let i = r.apiUrl ?? n[r.region ?? "eu"] ?? "https://api.tinybird.co", a = {
|
|
10
|
+
token: r.token,
|
|
11
|
+
apiUrl: i,
|
|
12
|
+
datasource: e(r.datasource ?? "voltro_events", "datasource"),
|
|
145
13
|
pipes: {
|
|
146
|
-
aggregate:
|
|
147
|
-
timeseries:
|
|
148
|
-
topN:
|
|
14
|
+
aggregate: e(r.pipes?.aggregate ?? "events_aggregate", "aggregate pipe name"),
|
|
15
|
+
timeseries: e(r.pipes?.timeseries ?? "events_timeseries", "timeseries pipe name"),
|
|
16
|
+
topN: e(r.pipes?.topN ?? "events_topn", "topN pipe name")
|
|
149
17
|
}
|
|
150
18
|
};
|
|
151
19
|
return {
|
|
152
20
|
kind: "tinybird",
|
|
153
|
-
|
|
21
|
+
sql: "none",
|
|
22
|
+
build: () => t(a)
|
|
154
23
|
};
|
|
155
24
|
};
|
|
156
25
|
//#endregion
|
|
157
|
-
export {
|
|
26
|
+
export { r as tinybirdAnalytics };
|
package/dist/sink.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { Effect as e } from "effect";
|
|
2
|
+
import { AnalyticsError as t } from "@voltro/runtime";
|
|
3
|
+
//#region src/sink.ts
|
|
4
|
+
var n = "tinybird", r = (r) => e.mapError((e) => new t({
|
|
5
|
+
provider: n,
|
|
6
|
+
operation: r,
|
|
7
|
+
cause: e instanceof Error ? `${e.name}: ${e.message}` : String(e)
|
|
8
|
+
})), i = /^[A-Za-z_][A-Za-z0-9_]*$/, a = (e, r) => {
|
|
9
|
+
if (!i.test(e)) throw new t({
|
|
10
|
+
provider: n,
|
|
11
|
+
operation: "config",
|
|
12
|
+
cause: `invalid ${r} ${JSON.stringify(e)} — must match ${i.source} (letters, digits, underscore; no dots/slashes/quotes/spaces)`
|
|
13
|
+
});
|
|
14
|
+
return e;
|
|
15
|
+
}, o = /['\\]/, s = (e) => {
|
|
16
|
+
for (let t = 0; t < e.length; t++) if (e.charCodeAt(t) < 32) return !0;
|
|
17
|
+
return !1;
|
|
18
|
+
}, c = (e) => {
|
|
19
|
+
if (o.test(e) || s(e)) throw Error(`tinybird: invalid property key ${JSON.stringify(e)} — must not contain quotes, backslashes, or control characters`);
|
|
20
|
+
return e;
|
|
21
|
+
}, l = (e, t) => {
|
|
22
|
+
let n = [];
|
|
23
|
+
if (t != null && n.push(`tenant_id = '${t.replace(/'/g, "''")}'`), e) for (let [t, r] of Object.entries(e)) {
|
|
24
|
+
let e = String(r).replace(/'/g, "''");
|
|
25
|
+
n.push(`JSONExtractString(properties, '${c(t)}') = '${e}'`);
|
|
26
|
+
}
|
|
27
|
+
return n.length === 0 ? "" : ` AND ${n.join(" AND ")}`;
|
|
28
|
+
}, u = (e) => e === "count" ? "count()" : e === "unique" ? "uniqExact(subject_id)" : "sum" in e ? `sum(JSONExtractFloat(properties, '${c(e.sum)}'))` : `avg(JSONExtractFloat(properties, '${c(e.avg)}'))`, d = async (e, t, n) => {
|
|
29
|
+
let r = new URL(`${e.apiUrl}/v0/pipes/${t}.json`);
|
|
30
|
+
for (let [e, t] of Object.entries(n)) r.searchParams.set(e, String(t));
|
|
31
|
+
let i = await fetch(r.toString(), { headers: { authorization: `Bearer ${e.token}` } });
|
|
32
|
+
if (!i.ok) {
|
|
33
|
+
let e = await i.text().catch(() => "");
|
|
34
|
+
throw Error(`tinybird pipe ${t} returned HTTP ${i.status}: ${e}`);
|
|
35
|
+
}
|
|
36
|
+
return i.json();
|
|
37
|
+
}, f = (t) => ({
|
|
38
|
+
info: {
|
|
39
|
+
provider: n,
|
|
40
|
+
capabilities: {
|
|
41
|
+
track: !0,
|
|
42
|
+
aggregate: !0,
|
|
43
|
+
timeseries: !0,
|
|
44
|
+
topN: !0,
|
|
45
|
+
mirror: !1
|
|
46
|
+
},
|
|
47
|
+
detail: {
|
|
48
|
+
apiUrl: t.apiUrl,
|
|
49
|
+
datasource: t.datasource,
|
|
50
|
+
pipes: t.pipes
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
track: (n) => e.gen(function* () {
|
|
54
|
+
let r = `${t.apiUrl}/v0/events?name=${encodeURIComponent(t.datasource)}`, i = JSON.stringify({
|
|
55
|
+
name: n.name,
|
|
56
|
+
subject_id: n.subjectId ?? null,
|
|
57
|
+
tenant_id: n.tenantId ?? null,
|
|
58
|
+
properties: JSON.stringify(n.properties),
|
|
59
|
+
occurred_at: (n.occurredAt ?? /* @__PURE__ */ new Date()).toISOString()
|
|
60
|
+
}), a = yield* e.tryPromise({
|
|
61
|
+
try: () => fetch(r, {
|
|
62
|
+
method: "POST",
|
|
63
|
+
headers: {
|
|
64
|
+
authorization: `Bearer ${t.token}`,
|
|
65
|
+
"content-type": "application/json"
|
|
66
|
+
},
|
|
67
|
+
body: i
|
|
68
|
+
}),
|
|
69
|
+
catch: (e) => e
|
|
70
|
+
});
|
|
71
|
+
if (!a.ok) {
|
|
72
|
+
let t = yield* e.tryPromise({
|
|
73
|
+
try: () => a.text(),
|
|
74
|
+
catch: () => "no body"
|
|
75
|
+
});
|
|
76
|
+
return yield* e.fail(/* @__PURE__ */ Error(`tinybird events API returned HTTP ${a.status}: ${t}`));
|
|
77
|
+
}
|
|
78
|
+
}).pipe(r("track")),
|
|
79
|
+
aggregate: (n) => e.gen(function* () {
|
|
80
|
+
let { data: r } = yield* e.tryPromise({
|
|
81
|
+
try: () => d(t, t.pipes.aggregate, {
|
|
82
|
+
event: n.event,
|
|
83
|
+
from: n.range.from.toISOString(),
|
|
84
|
+
to: (n.range.to ?? /* @__PURE__ */ new Date()).toISOString(),
|
|
85
|
+
metric_expr: u(n.metric),
|
|
86
|
+
filter_sql: l(n.filter, n.tenantId)
|
|
87
|
+
}),
|
|
88
|
+
catch: (e) => e
|
|
89
|
+
}), i = r[0]?.value ?? 0;
|
|
90
|
+
return typeof i == "number" ? i : Number(i ?? 0);
|
|
91
|
+
}).pipe(r("aggregate")),
|
|
92
|
+
timeseries: (n) => e.gen(function* () {
|
|
93
|
+
let { data: r } = yield* e.tryPromise({
|
|
94
|
+
try: () => d(t, t.pipes.timeseries, {
|
|
95
|
+
event: n.event,
|
|
96
|
+
from: n.range.from.toISOString(),
|
|
97
|
+
to: (n.range.to ?? /* @__PURE__ */ new Date()).toISOString(),
|
|
98
|
+
metric_expr: u(n.metric),
|
|
99
|
+
filter_sql: l(n.filter, n.tenantId),
|
|
100
|
+
bucket_fn: p(n.bucket)
|
|
101
|
+
}),
|
|
102
|
+
catch: (e) => e
|
|
103
|
+
});
|
|
104
|
+
return r.map((e) => ({
|
|
105
|
+
bucketStart: new Date(e.bucket_start),
|
|
106
|
+
value: typeof e.value == "number" ? e.value : Number(e.value ?? 0)
|
|
107
|
+
}));
|
|
108
|
+
}).pipe(r("timeseries")),
|
|
109
|
+
topN: (n) => e.gen(function* () {
|
|
110
|
+
let { data: r } = yield* e.tryPromise({
|
|
111
|
+
try: () => d(t, t.pipes.topN, {
|
|
112
|
+
event: n.event,
|
|
113
|
+
from: n.range.from.toISOString(),
|
|
114
|
+
to: (n.range.to ?? /* @__PURE__ */ new Date()).toISOString(),
|
|
115
|
+
group_expr: `JSONExtractString(properties, '${c(n.groupBy)}')`,
|
|
116
|
+
metric_expr: n.metric === "count" ? "count()" : `sum(JSONExtractFloat(properties, '${c(n.metric.sum)}'))`,
|
|
117
|
+
filter_sql: l(n.filter, n.tenantId),
|
|
118
|
+
limit: Math.max(1, Math.floor(n.n))
|
|
119
|
+
}),
|
|
120
|
+
catch: (e) => e
|
|
121
|
+
});
|
|
122
|
+
return r.filter((e) => e.key !== null).map((e) => ({
|
|
123
|
+
key: e.key,
|
|
124
|
+
value: typeof e.value == "number" ? e.value : Number(e.value ?? 0)
|
|
125
|
+
}));
|
|
126
|
+
}).pipe(r("topN"))
|
|
127
|
+
}), p = (e) => {
|
|
128
|
+
switch (e) {
|
|
129
|
+
case "minute": return "toStartOfMinute";
|
|
130
|
+
case "hour": return "toStartOfHour";
|
|
131
|
+
case "day": return "toStartOfDay";
|
|
132
|
+
case "week": return "toStartOfWeek";
|
|
133
|
+
case "month": return "toStartOfMonth";
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
//#endregion
|
|
137
|
+
export { a as assertIdentifier, f as buildTinybirdSink };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voltro/plugin-tinybird",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.87.0",
|
|
4
4
|
"description": "Tinybird AnalyticsSink. Hosted ClickHouse with the Tinybird Events API + Pipes for low-friction OLAP. Pay-as-you-go alternative to running your own ClickHouse.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"voltro",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"node": ">=24.0.0"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@voltro/runtime": "0.
|
|
36
|
+
"@voltro/runtime": "0.87.0"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"effect": "4.0.1"
|