@miguelmorales13/nestkit 0.5.0 → 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.
- package/README.md +81 -2
- package/dist/auth/index.cjs +12 -70
- package/dist/auth/index.js +11 -69
- package/dist/auth/oauth/http.d.ts +38 -0
- package/dist/auth/oauth/index.cjs +610 -0
- package/dist/auth/oauth/index.d.ts +12 -0
- package/dist/auth/oauth/index.js +610 -0
- package/dist/auth/oauth/oauth-auth.module.d.ts +28 -0
- package/dist/auth/oauth/oauth-auth.service.d.ts +101 -0
- package/dist/auth/oauth/oauth-callback.filter.d.ts +20 -0
- package/dist/auth/oauth/oauth-provider.d.ts +73 -0
- package/dist/auth/oauth/oauth.controller.d.ts +38 -0
- package/dist/auth/oauth/oauth.options.d.ts +89 -0
- package/dist/auth/oauth/oauth.ports.d.ts +86 -0
- package/dist/chunk-A3B2EY4V.js +75 -0
- package/dist/chunk-NVCI3CQI.cjs +75 -0
- package/dist/index.cjs +10 -10
- package/dist/index.js +11 -11
- package/dist/umami/index.cjs +109 -0
- package/dist/umami/index.d.ts +4 -0
- package/dist/umami/index.js +109 -0
- package/dist/umami/umami.module.d.ts +6 -0
- package/dist/umami/umami.options.d.ts +20 -0
- package/dist/umami/umami.service.d.ts +40 -0
- package/dist/umami/umami.types.d.ts +24 -0
- package/package.json +15 -1
|
@@ -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,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.
|
|
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",
|
|
@@ -213,5 +223,9 @@
|
|
|
213
223
|
"telegraf": "^4.16.3",
|
|
214
224
|
"tsup": "^8.5.1",
|
|
215
225
|
"typescript": "^5.6.0"
|
|
226
|
+
},
|
|
227
|
+
"overrides": {
|
|
228
|
+
"@nestjs/common": "11.2.3",
|
|
229
|
+
"@nestjs/core": "11.2.3"
|
|
216
230
|
}
|
|
217
231
|
}
|