@voltro/plugin-clickhouse 0.84.0 → 0.85.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/index.js CHANGED
@@ -1,17 +1,17 @@
1
1
  import { createClient as e } from "@clickhouse/client";
2
- import { Effect as t, Option as n } from "effect";
3
- import { createLogger as r } from "@voltro/logger";
4
- import { AnalyticsError as i } from "@voltro/runtime";
2
+ import { Effect as t } from "effect";
3
+ import { createLogger as n } from "@voltro/logger";
4
+ import { AnalyticsError as r } from "@voltro/runtime";
5
5
  //#region src/sink.ts
6
- var a = r({ scope: "@voltro/plugin-clickhouse" }), o = "clickhouse", s = (e) => `voltro_mirror_${e}`, c = (e, t) => `
7
- CREATE TABLE IF NOT EXISTS ${e}.${s(t)} (
6
+ var i = n({ scope: "@voltro/plugin-clickhouse" }), a = "clickhouse", o = (e) => `voltro_mirror_${e}`, s = (e, t) => `
7
+ CREATE TABLE IF NOT EXISTS ${e}.${o(t)} (
8
8
  id String,
9
9
  data String CODEC(ZSTD(1)),
10
10
  version UInt64,
11
11
  is_deleted UInt8 DEFAULT 0
12
12
  ) ENGINE = ReplacingMergeTree(version)
13
13
  ORDER BY id
14
- `.trim(), l = (e, t) => `
14
+ `.trim(), c = (e, t) => `
15
15
  CREATE TABLE IF NOT EXISTS ${e}.${t} (
16
16
  id UUID DEFAULT generateUUIDv7(),
17
17
  name LowCardinality(String),
@@ -22,57 +22,57 @@ var a = r({ scope: "@voltro/plugin-clickhouse" }), o = "clickhouse", s = (e) =>
22
22
  ingested_at DateTime64(3) DEFAULT now64()
23
23
  ) ENGINE = MergeTree
24
24
  ORDER BY (name, occurred_at, id)
25
- `.trim(), u = (e) => (t) => t instanceof i ? new i({
26
- provider: o,
25
+ `.trim(), l = (e) => (t) => t instanceof r ? new r({
26
+ provider: a,
27
27
  operation: e,
28
28
  cause: t.cause
29
- }) : new i({
30
- provider: o,
29
+ }) : new r({
30
+ provider: a,
31
31
  operation: e,
32
32
  cause: t instanceof Error ? `${t.name}: ${t.message}` : String(t)
33
- }), d = (e) => (r) => r.pipe(t.catchSomeDefect((e) => e instanceof i ? n.some(t.fail(e)) : n.none()), t.mapError(u(e))), f = /^[A-Za-z_][A-Za-z0-9_]*$/, p = (e, t) => {
34
- if (!f.test(e)) throw new i({
35
- provider: o,
33
+ }), u = (e) => (n) => n.pipe(t.catchDefect((e) => e instanceof r ? t.fail(e) : t.die(e)), t.mapError(l(e))), d = /^[A-Za-z_][A-Za-z0-9_]*$/, f = (e, t) => {
34
+ if (!d.test(e)) throw new r({
35
+ provider: a,
36
36
  operation: "config",
37
- cause: `invalid ${t} ${JSON.stringify(e)} — must match ${f.source} (letters, digits, underscore; no dots/quotes/spaces)`
37
+ cause: `invalid ${t} ${JSON.stringify(e)} — must match ${d.source} (letters, digits, underscore; no dots/quotes/spaces)`
38
38
  });
39
39
  return e;
40
- }, m = /['\\]/, h = (e) => {
40
+ }, p = /['\\]/, m = (e) => {
41
41
  for (let t = 0; t < e.length; t++) if (e.charCodeAt(t) < 32) return !0;
42
42
  return !1;
43
- }, g = (e) => (t) => {
44
- if (m.test(t) || h(t)) throw new i({
45
- provider: o,
43
+ }, h = (e) => (t) => {
44
+ if (p.test(t) || m(t)) throw new r({
45
+ provider: a,
46
46
  operation: e,
47
47
  cause: `invalid property key ${JSON.stringify(t)} — must not contain quotes, backslashes, or control characters`
48
48
  });
49
49
  return t;
50
- }, _ = (e) => e.client === null ? t.fail(new i({
51
- provider: o,
50
+ }, g = (e) => e.client === null ? t.fail(new r({
51
+ provider: a,
52
52
  operation: "ensureClient",
53
53
  cause: "client not initialized — spec.initialize must run before queries"
54
- })) : t.succeed(e.client), v = (e) => t.gen(function* () {
54
+ })) : t.succeed(e.client), _ = (e) => t.gen(function* () {
55
55
  let n = e.client;
56
- e.client = null, n !== null && (yield* t.tryPromise(() => n.close()).pipe(t.catchAll((e) => t.logWarning("clickhouse analytics sink teardown failed", {
57
- provider: o,
56
+ e.client = null, n !== null && (yield* t.tryPromise(() => n.close()).pipe(t.catch((e) => t.logWarning("clickhouse analytics sink teardown failed", {
57
+ provider: a,
58
58
  err: e
59
59
  }))));
60
- }), y = (e) => ({
60
+ }), v = (e) => ({
61
61
  name: e.name,
62
62
  subject_id: e.subjectId ?? null,
63
63
  tenant_id: e.tenantId ?? null,
64
64
  properties: JSON.stringify(e.properties),
65
65
  occurred_at: (e.occurredAt ?? /* @__PURE__ */ new Date()).toISOString()
66
- }), b = (e, t) => {
67
- let n = [], r, i = () => {
66
+ }), y = (e, t) => {
67
+ let n = [], r, a = () => {
68
68
  r !== void 0 && (clearTimeout(r), r = void 0);
69
69
  }, o = async () => {
70
- if (i(), n.length === 0) return;
70
+ if (a(), n.length === 0) return;
71
71
  let t = n;
72
72
  n = [];
73
73
  let r = e.client;
74
74
  if (r === null) {
75
- a.warn("clickhouse batch flush skipped — client not initialized; events dropped", { dropped: t.length });
75
+ i.warn("clickhouse batch flush skipped — client not initialized; events dropped", { dropped: t.length });
76
76
  return;
77
77
  }
78
78
  try {
@@ -82,12 +82,12 @@ var a = r({ scope: "@voltro/plugin-clickhouse" }), o = "clickhouse", s = (e) =>
82
82
  format: "JSONEachRow"
83
83
  });
84
84
  } catch (e) {
85
- a.warn("clickhouse batch flush failed — dropped events", { dropped: t.length }, e);
85
+ i.warn("clickhouse batch flush failed — dropped events", { dropped: t.length }, e);
86
86
  }
87
87
  };
88
88
  return {
89
89
  add: (e) => {
90
- if (n.push(y(e)), n.length >= t.maxSize) {
90
+ if (n.push(v(e)), n.length >= t.maxSize) {
91
91
  o();
92
92
  return;
93
93
  }
@@ -97,7 +97,7 @@ var a = r({ scope: "@voltro/plugin-clickhouse" }), o = "clickhouse", s = (e) =>
97
97
  },
98
98
  flush: o
99
99
  };
100
- }, x = (e) => {
100
+ }, b = (e) => {
101
101
  switch (e) {
102
102
  case "minute": return "toStartOfMinute";
103
103
  case "hour": return "toStartOfHour";
@@ -105,7 +105,7 @@ var a = r({ scope: "@voltro/plugin-clickhouse" }), o = "clickhouse", s = (e) =>
105
105
  case "week": return "toStartOfWeek";
106
106
  case "month": return "toStartOfMonth";
107
107
  }
108
- }, S = (e, t) => `JSONExtractString(properties, '${g(e)(t)}')`, C = (e, t) => `JSONExtractFloat(properties, '${g(e)(t)}')`, w = (e, t) => t === "count" ? "count()" : t === "unique" ? "uniqExact(subject_id)" : "sum" in t ? `sum(${C(e, t.sum)})` : `avg(${C(e, t.avg)})`, T = (e, t) => t === "count" ? "count()" : `sum(${C(e, t.sum)})`, E = (e, t, n, r, i) => {
108
+ }, x = (e, t) => `JSONExtractString(properties, '${h(e)(t)}')`, S = (e, t) => `JSONExtractFloat(properties, '${h(e)(t)}')`, C = (e, t) => t === "count" ? "count()" : t === "unique" ? "uniqExact(subject_id)" : "sum" in t ? `sum(${S(e, t.sum)})` : `avg(${S(e, t.avg)})`, w = (e, t) => t === "count" ? "count()" : `sum(${S(e, t.sum)})`, T = (e, t, n, r, i) => {
109
109
  let a = {
110
110
  event: t,
111
111
  from: n.from.toISOString(),
@@ -115,20 +115,20 @@ var a = r({ scope: "@voltro/plugin-clickhouse" }), o = "clickhouse", s = (e) =>
115
115
  let t = 0;
116
116
  for (let [n, i] of Object.entries(r)) {
117
117
  let r = `f${t++}`;
118
- a[r] = String(i), o += ` AND ${S(e, n)} = {${r}:String}`;
118
+ a[r] = String(i), o += ` AND ${x(e, n)} = {${r}:String}`;
119
119
  }
120
120
  }
121
121
  return {
122
122
  sql: o,
123
123
  params: a
124
124
  };
125
- }, D = (e) => {
125
+ }, E = (e) => {
126
126
  let n = (n, r) => t.gen(function* () {
127
- p(n, "mirror table");
128
- let i = yield* _(e);
127
+ f(n, "mirror table");
128
+ let i = yield* g(e);
129
129
  yield* t.tryPromise({
130
130
  try: () => i.insert({
131
- table: `${e.database}.${s(n)}`,
131
+ table: `${e.database}.${o(n)}`,
132
132
  values: [r],
133
133
  format: "JSONEachRow"
134
134
  }),
@@ -146,7 +146,7 @@ var a = r({ scope: "@voltro/plugin-clickhouse" }), o = "clickhouse", s = (e) =>
146
146
  version: a,
147
147
  is_deleted: 0
148
148
  });
149
- }).pipe(d("mirror.upsert")),
149
+ }).pipe(u("mirror.upsert")),
150
150
  remove: ({ table: e, primaryKeyValue: r, version: i }) => t.gen(function* () {
151
151
  yield* n(e, {
152
152
  id: String(r),
@@ -154,27 +154,27 @@ var a = r({ scope: "@voltro/plugin-clickhouse" }), o = "clickhouse", s = (e) =>
154
154
  version: i,
155
155
  is_deleted: 1
156
156
  });
157
- }).pipe(d("mirror.remove")),
157
+ }).pipe(u("mirror.remove")),
158
158
  maxVersion: ({ table: n, primaryKeyValue: r }) => t.gen(function* () {
159
- p(String(n), "mirror table");
160
- let i = yield* _(e), a = `SELECT max(version) AS v, count() AS n FROM ${e.database}.${s(String(n))} WHERE id = {id: String} FORMAT JSON`, o = yield* t.tryPromise({
159
+ f(String(n), "mirror table");
160
+ let i = yield* g(e), a = `SELECT max(version) AS v, count() AS n FROM ${e.database}.${o(String(n))} WHERE id = {id: String} FORMAT JSON`, s = yield* t.tryPromise({
161
161
  try: () => i.query({
162
162
  query: a,
163
163
  query_params: { id: String(r) }
164
164
  }),
165
165
  catch: (e) => e
166
166
  }), { data: c } = yield* t.tryPromise({
167
- try: () => o.json(),
167
+ try: () => s.json(),
168
168
  catch: (e) => e
169
169
  }), l = c[0];
170
170
  return l === void 0 || Number(l.n) === 0 || l.v === null ? null : Number(l.v);
171
- }).pipe(d("mirror.maxVersion"))
171
+ }).pipe(u("mirror.maxVersion"))
172
172
  };
173
- }, O = (e) => {
174
- let n = e.mirrorTables.length > 0 ? D(e) : void 0;
173
+ }, D = (e) => {
174
+ let n = e.mirrorTables.length > 0 ? E(e) : void 0;
175
175
  return {
176
176
  info: {
177
- provider: o,
177
+ provider: a,
178
178
  capabilities: {
179
179
  track: !0,
180
180
  aggregate: !0,
@@ -190,18 +190,18 @@ var a = r({ scope: "@voltro/plugin-clickhouse" }), o = "clickhouse", s = (e) =>
190
190
  }
191
191
  },
192
192
  track: (n) => e.batcher ? t.sync(() => e.batcher.add(n)) : t.gen(function* () {
193
- let r = yield* _(e);
193
+ let r = yield* g(e);
194
194
  yield* t.tryPromise({
195
195
  try: () => r.insert({
196
196
  table: `${e.database}.${e.table}`,
197
- values: [y(n)],
197
+ values: [v(n)],
198
198
  format: "JSONEachRow"
199
199
  }),
200
200
  catch: (e) => e
201
201
  });
202
- }).pipe(d("track")),
202
+ }).pipe(u("track")),
203
203
  aggregate: (n) => t.gen(function* () {
204
- let r = yield* _(e), i = E("aggregate", n.event, n.range, n.filter, n.tenantId), a = `SELECT ${w("aggregate", n.metric)} AS value FROM ${e.database}.${e.table} WHERE ${i.sql} FORMAT JSON`, o = yield* t.tryPromise({
204
+ let r = yield* g(e), i = T("aggregate", n.event, n.range, n.filter, n.tenantId), a = `SELECT ${C("aggregate", n.metric)} AS value FROM ${e.database}.${e.table} WHERE ${i.sql} FORMAT JSON`, o = yield* t.tryPromise({
205
205
  try: () => r.query({
206
206
  query: a,
207
207
  query_params: i.params
@@ -212,10 +212,10 @@ var a = r({ scope: "@voltro/plugin-clickhouse" }), o = "clickhouse", s = (e) =>
212
212
  catch: (e) => e
213
213
  }), c = s[0]?.value ?? 0;
214
214
  return typeof c == "number" ? c : Number(c ?? 0);
215
- }).pipe(d("aggregate")),
215
+ }).pipe(u("aggregate")),
216
216
  timeseries: (n) => t.gen(function* () {
217
- let r = yield* _(e), i = E("timeseries", n.event, n.range, n.filter, n.tenantId), a = `
218
- SELECT ${`${x(n.bucket)}(occurred_at)`} AS bucket_start, ${w("timeseries", n.metric)} AS value
217
+ let r = yield* g(e), i = T("timeseries", n.event, n.range, n.filter, n.tenantId), a = `
218
+ SELECT ${`${b(n.bucket)}(occurred_at)`} AS bucket_start, ${C("timeseries", n.metric)} AS value
219
219
  FROM ${e.database}.${e.table}
220
220
  WHERE ${i.sql}
221
221
  GROUP BY bucket_start
@@ -235,10 +235,10 @@ var a = r({ scope: "@voltro/plugin-clickhouse" }), o = "clickhouse", s = (e) =>
235
235
  bucketStart: new Date(e.bucket_start),
236
236
  value: typeof e.value == "number" ? e.value : Number(e.value ?? 0)
237
237
  }));
238
- }).pipe(d("timeseries")),
238
+ }).pipe(u("timeseries")),
239
239
  topN: (n) => t.gen(function* () {
240
- let r = yield* _(e), i = E("topN", n.event, n.range, n.filter, n.tenantId), a = Math.max(1, Math.floor(n.n)), o = S("topN", n.groupBy), s = `
241
- SELECT ${o} AS key, ${T("topN", n.metric)} AS value
240
+ let r = yield* g(e), i = T("topN", n.event, n.range, n.filter, n.tenantId), a = Math.max(1, Math.floor(n.n)), o = x("topN", n.groupBy), s = `
241
+ SELECT ${o} AS key, ${w("topN", n.metric)} AS value
242
242
  FROM ${e.database}.${e.table}
243
243
  WHERE ${i.sql}
244
244
  GROUP BY ${o}
@@ -259,27 +259,27 @@ var a = r({ scope: "@voltro/plugin-clickhouse" }), o = "clickhouse", s = (e) =>
259
259
  key: e.key,
260
260
  value: typeof e.value == "number" ? e.value : Number(e.value ?? 0)
261
261
  }));
262
- }).pipe(d("topN")),
262
+ }).pipe(u("topN")),
263
263
  ...n === void 0 ? {} : { mirror: n }
264
264
  };
265
- }, k = 20, A = 5e3, j = (n) => {
266
- let r = (n.mirrorTables ?? []).map((e) => p(e, "mirror table")), i = {
265
+ }, O = 20, k = 5e3, A = (n) => {
266
+ let r = (n.mirrorTables ?? []).map((e) => f(e, "mirror table")), i = {
267
267
  client: null,
268
- database: p(n.database ?? "default", "database"),
269
- table: p(n.table ?? "events", "table"),
268
+ database: f(n.database ?? "default", "database"),
269
+ table: f(n.table ?? "events", "table"),
270
270
  mirrorTables: r,
271
271
  mirrorPrimaryKey: n.mirrorPrimaryKey ?? "id"
272
272
  };
273
273
  if (n.batch !== !1) {
274
274
  let e = n.batch ?? {};
275
- i.batcher = b(i, {
276
- maxSize: e.maxSize ?? k,
277
- flushIntervalMs: e.flushIntervalMs ?? A
275
+ i.batcher = y(i, {
276
+ maxSize: e.maxSize ?? O,
277
+ flushIntervalMs: e.flushIntervalMs ?? k
278
278
  });
279
279
  }
280
280
  return {
281
281
  kind: "clickhouse",
282
- build: (e) => O(i),
282
+ build: (e) => D(i),
283
283
  initialize: () => t.gen(function* () {
284
284
  let r = yield* t.promise(() => Promise.resolve(e({
285
285
  url: n.url,
@@ -287,14 +287,14 @@ var a = r({ scope: "@voltro/plugin-clickhouse" }), o = "clickhouse", s = (e) =>
287
287
  ...n.username === void 0 ? {} : { username: n.username },
288
288
  ...n.password === void 0 ? {} : { password: n.password }
289
289
  })));
290
- yield* t.promise(() => r.ping()), yield* t.promise(() => r.command({ query: l(i.database, i.table) }));
291
- for (let e of i.mirrorTables) yield* t.promise(() => r.command({ query: c(i.database, e) }));
290
+ yield* t.promise(() => r.ping()), yield* t.promise(() => r.command({ query: c(i.database, i.table) }));
291
+ for (let e of i.mirrorTables) yield* t.promise(() => r.command({ query: s(i.database, e) }));
292
292
  i.client = r;
293
293
  }),
294
294
  dispose: () => t.gen(function* () {
295
- i.batcher && (yield* t.promise(() => i.batcher.flush())), yield* v(i);
295
+ i.batcher && (yield* t.promise(() => i.batcher.flush())), yield* _(i);
296
296
  })
297
297
  };
298
298
  };
299
299
  //#endregion
300
- export { l as EVENTS_TABLE_DDL, c as MIRROR_TABLE_DDL, j as clickhouseAnalytics };
300
+ export { c as EVENTS_TABLE_DDL, s as MIRROR_TABLE_DDL, A as clickhouseAnalytics };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voltro/plugin-clickhouse",
3
- "version": "0.84.0",
3
+ "version": "0.85.0",
4
4
  "description": "ClickHouse AnalyticsSink. Native HTTP ingest into a ClickHouse cluster — self-hosted OR ClickHouse Cloud. Production-grade OLAP for high-cardinality events with millisecond aggregate queries over billions of rows.",
5
5
  "keywords": [
6
6
  "voltro",
@@ -34,11 +34,11 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@clickhouse/client": "^1.23.1",
37
- "@voltro/logger": "0.84.0",
38
- "@voltro/runtime": "0.84.0"
37
+ "@voltro/logger": "0.85.0",
38
+ "@voltro/runtime": "0.85.0"
39
39
  },
40
40
  "peerDependencies": {
41
- "effect": "^3.22.2"
41
+ "effect": "4.0.1"
42
42
  },
43
43
  "publishConfig": {
44
44
  "access": "public"