@miguelmorales13/nestkit 0.5.1 → 0.6.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.
@@ -0,0 +1,109 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
+
3
+
4
+ var _chunk2REOCMUDcjs = require('../chunk-2REOCMUD.cjs');
5
+
6
+ // src/umami/umami.module.ts
7
+ var _common = require('@nestjs/common');
8
+
9
+ // src/umami/umami.service.ts
10
+
11
+
12
+ // src/umami/umami.options.ts
13
+ var UMAMI_OPTIONS = /* @__PURE__ */ Symbol("UMAMI_OPTIONS");
14
+
15
+ // src/umami/umami.service.ts
16
+ var CLOUD = "https://api.umami.is/v1";
17
+ var DAY_MS = 24 * 60 * 60 * 1e3;
18
+ var UmamiService = class {
19
+ constructor(options) {
20
+ this.options = options;
21
+ this.logger = new (0, _common.Logger)(UmamiService.name);
22
+ }
23
+ /** Whether there is enough configuration to make a call at all. */
24
+ get configured() {
25
+ return Boolean(this.options.apiKey && this.options.websiteId);
26
+ }
27
+ /** A range covering the last `days` days, ending now. */
28
+ static lastDays(days) {
29
+ const endAt = Date.now();
30
+ return { startAt: endAt - days * DAY_MS, endAt };
31
+ }
32
+ /** Visitors, pageviews, visits and bounces for a range. */
33
+ stats(range) {
34
+ return this.request("stats", range);
35
+ }
36
+ /**
37
+ * A breakdown by one dimension: top pages, referrers, countries, or —
38
+ * with `'event'` — how many times each custom event fired.
39
+ */
40
+ metrics(type, range, limit) {
41
+ return this.request("metrics", range, {
42
+ type,
43
+ ...limit ? { limit: String(limit) } : {}
44
+ });
45
+ }
46
+ /**
47
+ * How many times one named event fired. Returns 0 when the event exists but
48
+ * never fired, and `null` when the call itself failed — the difference
49
+ * matters: one is "nobody did it", the other is "we don't know".
50
+ */
51
+ async eventCount(name, range) {
52
+ const rows = await this.metrics("event", range);
53
+ if (rows === null) return null;
54
+ return _nullishCoalesce(_optionalChain([rows, 'access', _ => _.find, 'call', _2 => _2((row) => row.x === name), 'optionalAccess', _3 => _3.y]), () => ( 0));
55
+ }
56
+ async request(resource, range, extra = {}) {
57
+ if (!this.configured) {
58
+ this.logger.warn("Umami is not configured: apiKey and websiteId are required.");
59
+ return null;
60
+ }
61
+ const params = new URLSearchParams({
62
+ startAt: String(range.startAt),
63
+ endAt: String(range.endAt),
64
+ ...this.options.timezone ? { timezone: this.options.timezone } : {},
65
+ ...extra
66
+ });
67
+ const base = _nullishCoalesce(this.options.baseUrl, () => ( CLOUD));
68
+ try {
69
+ const response = await fetch(
70
+ `${base}/websites/${this.options.websiteId}/${resource}?${params}`,
71
+ { headers: { "x-umami-api-key": this.options.apiKey } }
72
+ );
73
+ if (!response.ok) {
74
+ this.logger.warn(`Umami ${resource}: HTTP ${response.status}`);
75
+ return null;
76
+ }
77
+ return await response.json();
78
+ } catch (error) {
79
+ this.logger.warn(`Umami ${resource}: ${error.message}`);
80
+ return null;
81
+ }
82
+ }
83
+ };
84
+ UmamiService = exports.UmamiService = _chunk2REOCMUDcjs.__decorateClass.call(void 0, [
85
+ _common.Injectable.call(void 0, ),
86
+ _chunk2REOCMUDcjs.__decorateParam.call(void 0, 0, _common.Inject.call(void 0, UMAMI_OPTIONS))
87
+ ], UmamiService);
88
+
89
+ // src/umami/umami.module.ts
90
+ var UmamiModule = class {
91
+ static forRoot(options) {
92
+ return {
93
+ module: UmamiModule,
94
+ providers: [
95
+ { provide: UMAMI_OPTIONS, useValue: options },
96
+ UmamiService
97
+ ],
98
+ exports: [UmamiService]
99
+ };
100
+ }
101
+ };
102
+ UmamiModule = exports.UmamiModule = _chunk2REOCMUDcjs.__decorateClass.call(void 0, [
103
+ _common.Module.call(void 0, {})
104
+ ], UmamiModule);
105
+
106
+
107
+
108
+
109
+ exports.UMAMI_OPTIONS = UMAMI_OPTIONS; exports.UmamiModule = UmamiModule; exports.UmamiService = UmamiService;
@@ -0,0 +1,4 @@
1
+ export { UmamiModule } from './umami.module.js';
2
+ export { UmamiService } from './umami.service.js';
3
+ export { UMAMI_OPTIONS, type UmamiOptions } from './umami.options.js';
4
+ export type { UmamiStats, UmamiMetric, UmamiMetricType, UmamiRange, } from './umami.types.js';
@@ -0,0 +1,109 @@
1
+ import {
2
+ __decorateClass,
3
+ __decorateParam
4
+ } from "../chunk-4MGIQFAJ.js";
5
+
6
+ // src/umami/umami.module.ts
7
+ import { Module } from "@nestjs/common";
8
+
9
+ // src/umami/umami.service.ts
10
+ import { Inject, Injectable, Logger } from "@nestjs/common";
11
+
12
+ // src/umami/umami.options.ts
13
+ var UMAMI_OPTIONS = /* @__PURE__ */ Symbol("UMAMI_OPTIONS");
14
+
15
+ // src/umami/umami.service.ts
16
+ var CLOUD = "https://api.umami.is/v1";
17
+ var DAY_MS = 24 * 60 * 60 * 1e3;
18
+ var UmamiService = class {
19
+ constructor(options) {
20
+ this.options = options;
21
+ this.logger = new Logger(UmamiService.name);
22
+ }
23
+ /** Whether there is enough configuration to make a call at all. */
24
+ get configured() {
25
+ return Boolean(this.options.apiKey && this.options.websiteId);
26
+ }
27
+ /** A range covering the last `days` days, ending now. */
28
+ static lastDays(days) {
29
+ const endAt = Date.now();
30
+ return { startAt: endAt - days * DAY_MS, endAt };
31
+ }
32
+ /** Visitors, pageviews, visits and bounces for a range. */
33
+ stats(range) {
34
+ return this.request("stats", range);
35
+ }
36
+ /**
37
+ * A breakdown by one dimension: top pages, referrers, countries, or —
38
+ * with `'event'` — how many times each custom event fired.
39
+ */
40
+ metrics(type, range, limit) {
41
+ return this.request("metrics", range, {
42
+ type,
43
+ ...limit ? { limit: String(limit) } : {}
44
+ });
45
+ }
46
+ /**
47
+ * How many times one named event fired. Returns 0 when the event exists but
48
+ * never fired, and `null` when the call itself failed — the difference
49
+ * matters: one is "nobody did it", the other is "we don't know".
50
+ */
51
+ async eventCount(name, range) {
52
+ const rows = await this.metrics("event", range);
53
+ if (rows === null) return null;
54
+ return rows.find((row) => row.x === name)?.y ?? 0;
55
+ }
56
+ async request(resource, range, extra = {}) {
57
+ if (!this.configured) {
58
+ this.logger.warn("Umami is not configured: apiKey and websiteId are required.");
59
+ return null;
60
+ }
61
+ const params = new URLSearchParams({
62
+ startAt: String(range.startAt),
63
+ endAt: String(range.endAt),
64
+ ...this.options.timezone ? { timezone: this.options.timezone } : {},
65
+ ...extra
66
+ });
67
+ const base = this.options.baseUrl ?? CLOUD;
68
+ try {
69
+ const response = await fetch(
70
+ `${base}/websites/${this.options.websiteId}/${resource}?${params}`,
71
+ { headers: { "x-umami-api-key": this.options.apiKey } }
72
+ );
73
+ if (!response.ok) {
74
+ this.logger.warn(`Umami ${resource}: HTTP ${response.status}`);
75
+ return null;
76
+ }
77
+ return await response.json();
78
+ } catch (error) {
79
+ this.logger.warn(`Umami ${resource}: ${error.message}`);
80
+ return null;
81
+ }
82
+ }
83
+ };
84
+ UmamiService = __decorateClass([
85
+ Injectable(),
86
+ __decorateParam(0, Inject(UMAMI_OPTIONS))
87
+ ], UmamiService);
88
+
89
+ // src/umami/umami.module.ts
90
+ var UmamiModule = class {
91
+ static forRoot(options) {
92
+ return {
93
+ module: UmamiModule,
94
+ providers: [
95
+ { provide: UMAMI_OPTIONS, useValue: options },
96
+ UmamiService
97
+ ],
98
+ exports: [UmamiService]
99
+ };
100
+ }
101
+ };
102
+ UmamiModule = __decorateClass([
103
+ Module({})
104
+ ], UmamiModule);
105
+ export {
106
+ UMAMI_OPTIONS,
107
+ UmamiModule,
108
+ UmamiService
109
+ };
@@ -0,0 +1,6 @@
1
+ import { type DynamicModule } from '@nestjs/common';
2
+ import { type UmamiOptions } from './umami.options.js';
3
+ /** Read-only access to the Umami analytics API. See `UmamiService`. */
4
+ export declare class UmamiModule {
5
+ static forRoot(options: UmamiOptions): DynamicModule;
6
+ }
@@ -0,0 +1,20 @@
1
+ export declare const UMAMI_OPTIONS: unique symbol;
2
+ export interface UmamiOptions {
3
+ /** API key from Umami Cloud (Settings → API Keys), or a self-hosted token. */
4
+ apiKey?: string;
5
+ /** The website's UUID, shown next to its name in the dashboard. */
6
+ websiteId?: string;
7
+ /**
8
+ * API base URL. Defaults to Umami Cloud.
9
+ *
10
+ * Self-hosted instances serve the same endpoints under `/api`, so pass
11
+ * `https://your-host/api` there.
12
+ */
13
+ baseUrl?: string;
14
+ /**
15
+ * Timezone for the queries, as an IANA name. Umami buckets by day in this
16
+ * zone, so leaving it unset silently reports UTC days — which for anything
17
+ * outside UTC means a "day" that starts in the middle of the afternoon.
18
+ */
19
+ timezone?: string;
20
+ }
@@ -0,0 +1,40 @@
1
+ import { type UmamiOptions } from './umami.options.js';
2
+ import type { UmamiMetric, UmamiMetricType, UmamiRange, UmamiStats } from './umami.types.js';
3
+ /**
4
+ * Read-only client for the Umami analytics API.
5
+ *
6
+ * Only reads. Events are sent by the browser script; a backend writing them
7
+ * would be reporting traffic that never happened.
8
+ *
9
+ * Every method returns `null` instead of throwing when a call fails. A summary
10
+ * usually asks for several things at once, and one endpoint being down should
11
+ * not take the rest of the report with it — the caller decides what a missing
12
+ * block means. Failures are logged, so a persistent one is still visible.
13
+ *
14
+ * Deliberately has no opinion about what the numbers mean. Which events form
15
+ * a funnel, what to call them and how to phrase a report are product
16
+ * decisions that differ per app; this only fetches.
17
+ */
18
+ export declare class UmamiService {
19
+ private readonly options;
20
+ private readonly logger;
21
+ constructor(options: UmamiOptions);
22
+ /** Whether there is enough configuration to make a call at all. */
23
+ get configured(): boolean;
24
+ /** A range covering the last `days` days, ending now. */
25
+ static lastDays(days: number): UmamiRange;
26
+ /** Visitors, pageviews, visits and bounces for a range. */
27
+ stats(range: UmamiRange): Promise<UmamiStats | null>;
28
+ /**
29
+ * A breakdown by one dimension: top pages, referrers, countries, or —
30
+ * with `'event'` — how many times each custom event fired.
31
+ */
32
+ metrics(type: UmamiMetricType, range: UmamiRange, limit?: number): Promise<UmamiMetric[] | null>;
33
+ /**
34
+ * How many times one named event fired. Returns 0 when the event exists but
35
+ * never fired, and `null` when the call itself failed — the difference
36
+ * matters: one is "nobody did it", the other is "we don't know".
37
+ */
38
+ eventCount(name: string, range: UmamiRange): Promise<number | null>;
39
+ private request;
40
+ }
@@ -0,0 +1,24 @@
1
+ /** What `GET /websites/:id/stats` returns. */
2
+ export interface UmamiStats {
3
+ pageviews: number;
4
+ visitors: number;
5
+ visits: number;
6
+ bounces: number;
7
+ totaltime: number;
8
+ }
9
+ /**
10
+ * A single metric row. Umami names these `x` and `y` across every metric type,
11
+ * so the meaning of `x` depends on what was asked for: a URL, a referrer, a
12
+ * country, an event name.
13
+ */
14
+ export interface UmamiMetric {
15
+ x: string | null;
16
+ y: number;
17
+ }
18
+ /** What `type=` accepts on the metrics endpoint. */
19
+ export type UmamiMetricType = 'url' | 'path' | 'entry' | 'exit' | 'referrer' | 'title' | 'query' | 'browser' | 'os' | 'device' | 'country' | 'region' | 'city' | 'language' | 'event';
20
+ /** A window of time, as milliseconds since the epoch. */
21
+ export interface UmamiRange {
22
+ startAt: number;
23
+ endAt: number;
24
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miguelmorales13/nestkit",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -81,6 +81,11 @@
81
81
  "import": "./dist/auth/index.js",
82
82
  "require": "./dist/auth/index.cjs"
83
83
  },
84
+ "./auth/oauth": {
85
+ "types": "./dist/auth/oauth/index.d.ts",
86
+ "import": "./dist/auth/oauth/index.js",
87
+ "require": "./dist/auth/oauth/index.cjs"
88
+ },
84
89
  "./email/resend": {
85
90
  "types": "./dist/email/resend/index.d.ts",
86
91
  "import": "./dist/email/resend/index.js",
@@ -111,6 +116,11 @@
111
116
  "import": "./dist/media/index.js",
112
117
  "require": "./dist/media/index.cjs"
113
118
  },
119
+ "./umami": {
120
+ "types": "./dist/umami/index.d.ts",
121
+ "import": "./dist/umami/index.js",
122
+ "require": "./dist/umami/index.cjs"
123
+ },
114
124
  "./storage": {
115
125
  "types": "./dist/storage/index.d.ts",
116
126
  "import": "./dist/storage/index.js",