@adriangalilea/utils 4.1.1 → 6.0.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/README.md CHANGED
@@ -7,21 +7,46 @@ TypeScript utilities - logger, currency, offensive programming, file operations,
7
7
  ```ts
8
8
  import { createClient } from "@libsql/client"
9
9
  import { defineMetrics } from "@adriangalilea/utils/metrics"
10
- import { sqliteMetricsWriter } from "@adriangalilea/utils/metrics/sqlite"
10
+ import { libsqlDriver } from "@adriangalilea/utils/metrics/libsql"
11
+ import { metricsStore } from "@adriangalilea/utils/metrics/sqlite"
11
12
 
12
- const db = createClient({ url: process.env.METRICS_DATABASE_URL!, authToken: process.env.METRICS_AUTH_TOKEN })
13
+ const driver = libsqlDriver(createClient({ url: process.env.METRICS_DATABASE_URL!, authToken: process.env.METRICS_AUTH_TOKEN }))
13
14
  const metrics = defineMetrics({
14
15
  installCopy: { kind: "counter", label: "install command copies", dimensions: { component: ["chat", "glass"] } },
15
- }, { write: sqliteMetricsWriter(db, "my-project") })
16
+ }, { store: metricsStore(driver, "my-project") })
16
17
 
17
18
  await metrics.installCopy.bump({ dimensions: { component: "chat" } })
18
19
  ```
19
20
 
20
- Provision the exported `METRICS_SCHEMA` once before collecting. `describe()` returns
21
- the declarations; the SQL writer stores labels beside daily counters so reports
22
- discover metrics without another hardcoded list. `readMetrics(db, { from, to,
23
- project? })` returns daily rows with labels and dimensions, using inclusive UTC dates.
24
- Readers propagate database errors rather than presenting missing data as zero.
21
+ One SQLite dialect, many stores. `metrics/sqlite` holds the schema, the store and
22
+ the readers over a `MetricsDriver`: two verbs, `query(statement)` for rows and
23
+ `transact(statements)` for an all-or-nothing write batch. `metrics/libsql` wraps a
24
+ Turso / libSQL client, `metrics/d1` wraps a Cloudflare D1 binding (`d1Driver(env.DB)`),
25
+ each with the driver's native calls and structural types, so no database client is
26
+ bundled. Any other SQLite driver implements the two verbs in a few lines (the test
27
+ does it over `node:sqlite`). Readers need only `query`, a `MetricsReader`:
28
+ `metrics/d1-rest` reads a D1 database over Cloudflare's REST API from a process with
29
+ no binding (`d1RestReader({ accountId, databaseId, token })`). A store that does not
30
+ speak SQLite implements the `MetricsStore` contract, `declare(schema)` and
31
+ `write(measurement)`, and its own readers returning the `metrics/report` types.
32
+
33
+ **The store describes itself.** `declare` runs once per process before the first
34
+ sample and carries the whole schema: kinds, labels, help, units, per-user flags and
35
+ overlaps. Every later sample is one small transaction. A reader therefore never needs
36
+ the declaring code: `readSchema(reader, project)` returns what a project declared,
37
+ and `readReport(reader, { project, days, includeToday? })` returns everything a panel
38
+ renders in one call, `{ project, window, schema, daily, audience }`. A changed kind or
39
+ unit is refused at declaration and every sample of that process fails loudly; a store
40
+ that was briefly away is asked again by the next sample.
41
+
42
+ Provision the exported `METRICS_SCHEMA` once before collecting. `readMetrics(reader,
43
+ { from, to, project? })` returns daily rows with labels and dimensions, using inclusive
44
+ UTC dates. `readAudience(reader, { from, to, project }, schema)` answers who did it
45
+ from the opt-in per-user rows: one row per declared per-user metric (zeros when nobody
46
+ touched it), with distinct actors, actors with more than one sample on a single day,
47
+ actors seen on more than one day, then each declared overlap as `fromUsers` and
48
+ `bothUsers`. Readers propagate database errors rather than presenting missing data
49
+ as zero.
25
50
  `summarizeMetrics(rows)` from `metrics/report` produces one generic report shape;
26
51
  `renderMetrics(rows, { daily? })` from `metrics/cli` renders it with the existing
27
52
  ANSI-aware `cli.table` helpers. Both discover every recorded metric from its
@@ -37,10 +62,7 @@ disappearing series, count changes and weighted timing-average changes. Percent
37
62
  change is null without a nonzero baseline; missing timing samples stay null.
38
63
  Changing a metric's kind or unit across the inputs is rejected. Missing observations
39
64
  are not proof that collection was running: deltas compare recorded data only.
40
- The SQL writer rejects changes to an existing key's kind or unit atomically, before
41
- adding observations. Use a new key for a new meaning; labels and help can be edited.
42
- The SQL adapter accepts a libSQL-compatible client; D1 or another store can implement
43
- the injected `write(measurement)` contract instead. No database client is bundled.
65
+ Use a new key for a new meaning; labels, help and the per-user flag can be edited.
44
66
 
45
67
  Measurements validate finite nonnegative samples, positive integer counts, and
46
68
  declared dimension values. Calls resolve even when validation or storage fails;
@@ -55,16 +77,16 @@ Enable it only with a deletion and retention policy; no identity is inferred.
55
77
  `overlaps: [["a", "b"]]` declares unordered audience overlap, not an ordered funnel.
56
78
  Daily totals support counts and averages, not percentile latency or event ordering.
57
79
 
58
- **4.0 migration:** import `DailyMetric` from `metrics/report`, not `metrics/sqlite`.
59
- Report types and renderers are store-independent; SQLite is one optional adapter.
60
- This removes the old type export rather than retaining a compatibility alias.
61
-
62
- **3.0 migration:** `bot/metrics` and its bot-barrel export are removed. Import
63
- `@adriangalilea/utils/metrics`; replace `write(key, count, sum, user)` with
64
- `write({ key, count, sum, user, day, dimensions, spec })`. Rename `funnels` to
65
- `overlaps` in declarations and schema consumers. Existing stores can adapt the new
66
- write object without moving historical data. Metric keys and dimensions are storage
67
- identifiers: introduce a new key when changing meaning rather than relabelling history.
80
+ **6.0 migration:** `defineMetrics` takes `store: metricsStore(driver, project)` instead
81
+ of `write: metricsWriter(...)`; a custom store implements `declare` and `write`, and
82
+ `Measurement` no longer carries `spec`. Existing tables gain a column and a table:
83
+ `ALTER TABLE metric_definition ADD COLUMN per_user INTEGER NOT NULL DEFAULT 0` and the
84
+ `metric_overlap` table from `METRICS_SCHEMA`; the first sample after the deploy
85
+ declares the real flags, labels and overlaps. `readAudience` takes the schema
86
+ (`readSchema(reader, project)`) instead of an overlap list and returns a row per
87
+ declared per-user key. `readReport` replaces hand-rolled window + rows + audience
88
+ composition. Metric keys and dimensions are storage identifiers: introduce a new key
89
+ when changing meaning rather than relabelling history.
68
90
 
69
91
  ## Installation
70
92
 
@@ -0,0 +1,15 @@
1
+ import type { MetricsReader } from "./sqlite.js";
2
+ export interface D1RestOptions {
3
+ accountId: string;
4
+ databaseId: string;
5
+ /** A Cloudflare API token with D1 read on the database. */
6
+ token: string;
7
+ fetch?: typeof fetch;
8
+ }
9
+ /**
10
+ * A D1 database read over Cloudflare's REST API, for a process that has no binding
11
+ * (a Next server, a CLI). A reader only: one REST call cannot transact, so writes stay
12
+ * with `metrics/d1` inside the Worker that owns the binding.
13
+ */
14
+ export declare function d1RestReader(options: D1RestOptions): MetricsReader;
15
+ //# sourceMappingURL=d1-rest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"d1-rest.d.ts","sourceRoot":"","sources":["../../src/metrics/d1-rest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,WAAW,aAAa;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,2DAA2D;IAC3D,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,aAAa,GAAG,aAAa,CAyBlE"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * A D1 database read over Cloudflare's REST API, for a process that has no binding
3
+ * (a Next server, a CLI). A reader only: one REST call cannot transact, so writes stay
4
+ * with `metrics/d1` inside the Worker that owns the binding.
5
+ */
6
+ export function d1RestReader(options) {
7
+ const url = `https://api.cloudflare.com/client/v4/accounts/${options.accountId}/d1/database/${options.databaseId}/query`;
8
+ const call = options.fetch ?? fetch;
9
+ return {
10
+ async query({ sql, args }) {
11
+ const response = await call(url, {
12
+ method: "POST",
13
+ headers: {
14
+ authorization: `Bearer ${options.token}`,
15
+ "content-type": "application/json",
16
+ },
17
+ body: JSON.stringify({ sql, params: args }),
18
+ });
19
+ const data = (await response.json());
20
+ if (!response.ok || !data.success)
21
+ throw new Error(`metrics: d1 ${data.errors?.[0]?.message ?? response.status}`);
22
+ return data.result?.[0]?.results ?? [];
23
+ },
24
+ };
25
+ }
26
+ //# sourceMappingURL=d1-rest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"d1-rest.js","sourceRoot":"","sources":["../../src/metrics/d1-rest.ts"],"names":[],"mappings":"AAUA;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,OAAsB;IAClD,MAAM,GAAG,GAAG,iDAAiD,OAAO,CAAC,SAAS,gBAAgB,OAAO,CAAC,UAAU,QAAQ,CAAC;IACzH,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC;IACpC,OAAO;QACN,KAAK,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE;YACxB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,GAAG,EAAE;gBAChC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACR,aAAa,EAAE,UAAU,OAAO,CAAC,KAAK,EAAE;oBACxC,cAAc,EAAE,kBAAkB;iBAClC;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;aAC3C,CAAC,CAAC;YACH,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAIlC,CAAC;YACF,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO;gBAChC,MAAM,IAAI,KAAK,CACd,eAAe,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,QAAQ,CAAC,MAAM,EAAE,CAC7D,CAAC;YACH,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,EAAE,CAAC;QACxC,CAAC;KACD,CAAC;AACH,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { MetricsDriver } from "./sqlite.js";
2
+ /** The slice of Cloudflare D1 the metrics driver touches, typed structurally: no workers-types dependency. */
3
+ export interface D1Statement {
4
+ bind(...values: unknown[]): D1Statement;
5
+ all<T = Record<string, unknown>>(): Promise<{
6
+ results: T[];
7
+ }>;
8
+ }
9
+ export interface D1Binding {
10
+ prepare(sql: string): D1Statement;
11
+ /** D1 runs a batch as one transaction: a failing statement rolls back the whole sequence. */
12
+ batch(statements: D1Statement[]): Promise<unknown>;
13
+ }
14
+ /** A D1 binding as a metrics driver. */
15
+ export declare function d1Driver(db: D1Binding): MetricsDriver;
16
+ //# sourceMappingURL=d1.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"d1.d.ts","sourceRoot":"","sources":["../../src/metrics/d1.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,8GAA8G;AAC9G,MAAM,WAAW,WAAW;IAC3B,IAAI,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,WAAW,CAAC;IACxC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;QAAE,OAAO,EAAE,CAAC,EAAE,CAAA;KAAE,CAAC,CAAC;CAC9D;AACD,MAAM,WAAW,SAAS;IACzB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAAC;IAClC,6FAA6F;IAC7F,KAAK,CAAC,UAAU,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACnD;AAED,wCAAwC;AACxC,wBAAgB,QAAQ,CAAC,EAAE,EAAE,SAAS,GAAG,aAAa,CAYrD"}
@@ -0,0 +1,11 @@
1
+ /** A D1 binding as a metrics driver. */
2
+ export function d1Driver(db) {
3
+ return {
4
+ query: async ({ sql, args }) => (await db
5
+ .prepare(sql)
6
+ .bind(...args)
7
+ .all()).results,
8
+ transact: (statements) => db.batch(statements.map((s) => db.prepare(s.sql).bind(...s.args))),
9
+ };
10
+ }
11
+ //# sourceMappingURL=d1.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"d1.js","sourceRoot":"","sources":["../../src/metrics/d1.ts"],"names":[],"mappings":"AAaA,wCAAwC;AACxC,MAAM,UAAU,QAAQ,CAAC,EAAa;IACrC,OAAO;QACN,KAAK,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,CAC9B,CACC,MAAM,EAAE;aACN,OAAO,CAAC,GAAG,CAAC;aACZ,IAAI,CAAC,GAAG,IAAI,CAAC;aACb,GAAG,EAAE,CACP,CAAC,OAAO;QACV,QAAQ,EAAE,CAAC,UAAU,EAAE,EAAE,CACxB,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;KACnE,CAAC;AACH,CAAC"}
@@ -14,10 +14,27 @@ export interface Measurement {
14
14
  sum: number;
15
15
  user?: string | number;
16
16
  dimensions: Record<string, string>;
17
- spec: MetricSpec;
17
+ }
18
+ export interface MetricsSchema {
19
+ metrics: Array<{
20
+ key: string;
21
+ } & MetricSpec>;
22
+ overlaps: Array<{
23
+ from: string;
24
+ to: string;
25
+ }>;
26
+ }
27
+ /**
28
+ * Where measurements go. `declare` runs once per process before the first write and
29
+ * carries the whole schema (kinds, labels, per-user flags, overlaps), so a store is
30
+ * self-describing and a reader never needs the declaring code. `write` carries one sample.
31
+ */
32
+ export interface MetricsStore {
33
+ declare(schema: MetricsSchema): Promise<unknown>;
34
+ write(measurement: Measurement): Promise<unknown>;
18
35
  }
19
36
  export interface MetricsOptions<Keys extends string = string> {
20
- write: (measurement: Measurement) => Promise<unknown>;
37
+ store: MetricsStore;
21
38
  /** Unordered user overlap, not an ordered conversion funnel. */
22
39
  overlaps?: ReadonlyArray<readonly [Keys, Keys]>;
23
40
  /** Failures are visible by default, but never reject a measurement call. */
@@ -36,15 +53,6 @@ export interface CounterHandle {
36
53
  export interface TimingHandle {
37
54
  record(value: number, options?: SampleOptions): Promise<void>;
38
55
  }
39
- export interface MetricsSchema {
40
- metrics: Array<{
41
- key: string;
42
- } & MetricSpec>;
43
- overlaps: Array<{
44
- from: string;
45
- to: string;
46
- }>;
47
- }
48
56
  export type Metrics<Spec extends Record<string, MetricSpec>> = {
49
57
  [K in keyof Spec]: Spec[K]["kind"] extends "counter" ? CounterHandle : TimingHandle;
50
58
  } & {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/metrics/index.ts"],"names":[],"mappings":"AAAA,qGAAqG;AACrG,MAAM,MAAM,UAAU,GAAG;IACxB,IAAI,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;CAC/C,CAAC;AAEF,MAAM,WAAW,WAAW;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,IAAI,EAAE,UAAU,CAAC;CACjB;AAED,MAAM,WAAW,cAAc,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM;IAC3D,KAAK,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACtD,gEAAgE;IAChE,QAAQ,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IAChD,4EAA4E;IAC5E,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC7B,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC;AACD,MAAM,WAAW,aAAa;IAC7B,IAAI,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG;QAAE,CAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9D;AACD,MAAM,WAAW,YAAY;IAC5B,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9D;AACD,MAAM,WAAW,aAAa;IAC7B,OAAO,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,UAAU,CAAC,CAAC;IAC7C,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9C;AACD,MAAM,MAAM,OAAO,CAAC,IAAI,SAAS,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,IAAI;KAC7D,CAAC,IAAI,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,SAAS,GACjD,aAAa,GACb,YAAY;CACf,GAAG;IAAE,QAAQ,IAAI,aAAa,CAAA;CAAE,CAAC;AAIlC,wBAAgB,aAAa,CAAC,KAAK,CAAC,IAAI,SAAS,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,EAC1E,KAAK,EAAE,IAAI,EACX,IAAI,EAAE,cAAc,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,MAAM,CAAC,CAAC,GAC/C,OAAO,CAAC,IAAI,CAAC,CAqGf"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/metrics/index.ts"],"names":[],"mappings":"AAAA,qGAAqG;AACrG,MAAM,MAAM,UAAU,GAAG;IACxB,IAAI,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;CAC/C,CAAC;AAEF,MAAM,WAAW,WAAW;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,aAAa;IAC7B,OAAO,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,UAAU,CAAC,CAAC;IAC7C,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9C;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC5B,OAAO,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACjD,KAAK,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAClD;AAED,MAAM,WAAW,cAAc,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM;IAC3D,KAAK,EAAE,YAAY,CAAC;IACpB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IAChD,4EAA4E;IAC5E,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC7B,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC;AACD,MAAM,WAAW,aAAa;IAC7B,IAAI,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG;QAAE,CAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9D;AACD,MAAM,WAAW,YAAY;IAC5B,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9D;AACD,MAAM,MAAM,OAAO,CAAC,IAAI,SAAS,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,IAAI;KAC7D,CAAC,IAAI,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,SAAS,GACjD,aAAa,GACb,YAAY;CACf,GAAG;IAAE,QAAQ,IAAI,aAAa,CAAA;CAAE,CAAC;AAIlC,wBAAgB,aAAa,CAAC,KAAK,CAAC,IAAI,SAAS,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,EAC1E,KAAK,EAAE,IAAI,EACX,IAAI,EAAE,cAAc,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,MAAM,CAAC,CAAC,GAC/C,OAAO,CAAC,IAAI,CAAC,CA8Gf"}
@@ -23,8 +23,23 @@ export function defineMetrics(input, opts) {
23
23
  throw new Error("metrics: overlap requires two declared perUser metrics");
24
24
  return { from, to };
25
25
  });
26
+ const describe = () => structuredClone({
27
+ metrics: Object.entries(spec).map(([key, s]) => ({ key, ...s })),
28
+ overlaps,
29
+ });
26
30
  const report = opts.onError ??
27
31
  ((_error, key) => console.warn(`metrics: measurement failed (${key})`));
32
+ // The schema reaches the store once per process, ahead of the first sample. A failed
33
+ // declaration is retried by the next sample, so a store that was briefly away recovers
34
+ // and a store that refuses the schema (a changed kind) fails every sample, loudly.
35
+ let declared;
36
+ const declare = () => {
37
+ declared ??= opts.store.declare(describe()).catch((error) => {
38
+ declared = undefined;
39
+ throw error;
40
+ });
41
+ return declared;
42
+ };
28
43
  async function write(key, count, sum, options) {
29
44
  try {
30
45
  if (!Number.isSafeInteger(count) ||
@@ -49,14 +64,14 @@ export function defineMetrics(input, opts) {
49
64
  ? !Number.isSafeInteger(user)
50
65
  : typeof user !== "string" || !user.length || user.length > 128))
51
66
  throw new Error("metrics: invalid user identifier");
52
- await opts.write({
67
+ await declare();
68
+ await opts.store.write({
53
69
  key,
54
70
  day: (opts.now?.() ?? new Date()).toISOString().slice(0, 10),
55
71
  count,
56
72
  sum,
57
73
  user,
58
74
  dimensions,
59
- spec: structuredClone(s),
60
75
  });
61
76
  }
62
77
  catch (error) {
@@ -75,12 +90,6 @@ export function defineMetrics(input, opts) {
75
90
  ? { bump: (o) => write(key, o?.n ?? 1, 0, o) }
76
91
  : { record: (value, o) => write(key, 1, value, o) };
77
92
  }
78
- return {
79
- ...out,
80
- describe: () => structuredClone({
81
- metrics: Object.entries(spec).map(([key, s]) => ({ key, ...s })),
82
- overlaps,
83
- }),
84
- };
93
+ return { ...out, describe };
85
94
  }
86
95
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/metrics/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/metrics/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { MetricsDriver, SqlStatement } from "./sqlite.js";
2
+ /** The slice of `@libsql/client` the metrics driver touches, typed structurally: no client is bundled. */
3
+ export interface LibsqlClient {
4
+ execute(statement: SqlStatement): Promise<{
5
+ rows: Iterable<Record<string, unknown>>;
6
+ }>;
7
+ batch(statements: SqlStatement[], mode: "write"): Promise<unknown>;
8
+ }
9
+ /** A Turso / libSQL / sqld connection as a metrics driver; `batch` in write mode is one transaction. */
10
+ export declare function libsqlDriver(client: LibsqlClient): MetricsDriver;
11
+ //# sourceMappingURL=libsql.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"libsql.d.ts","sourceRoot":"","sources":["../../src/metrics/libsql.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE/D,0GAA0G;AAC1G,MAAM,WAAW,YAAY;IAC5B,OAAO,CAAC,SAAS,EAAE,YAAY,GAAG,OAAO,CAAC;QACzC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;KACxC,CAAC,CAAC;IACH,KAAK,CAAC,UAAU,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACnE;AAED,wGAAwG;AACxG,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,aAAa,CAKhE"}
@@ -0,0 +1,8 @@
1
+ /** A Turso / libSQL / sqld connection as a metrics driver; `batch` in write mode is one transaction. */
2
+ export function libsqlDriver(client) {
3
+ return {
4
+ query: async (statement) => (await client.execute(statement)).rows,
5
+ transact: (statements) => client.batch(statements, "write"),
6
+ };
7
+ }
8
+ //# sourceMappingURL=libsql.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"libsql.js","sourceRoot":"","sources":["../../src/metrics/libsql.ts"],"names":[],"mappings":"AAUA,wGAAwG;AACxG,MAAM,UAAU,YAAY,CAAC,MAAoB;IAChD,OAAO;QACN,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI;QAClE,QAAQ,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,OAAO,CAAC;KAC3D,CAAC;AACH,CAAC"}
@@ -1,3 +1,4 @@
1
+ import type { MetricsSchema } from "./index.js";
1
2
  /** Store-independent daily observations, shared by adapters and renderers. */
2
3
  export interface DailyMetric {
3
4
  project: string;
@@ -11,6 +12,43 @@ export interface DailyMetric {
11
12
  count: number;
12
13
  sum: number;
13
14
  }
15
+ /** Per key, from opt-in per-user rows: keys nobody touched in the window are absent. */
16
+ export interface AudienceMetric {
17
+ project: string;
18
+ key: string;
19
+ /** Distinct actors. */
20
+ uniques: number;
21
+ /** Actors with more than one sample on a single day. */
22
+ repeatUsers: number;
23
+ /** Actors seen on more than one day. */
24
+ returningUsers: number;
25
+ }
26
+ /** Unordered: how many of `from`'s actors also touched `to`, in the same window. */
27
+ export interface AudienceOverlap {
28
+ project: string;
29
+ from: string;
30
+ to: string;
31
+ fromUsers: number;
32
+ bothUsers: number;
33
+ }
34
+ export interface Audience {
35
+ metrics: AudienceMetric[];
36
+ overlaps: AudienceOverlap[];
37
+ }
38
+ export interface MetricsWindow {
39
+ from: string;
40
+ to: string;
41
+ /** The window ends on the current, incomplete UTC day. */
42
+ partial: boolean;
43
+ }
44
+ /** One project, one window, everything a panel renders; the schema comes from the store. */
45
+ export interface MetricsReport {
46
+ project: string;
47
+ window: MetricsWindow;
48
+ schema: MetricsSchema;
49
+ daily: DailyMetric[];
50
+ audience: Audience;
51
+ }
14
52
  export interface MetricTotal {
15
53
  project: string;
16
54
  key: string;
@@ -1 +1 @@
1
- {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/metrics/report.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,MAAM,WAAW,WAAW;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,WAAW;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,gBAAgB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IAC5B,QAAQ,EAAE,WAAW,GAAG,IAAI,CAAC;IAC7B,WAAW,EAAE,YAAY,CAAC;IAC1B,aAAa,EAAE,YAAY,GAAG,IAAI,CAAC;CACnC;AAED,oEAAoE;AACpE,wBAAgB,aAAa,CAC5B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,IAAI,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAA;CAAO;;;;;;;;;;EAkBpD;AASD,yFAAyF;AACzF,wBAAgB,cAAc,CAC7B,OAAO,EAAE,SAAS,WAAW,EAAE,EAC/B,QAAQ,EAAE,SAAS,WAAW,EAAE,GAC9B,gBAAgB,EAAE,CA4CpB;AAED,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,WAAW,EAAE,GAAG,WAAW,EAAE,CAqC5E"}
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/metrics/report.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/metrics/report.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/metrics/report.ts"],"names":[],"mappings":"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"}
@@ -1,25 +1,52 @@
1
- import type { Measurement } from "./index.js";
2
- import type { DailyMetric } from "./report.js";
3
- /** Structural libSQL interface; callers own connections and credentials. */
4
- export interface MetricsDatabase {
5
- execute(statement: {
6
- sql: string;
7
- args: Array<string | number>;
8
- }): Promise<{
9
- rows: Iterable<Record<string, unknown>>;
10
- }>;
11
- batch(statements: Array<{
12
- sql: string;
13
- args: Array<string | number>;
14
- }>, mode: "write"): Promise<unknown>;
1
+ import type { MetricsSchema, MetricsStore } from "./index.js";
2
+ import { type Audience, type DailyMetric, type MetricsReport } from "./report.js";
3
+ export type SqlValue = string | number;
4
+ export interface SqlStatement {
5
+ sql: string;
6
+ args: SqlValue[];
7
+ }
8
+ /** Reads need one verb. `metrics/d1-rest` is a reader only: a REST call cannot transact. */
9
+ export interface MetricsReader {
10
+ /** The rows of one read statement. */
11
+ query(statement: SqlStatement): Promise<Iterable<Record<string, unknown>>>;
12
+ }
13
+ /**
14
+ * The SQLite dialect below needs exactly two verbs from a store. `metrics/libsql` and
15
+ * `metrics/d1` implement them with each driver's native calls; any driver that speaks
16
+ * SQLite (node:sqlite, bun:sqlite, better-sqlite3) does the same in a few lines.
17
+ */
18
+ export interface MetricsDriver extends MetricsReader {
19
+ /** Every statement or none: a constraint failure in any of them rolls the batch back. */
20
+ transact(statements: SqlStatement[]): Promise<unknown>;
15
21
  }
16
22
  /** Run explicitly during provisioning, never on a user's request. */
17
- export declare const METRICS_SCHEMA: readonly ["CREATE TABLE IF NOT EXISTS metric_definition (project TEXT NOT NULL, key TEXT NOT NULL, kind TEXT NOT NULL, label TEXT NOT NULL, help TEXT NOT NULL, unit TEXT NOT NULL, PRIMARY KEY(project, key))", "CREATE TABLE IF NOT EXISTS metric_daily (project TEXT NOT NULL, key TEXT NOT NULL, dimensions TEXT NOT NULL, day TEXT NOT NULL, count INTEGER NOT NULL CHECK(count >= 0), sum REAL NOT NULL CHECK(sum >= 0), PRIMARY KEY(project, key, dimensions, day))", "CREATE TABLE IF NOT EXISTS metric_user_daily (project TEXT NOT NULL, key TEXT NOT NULL, dimensions TEXT NOT NULL, day TEXT NOT NULL, user TEXT NOT NULL, count INTEGER NOT NULL CHECK(count >= 0), sum REAL NOT NULL CHECK(sum >= 0), PRIMARY KEY(project, key, dimensions, day, user))", "CREATE INDEX IF NOT EXISTS metric_user_identity ON metric_user_daily(project, user)"];
18
- export declare function sqliteMetricsWriter(db: MetricsDatabase, project: string): (m: Measurement) => Promise<void>;
23
+ export declare const METRICS_SCHEMA: readonly ["CREATE TABLE IF NOT EXISTS metric_definition (project TEXT NOT NULL, key TEXT NOT NULL, kind TEXT NOT NULL, label TEXT NOT NULL, help TEXT NOT NULL, unit TEXT NOT NULL, per_user INTEGER NOT NULL, PRIMARY KEY(project, key))", "CREATE TABLE IF NOT EXISTS metric_overlap (project TEXT NOT NULL, from_key TEXT NOT NULL, to_key TEXT NOT NULL, PRIMARY KEY(project, from_key, to_key))", "CREATE TABLE IF NOT EXISTS metric_daily (project TEXT NOT NULL, key TEXT NOT NULL, dimensions TEXT NOT NULL, day TEXT NOT NULL, count INTEGER NOT NULL CHECK(count >= 0), sum REAL NOT NULL CHECK(sum >= 0), PRIMARY KEY(project, key, dimensions, day))", "CREATE TABLE IF NOT EXISTS metric_user_daily (project TEXT NOT NULL, key TEXT NOT NULL, dimensions TEXT NOT NULL, day TEXT NOT NULL, user TEXT NOT NULL, count INTEGER NOT NULL CHECK(count >= 0), sum REAL NOT NULL CHECK(sum >= 0), PRIMARY KEY(project, key, dimensions, day, user))", "CREATE INDEX IF NOT EXISTS metric_user_identity ON metric_user_daily(project, user)"];
24
+ /** One project's store over a SQLite driver. */
25
+ export declare function metricsStore(driver: MetricsDriver, project: string): MetricsStore;
26
+ /** What one project declared, as the store holds it: the reader needs no declaring code. */
27
+ export declare function readSchema(reader: MetricsReader, project: string): Promise<MetricsSchema>;
19
28
  /** Inclusive UTC dates. Errors propagate: unavailable data must never read as zero. */
20
- export declare function readMetrics(db: MetricsDatabase, range: {
29
+ export declare function readMetrics(reader: MetricsReader, range: {
21
30
  from: string;
22
31
  to: string;
23
32
  project?: string;
24
33
  }): Promise<DailyMetric[]>;
34
+ /**
35
+ * Who did it, over one project's opt-in per-user rows, all dimensions folded: one row per
36
+ * declared per-user metric (zeros when nobody touched it in the window) with distinct
37
+ * actors, actors with more than one sample on a single day, actors seen on more than one
38
+ * day; then every declared unordered overlap.
39
+ */
40
+ export declare function readAudience(reader: MetricsReader, range: {
41
+ from: string;
42
+ to: string;
43
+ project: string;
44
+ }, schema: MetricsSchema): Promise<Audience>;
45
+ /** Everything a panel renders for one project over the last `days` UTC days, in one call. */
46
+ export declare function readReport(reader: MetricsReader, options: {
47
+ project: string;
48
+ days: number;
49
+ includeToday?: boolean;
50
+ now?: Date;
51
+ }): Promise<MetricsReport>;
25
52
  //# sourceMappingURL=sqlite.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../src/metrics/sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,4EAA4E;AAC5E,MAAM,WAAW,eAAe;IAC/B,OAAO,CAAC,SAAS,EAAE;QAClB,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;KAC7B,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;KAAE,CAAC,CAAC;IACzD,KAAK,CACJ,UAAU,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAA;KAAE,CAAC,EAChE,IAAI,EAAE,OAAO,GACX,OAAO,CAAC,OAAO,CAAC,CAAC;CACpB;AAED,qEAAqE;AACrE,eAAO,MAAM,cAAc,g0BAKjB,CAAC;AAEX,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,IAGzD,GAAG,WAAW,mBAoC5B;AAED,uFAAuF;AACvF,wBAAsB,WAAW,CAChC,EAAE,EAAE,eAAe,EACnB,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GACnD,OAAO,CAAC,WAAW,EAAE,CAAC,CAyBxB"}
1
+ {"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../src/metrics/sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC3E,OAAO,EACN,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,aAAa,EAElB,MAAM,aAAa,CAAC;AAErB,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;AACvC,MAAM,WAAW,YAAY;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,QAAQ,EAAE,CAAC;CACjB;AAED,4FAA4F;AAC5F,MAAM,WAAW,aAAa;IAC7B,sCAAsC;IACtC,KAAK,CAAC,SAAS,EAAE,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;CAC3E;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAc,SAAQ,aAAa;IACnD,yFAAyF;IACzF,QAAQ,CAAC,UAAU,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACvD;AAED,qEAAqE;AACrE,eAAO,MAAM,cAAc,s/BAMjB,CAAC;AAiBX,gDAAgD;AAChD,wBAAgB,YAAY,CAC3B,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,MAAM,GACb,YAAY,CAqDd;AAED,4FAA4F;AAC5F,wBAAsB,UAAU,CAC/B,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,MAAM,GACb,OAAO,CAAC,aAAa,CAAC,CA0BxB;AAED,uFAAuF;AACvF,wBAAsB,WAAW,CAChC,MAAM,EAAE,aAAa,EACrB,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GACnD,OAAO,CAAC,WAAW,EAAE,CAAC,CAmBxB;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CACjC,MAAM,EAAE,aAAa,EACrB,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EACpD,MAAM,EAAE,aAAa,GACnB,OAAO,CAAC,QAAQ,CAAC,CAmDnB;AAED,6FAA6F;AAC7F,wBAAsB,UAAU,CAC/B,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE;IACR,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,GAAG,CAAC,EAAE,IAAI,CAAC;CACX,GACC,OAAO,CAAC,aAAa,CAAC,CAkBxB"}
@@ -1,64 +1,119 @@
1
+ import { metricWindows, } from "./report.js";
1
2
  /** Run explicitly during provisioning, never on a user's request. */
2
3
  export const METRICS_SCHEMA = [
3
- `CREATE TABLE IF NOT EXISTS metric_definition (project TEXT NOT NULL, key TEXT NOT NULL, kind TEXT NOT NULL, label TEXT NOT NULL, help TEXT NOT NULL, unit TEXT NOT NULL, PRIMARY KEY(project, key))`,
4
+ `CREATE TABLE IF NOT EXISTS metric_definition (project TEXT NOT NULL, key TEXT NOT NULL, kind TEXT NOT NULL, label TEXT NOT NULL, help TEXT NOT NULL, unit TEXT NOT NULL, per_user INTEGER NOT NULL, PRIMARY KEY(project, key))`,
5
+ `CREATE TABLE IF NOT EXISTS metric_overlap (project TEXT NOT NULL, from_key TEXT NOT NULL, to_key TEXT NOT NULL, PRIMARY KEY(project, from_key, to_key))`,
4
6
  `CREATE TABLE IF NOT EXISTS metric_daily (project TEXT NOT NULL, key TEXT NOT NULL, dimensions TEXT NOT NULL, day TEXT NOT NULL, count INTEGER NOT NULL CHECK(count >= 0), sum REAL NOT NULL CHECK(sum >= 0), PRIMARY KEY(project, key, dimensions, day))`,
5
7
  `CREATE TABLE IF NOT EXISTS metric_user_daily (project TEXT NOT NULL, key TEXT NOT NULL, dimensions TEXT NOT NULL, day TEXT NOT NULL, user TEXT NOT NULL, count INTEGER NOT NULL CHECK(count >= 0), sum REAL NOT NULL CHECK(sum >= 0), PRIMARY KEY(project, key, dimensions, day, user))`,
6
8
  `CREATE INDEX IF NOT EXISTS metric_user_identity ON metric_user_daily(project, user)`,
7
9
  ];
8
- export function sqliteMetricsWriter(db, project) {
9
- if (!/^[a-z][a-z0-9-]*$/.test(project))
10
+ const PROJECT = /^[a-z][a-z0-9-]*$/;
11
+ const DAY = /^\d{4}-\d{2}-\d{2}$/;
12
+ function assertProject(project) {
13
+ if (!PROJECT.test(project))
10
14
  throw new Error("metrics: invalid project");
11
- return async (m) => {
12
- const dimensions = JSON.stringify(m.dimensions);
13
- const statements = [
14
- {
15
- // NOT NULL makes a changed kind/unit fail the whole atomic batch, including counts.
16
- // Labels/help may evolve, but historical measurements must retain their meaning.
17
- sql: `INSERT INTO metric_definition VALUES (?, ?, ?, ?, ?, ?) ON CONFLICT(project, key) DO UPDATE SET kind=CASE WHEN kind=excluded.kind THEN kind ELSE NULL END, label=excluded.label, help=excluded.help, unit=CASE WHEN unit=excluded.unit THEN unit ELSE NULL END`,
15
+ }
16
+ function assertRange(range) {
17
+ for (const day of [range.from, range.to]) {
18
+ if (!DAY.test(day) || new Date(day).toISOString().slice(0, 10) !== day)
19
+ throw new Error("metrics: invalid UTC date");
20
+ }
21
+ if (range.from > range.to)
22
+ throw new Error("metrics: reversed date range");
23
+ }
24
+ /** One project's store over a SQLite driver. */
25
+ export function metricsStore(driver, project) {
26
+ assertProject(project);
27
+ return {
28
+ async declare(schema) {
29
+ const statements = schema.metrics.map((m) => ({
30
+ // NOT NULL makes a changed kind/unit fail the whole atomic batch. Labels, help
31
+ // and the per-user flag may evolve; historical measurements keep their meaning.
32
+ sql: `INSERT INTO metric_definition VALUES (?, ?, ?, ?, ?, ?, ?) ON CONFLICT(project, key) DO UPDATE SET kind=CASE WHEN kind=excluded.kind THEN kind ELSE NULL END, label=excluded.label, help=excluded.help, unit=CASE WHEN unit=excluded.unit THEN unit ELSE NULL END, per_user=excluded.per_user`,
18
33
  args: [
19
34
  project,
20
35
  m.key,
21
- m.spec.kind,
22
- m.spec.label,
23
- m.spec.help ?? "",
24
- m.spec.unit ?? "",
36
+ m.kind,
37
+ m.label,
38
+ m.help ?? "",
39
+ m.unit ?? "",
40
+ m.perUser ? 1 : 0,
25
41
  ],
26
- },
27
- {
28
- sql: `INSERT INTO metric_daily VALUES (?, ?, ?, ?, ?, ?) ON CONFLICT(project, key, dimensions, day) DO UPDATE SET count=count+excluded.count, sum=sum+excluded.sum`,
29
- args: [project, m.key, dimensions, m.day, m.count, m.sum],
30
- },
31
- ];
32
- if (m.user !== undefined)
42
+ }));
33
43
  statements.push({
34
- sql: `INSERT INTO metric_user_daily VALUES (?, ?, ?, ?, ?, ?, ?) ON CONFLICT(project, key, dimensions, day, user) DO UPDATE SET count=count+excluded.count, sum=sum+excluded.sum`,
35
- args: [
36
- project,
37
- m.key,
38
- dimensions,
39
- m.day,
40
- String(m.user),
41
- m.count,
42
- m.sum,
43
- ],
44
+ sql: `DELETE FROM metric_overlap WHERE project = ?`,
45
+ args: [project],
44
46
  });
45
- await db.batch(statements, "write");
47
+ for (const o of schema.overlaps)
48
+ statements.push({
49
+ sql: `INSERT INTO metric_overlap VALUES (?, ?, ?)`,
50
+ args: [project, o.from, o.to],
51
+ });
52
+ await driver.transact(statements);
53
+ },
54
+ async write(m) {
55
+ const dimensions = JSON.stringify(m.dimensions);
56
+ const statements = [
57
+ {
58
+ sql: `INSERT INTO metric_daily VALUES (?, ?, ?, ?, ?, ?) ON CONFLICT(project, key, dimensions, day) DO UPDATE SET count=count+excluded.count, sum=sum+excluded.sum`,
59
+ args: [project, m.key, dimensions, m.day, m.count, m.sum],
60
+ },
61
+ ];
62
+ if (m.user !== undefined)
63
+ statements.push({
64
+ sql: `INSERT INTO metric_user_daily VALUES (?, ?, ?, ?, ?, ?, ?) ON CONFLICT(project, key, dimensions, day, user) DO UPDATE SET count=count+excluded.count, sum=sum+excluded.sum`,
65
+ args: [
66
+ project,
67
+ m.key,
68
+ dimensions,
69
+ m.day,
70
+ String(m.user),
71
+ m.count,
72
+ m.sum,
73
+ ],
74
+ });
75
+ await driver.transact(statements);
76
+ },
77
+ };
78
+ }
79
+ /** What one project declared, as the store holds it: the reader needs no declaring code. */
80
+ export async function readSchema(reader, project) {
81
+ assertProject(project);
82
+ const [definitions, overlaps] = await Promise.all([
83
+ reader.query({
84
+ sql: `SELECT key, kind, label, help, unit, per_user FROM metric_definition WHERE project = ? ORDER BY key`,
85
+ args: [project],
86
+ }),
87
+ reader.query({
88
+ sql: `SELECT from_key, to_key FROM metric_overlap WHERE project = ? ORDER BY from_key, to_key`,
89
+ args: [project],
90
+ }),
91
+ ]);
92
+ return {
93
+ metrics: Array.from(definitions, (r) => ({
94
+ key: String(r.key),
95
+ kind: String(r.kind),
96
+ label: String(r.label),
97
+ ...(r.help ? { help: String(r.help) } : {}),
98
+ ...(r.unit ? { unit: String(r.unit) } : {}),
99
+ ...(Number(r.per_user) ? { perUser: true } : {}),
100
+ })),
101
+ overlaps: Array.from(overlaps, (r) => ({
102
+ from: String(r.from_key),
103
+ to: String(r.to_key),
104
+ })),
46
105
  };
47
106
  }
48
107
  /** Inclusive UTC dates. Errors propagate: unavailable data must never read as zero. */
49
- export async function readMetrics(db, range) {
50
- for (const day of [range.from, range.to]) {
51
- if (!/^\d{4}-\d{2}-\d{2}$/.test(day) ||
52
- new Date(day).toISOString().slice(0, 10) !== day)
53
- throw new Error("metrics: invalid UTC date");
54
- }
55
- if (range.from > range.to)
56
- throw new Error("metrics: reversed date range");
57
- const result = await db.execute({
108
+ export async function readMetrics(reader, range) {
109
+ assertRange(range);
110
+ if (range.project !== undefined)
111
+ assertProject(range.project);
112
+ const rows = await reader.query({
58
113
  sql: `SELECT d.*, s.label, s.kind, s.help, s.unit FROM metric_daily d JOIN metric_definition s USING(project, key) WHERE day >= ? AND day <= ? ${range.project ? "AND project = ?" : ""} ORDER BY project, key, dimensions, day`,
59
114
  args: [range.from, range.to, ...(range.project ? [range.project] : [])],
60
115
  });
61
- return Array.from(result.rows, (r) => ({
116
+ return Array.from(rows, (r) => ({
62
117
  project: String(r.project),
63
118
  key: String(r.key),
64
119
  label: String(r.label),
@@ -71,4 +126,75 @@ export async function readMetrics(db, range) {
71
126
  sum: Number(r.sum),
72
127
  }));
73
128
  }
129
+ /**
130
+ * Who did it, over one project's opt-in per-user rows, all dimensions folded: one row per
131
+ * declared per-user metric (zeros when nobody touched it in the window) with distinct
132
+ * actors, actors with more than one sample on a single day, actors seen on more than one
133
+ * day; then every declared unordered overlap.
134
+ */
135
+ export async function readAudience(reader, range, schema) {
136
+ assertRange(range);
137
+ assertProject(range.project);
138
+ const perKey = new Map(Array.from(await reader.query({
139
+ sql: `WITH per_day AS (SELECT key, user, day, SUM(count) AS count FROM metric_user_daily WHERE project = ? AND day >= ? AND day <= ? GROUP BY key, user, day), per_user AS (SELECT key, user, COUNT(*) AS days, MAX(count) AS peak FROM per_day GROUP BY key, user) SELECT key, COUNT(*) AS uniques, SUM(CASE WHEN peak > 1 THEN 1 ELSE 0 END) AS repeat_users, SUM(CASE WHEN days > 1 THEN 1 ELSE 0 END) AS returning_users FROM per_user GROUP BY key`,
140
+ args: [range.project, range.from, range.to],
141
+ }), (r) => [String(r.key), r]));
142
+ const metrics = schema.metrics
143
+ .filter((m) => m.perUser)
144
+ .map((m) => {
145
+ const r = perKey.get(m.key);
146
+ return {
147
+ project: range.project,
148
+ key: m.key,
149
+ uniques: Number(r?.uniques ?? 0),
150
+ repeatUsers: Number(r?.repeat_users ?? 0),
151
+ returningUsers: Number(r?.returning_users ?? 0),
152
+ };
153
+ });
154
+ const actors = `SELECT DISTINCT user FROM metric_user_daily WHERE project = ? AND key = ? AND day >= ? AND day <= ?`;
155
+ const overlaps = [];
156
+ for (const pair of schema.overlaps) {
157
+ const [row] = Array.from(await reader.query({
158
+ sql: `WITH a AS (${actors}), b AS (${actors}) SELECT (SELECT COUNT(*) FROM a) AS from_users, (SELECT COUNT(*) FROM a WHERE user IN (SELECT user FROM b)) AS both_users`,
159
+ args: [
160
+ range.project,
161
+ pair.from,
162
+ range.from,
163
+ range.to,
164
+ range.project,
165
+ pair.to,
166
+ range.from,
167
+ range.to,
168
+ ],
169
+ }));
170
+ overlaps.push({
171
+ project: range.project,
172
+ from: pair.from,
173
+ to: pair.to,
174
+ fromUsers: Number(row?.from_users ?? 0),
175
+ bothUsers: Number(row?.both_users ?? 0),
176
+ });
177
+ }
178
+ return { metrics, overlaps };
179
+ }
180
+ /** Everything a panel renders for one project over the last `days` UTC days, in one call. */
181
+ export async function readReport(reader, options) {
182
+ const { current, partial } = metricWindows(options.days, {
183
+ now: options.now,
184
+ includeToday: options.includeToday,
185
+ });
186
+ const range = { ...current, project: options.project };
187
+ const schema = await readSchema(reader, options.project);
188
+ const [daily, audience] = await Promise.all([
189
+ readMetrics(reader, range),
190
+ readAudience(reader, range, schema),
191
+ ]);
192
+ return {
193
+ project: options.project,
194
+ window: { ...current, partial },
195
+ schema,
196
+ daily,
197
+ audience,
198
+ };
199
+ }
74
200
  //# sourceMappingURL=sqlite.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../../src/metrics/sqlite.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../../src/metrics/sqlite.ts"],"names":[],"mappings":"AACA,OAAO,EAIN,aAAa,GACb,MAAM,aAAa,CAAC;AAwBrB,qEAAqE;AACrE,MAAM,CAAC,MAAM,cAAc,GAAG;IAC7B,gOAAgO;IAChO,yJAAyJ;IACzJ,0PAA0P;IAC1P,yRAAyR;IACzR,qFAAqF;CAC5E,CAAC;AAEX,MAAM,OAAO,GAAG,mBAAmB,CAAC;AACpC,MAAM,GAAG,GAAG,qBAAqB,CAAC;AAElC,SAAS,aAAa,CAAC,OAAe;IACrC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;AACzE,CAAC;AAED,SAAS,WAAW,CAAC,KAAmC;IACvD,KAAK,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;QAC1C,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,GAAG;YACrE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC/C,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;AAC5E,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,YAAY,CAC3B,MAAqB,EACrB,OAAe;IAEf,aAAa,CAAC,OAAO,CAAC,CAAC;IACvB,OAAO;QACN,KAAK,CAAC,OAAO,CAAC,MAAqB;YAClC,MAAM,UAAU,GAAmB,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC7D,+EAA+E;gBAC/E,gFAAgF;gBAChF,GAAG,EAAE,+RAA+R;gBACpS,IAAI,EAAE;oBACL,OAAO;oBACP,CAAC,CAAC,GAAG;oBACL,CAAC,CAAC,IAAI;oBACN,CAAC,CAAC,KAAK;oBACP,CAAC,CAAC,IAAI,IAAI,EAAE;oBACZ,CAAC,CAAC,IAAI,IAAI,EAAE;oBACZ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;iBACjB;aACD,CAAC,CAAC,CAAC;YACJ,UAAU,CAAC,IAAI,CAAC;gBACf,GAAG,EAAE,8CAA8C;gBACnD,IAAI,EAAE,CAAC,OAAO,CAAC;aACf,CAAC,CAAC;YACH,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ;gBAC9B,UAAU,CAAC,IAAI,CAAC;oBACf,GAAG,EAAE,6CAA6C;oBAClD,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;iBAC7B,CAAC,CAAC;YACJ,MAAM,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QACnC,CAAC;QACD,KAAK,CAAC,KAAK,CAAC,CAAc;YACzB,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;YAChD,MAAM,UAAU,GAAmB;gBAClC;oBACC,GAAG,EAAE,8JAA8J;oBACnK,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC;iBACzD;aACD,CAAC;YACF,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS;gBACvB,UAAU,CAAC,IAAI,CAAC;oBACf,GAAG,EAAE,4KAA4K;oBACjL,IAAI,EAAE;wBACL,OAAO;wBACP,CAAC,CAAC,GAAG;wBACL,UAAU;wBACV,CAAC,CAAC,GAAG;wBACL,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;wBACd,CAAC,CAAC,KAAK;wBACP,CAAC,CAAC,GAAG;qBACL;iBACD,CAAC,CAAC;YACJ,MAAM,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QACnC,CAAC;KACD,CAAC;AACH,CAAC;AAED,4FAA4F;AAC5F,MAAM,CAAC,KAAK,UAAU,UAAU,CAC/B,MAAqB,EACrB,OAAe;IAEf,aAAa,CAAC,OAAO,CAAC,CAAC;IACvB,MAAM,CAAC,WAAW,EAAE,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACjD,MAAM,CAAC,KAAK,CAAC;YACZ,GAAG,EAAE,qGAAqG;YAC1G,IAAI,EAAE,CAAC,OAAO,CAAC;SACf,CAAC;QACF,MAAM,CAAC,KAAK,CAAC;YACZ,GAAG,EAAE,yFAAyF;YAC9F,IAAI,EAAE,CAAC,OAAO,CAAC;SACf,CAAC;KACF,CAAC,CAAC;IACH,OAAO;QACN,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACxC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;YAClB,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAyB;YAC5C,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;YACtB,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3C,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3C,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAChD,CAAC,CAAC;QACH,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACtC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;YACxB,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;SACpB,CAAC,CAAC;KACH,CAAC;AACH,CAAC;AAED,uFAAuF;AACvF,MAAM,CAAC,KAAK,UAAU,WAAW,CAChC,MAAqB,EACrB,KAAqD;IAErD,WAAW,CAAC,KAAK,CAAC,CAAC;IACnB,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS;QAAE,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC9D,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC;QAC/B,GAAG,EAAE,4IAA4I,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,yCAAyC;QAChO,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;KACvE,CAAC,CAAC;IACH,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC/B,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;QAC1B,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;QACtB,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;QACpB,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QAC5C,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;QACtB,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;KAClB,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CACjC,MAAqB,EACrB,KAAoD,EACpD,MAAqB;IAErB,WAAW,CAAC,KAAK,CAAC,CAAC;IACnB,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7B,MAAM,MAAM,GAAG,IAAI,GAAG,CACrB,KAAK,CAAC,IAAI,CACT,MAAM,MAAM,CAAC,KAAK,CAAC;QAClB,GAAG,EAAE,mbAAmb;QACxb,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;KAC3C,CAAC,EACF,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAU,CAClC,CACD,CAAC;IACF,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO;SAC5B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;SACxB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACV,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC5B,OAAO;YACN,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,GAAG,EAAE,CAAC,CAAC,GAAG;YACV,OAAO,EAAE,MAAM,CAAC,CAAC,EAAE,OAAO,IAAI,CAAC,CAAC;YAChC,WAAW,EAAE,MAAM,CAAC,CAAC,EAAE,YAAY,IAAI,CAAC,CAAC;YACzC,cAAc,EAAE,MAAM,CAAC,CAAC,EAAE,eAAe,IAAI,CAAC,CAAC;SAC/C,CAAC;IACH,CAAC,CAAC,CAAC;IACJ,MAAM,MAAM,GAAG,qGAAqG,CAAC;IACrH,MAAM,QAAQ,GAAyB,EAAE,CAAC;IAC1C,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACpC,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,IAAI,CACvB,MAAM,MAAM,CAAC,KAAK,CAAC;YAClB,GAAG,EAAE,cAAc,MAAM,YAAY,MAAM,4HAA4H;YACvK,IAAI,EAAE;gBACL,KAAK,CAAC,OAAO;gBACb,IAAI,CAAC,IAAI;gBACT,KAAK,CAAC,IAAI;gBACV,KAAK,CAAC,EAAE;gBACR,KAAK,CAAC,OAAO;gBACb,IAAI,CAAC,EAAE;gBACP,KAAK,CAAC,IAAI;gBACV,KAAK,CAAC,EAAE;aACR;SACD,CAAC,CACF,CAAC;QACF,QAAQ,CAAC,IAAI,CAAC;YACb,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,SAAS,EAAE,MAAM,CAAC,GAAG,EAAE,UAAU,IAAI,CAAC,CAAC;YACvC,SAAS,EAAE,MAAM,CAAC,GAAG,EAAE,UAAU,IAAI,CAAC,CAAC;SACvC,CAAC,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;AAC9B,CAAC;AAED,6FAA6F;AAC7F,MAAM,CAAC,KAAK,UAAU,UAAU,CAC/B,MAAqB,EACrB,OAKC;IAED,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,aAAa,CAAC,OAAO,CAAC,IAAI,EAAE;QACxD,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,YAAY,EAAE,OAAO,CAAC,YAAY;KAClC,CAAC,CAAC;IACH,MAAM,KAAK,GAAG,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;IACvD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACzD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC3C,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC;QAC1B,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC;KACnC,CAAC,CAAC;IACH,OAAO;QACN,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,MAAM,EAAE,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE;QAC/B,MAAM;QACN,KAAK;QACL,QAAQ;KACR,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adriangalilea/utils",
3
- "version": "4.1.1",
3
+ "version": "6.0.0",
4
4
  "description": "TypeScript utilities - logger, currency, formatter, GramIO bot plugins, and more",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -192,6 +192,18 @@
192
192
  "types": "./dist/metrics/sqlite.d.ts",
193
193
  "default": "./dist/metrics/sqlite.js"
194
194
  },
195
+ "./metrics/libsql": {
196
+ "types": "./dist/metrics/libsql.d.ts",
197
+ "default": "./dist/metrics/libsql.js"
198
+ },
199
+ "./metrics/d1": {
200
+ "types": "./dist/metrics/d1.d.ts",
201
+ "default": "./dist/metrics/d1.js"
202
+ },
203
+ "./metrics/d1-rest": {
204
+ "types": "./dist/metrics/d1-rest.d.ts",
205
+ "default": "./dist/metrics/d1-rest.js"
206
+ },
195
207
  "./metrics/report": {
196
208
  "types": "./dist/metrics/report.d.ts",
197
209
  "default": "./dist/metrics/report.js"