@nexpress/plugin-analytics-lite 0.2.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.d.ts +45 -0
- package/dist/index.js +197 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as _nexpress_plugin_sdk from '@nexpress/plugin-sdk';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
declare const configSchema: z.ZodObject<{
|
|
5
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
6
|
+
respectDoNotTrack: z.ZodDefault<z.ZodBoolean>;
|
|
7
|
+
sampleRate: z.ZodDefault<z.ZodNumber>;
|
|
8
|
+
scriptPath: z.ZodDefault<z.ZodString>;
|
|
9
|
+
retentionDays: z.ZodDefault<z.ZodNumber>;
|
|
10
|
+
}, z.core.$strip>;
|
|
11
|
+
type AnalyticsLiteConfig = z.infer<typeof configSchema>;
|
|
12
|
+
interface AnalyticsEventInput {
|
|
13
|
+
path?: unknown;
|
|
14
|
+
referrer?: unknown;
|
|
15
|
+
title?: unknown;
|
|
16
|
+
at?: unknown;
|
|
17
|
+
}
|
|
18
|
+
interface NormalizedAnalyticsEvent {
|
|
19
|
+
path: string;
|
|
20
|
+
referrer: string | null;
|
|
21
|
+
title: string | null;
|
|
22
|
+
at: string;
|
|
23
|
+
}
|
|
24
|
+
declare function previousUtcDay(date?: Date): Date;
|
|
25
|
+
declare function normalizeEvent(input: AnalyticsEventInput): NormalizedAnalyticsEvent;
|
|
26
|
+
declare function rollupEvents(events: NormalizedAnalyticsEvent[]): {
|
|
27
|
+
views: number;
|
|
28
|
+
topPaths: Array<{
|
|
29
|
+
path: string;
|
|
30
|
+
views: number;
|
|
31
|
+
}>;
|
|
32
|
+
referrers: Array<{
|
|
33
|
+
referrer: string;
|
|
34
|
+
views: number;
|
|
35
|
+
}>;
|
|
36
|
+
};
|
|
37
|
+
declare const analyticsLitePlugin: _nexpress_plugin_sdk.NpResolvedPlugin<{
|
|
38
|
+
enabled: boolean;
|
|
39
|
+
respectDoNotTrack: boolean;
|
|
40
|
+
sampleRate: number;
|
|
41
|
+
scriptPath: string;
|
|
42
|
+
retentionDays: number;
|
|
43
|
+
}>;
|
|
44
|
+
|
|
45
|
+
export { type AnalyticsEventInput, type AnalyticsLiteConfig, type NormalizedAnalyticsEvent, analyticsLitePlugin, analyticsLitePlugin as default, normalizeEvent, previousUtcDay, rollupEvents };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { definePlugin, npAdminMetric, npAdminTable } from "@nexpress/plugin-sdk";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
var configSchema = z.object({
|
|
5
|
+
enabled: z.boolean().default(true).describe("Enable analytics collection"),
|
|
6
|
+
respectDoNotTrack: z.boolean().default(true).describe("Respect Do Not Track"),
|
|
7
|
+
sampleRate: z.number().min(0).max(1).default(1).describe("Sampling rate"),
|
|
8
|
+
scriptPath: z.string().default("/api/plugins/analytics-lite/event").describe("Event endpoint"),
|
|
9
|
+
retentionDays: z.number().int().min(1).max(730).default(90).describe("Retention window")
|
|
10
|
+
});
|
|
11
|
+
var EVENT_PREFIX = "events:";
|
|
12
|
+
var ROLLUP_PREFIX = "rollups:";
|
|
13
|
+
function dayKey(date = /* @__PURE__ */ new Date()) {
|
|
14
|
+
return date.toISOString().slice(0, 10);
|
|
15
|
+
}
|
|
16
|
+
function eventKey(date = /* @__PURE__ */ new Date()) {
|
|
17
|
+
return `${EVENT_PREFIX}${dayKey(date)}:`;
|
|
18
|
+
}
|
|
19
|
+
function rollupKey(date = /* @__PURE__ */ new Date()) {
|
|
20
|
+
return `${ROLLUP_PREFIX}${dayKey(date)}`;
|
|
21
|
+
}
|
|
22
|
+
function previousUtcDay(date = /* @__PURE__ */ new Date()) {
|
|
23
|
+
const previous = new Date(date);
|
|
24
|
+
previous.setUTCDate(previous.getUTCDate() - 1);
|
|
25
|
+
return previous;
|
|
26
|
+
}
|
|
27
|
+
function cleanString(value, maxLength) {
|
|
28
|
+
if (typeof value !== "string") return null;
|
|
29
|
+
const trimmed = value.trim();
|
|
30
|
+
if (!trimmed) return null;
|
|
31
|
+
return trimmed.slice(0, maxLength);
|
|
32
|
+
}
|
|
33
|
+
function normalizeEvent(input) {
|
|
34
|
+
return {
|
|
35
|
+
path: cleanString(input.path, 2048) ?? "/",
|
|
36
|
+
referrer: cleanString(input.referrer, 2048),
|
|
37
|
+
title: cleanString(input.title, 300),
|
|
38
|
+
at: cleanString(input.at, 64) ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function rollupEvents(events) {
|
|
42
|
+
const paths = /* @__PURE__ */ new Map();
|
|
43
|
+
const referrers = /* @__PURE__ */ new Map();
|
|
44
|
+
for (const event of events) {
|
|
45
|
+
paths.set(event.path, (paths.get(event.path) ?? 0) + 1);
|
|
46
|
+
if (event.referrer) {
|
|
47
|
+
referrers.set(event.referrer, (referrers.get(event.referrer) ?? 0) + 1);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const sortCounts = (entries) => [...entries].sort((a, b) => b[1] - a[1]).slice(0, 10);
|
|
51
|
+
return {
|
|
52
|
+
views: events.length,
|
|
53
|
+
topPaths: sortCounts(paths.entries()).map(([path, views]) => ({ path, views })),
|
|
54
|
+
referrers: sortCounts(referrers.entries()).map(([referrer, views]) => ({
|
|
55
|
+
referrer,
|
|
56
|
+
views
|
|
57
|
+
}))
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
var analyticsLitePlugin = definePlugin({
|
|
61
|
+
manifest: {
|
|
62
|
+
id: "analytics-lite",
|
|
63
|
+
version: "0.1.0",
|
|
64
|
+
name: "Analytics Lite",
|
|
65
|
+
description: "Adds a tiny first-party analytics collector with a render hook, plugin route, scheduled rollup, and admin metrics.",
|
|
66
|
+
author: { name: "NexPress" },
|
|
67
|
+
license: "MIT",
|
|
68
|
+
nexpress: { minVersion: "0.1.0" },
|
|
69
|
+
allowedHosts: [],
|
|
70
|
+
agent: {
|
|
71
|
+
description: "First-party page view collection for small sites. Injects a small script, stores daily events in plugin storage, and rolls up top paths.",
|
|
72
|
+
category: "analytics",
|
|
73
|
+
tags: ["analytics", "render-hook", "scheduled-task", "storage"]
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
configSchema,
|
|
77
|
+
hooks: {
|
|
78
|
+
"render:afterPage": ({ ctx }) => {
|
|
79
|
+
if (!ctx.config.enabled) return void 0;
|
|
80
|
+
const script = [
|
|
81
|
+
"(() => {",
|
|
82
|
+
"try {",
|
|
83
|
+
ctx.config.respectDoNotTrack ? "if (navigator.doNotTrack === '1' || window.doNotTrack === '1') return;" : "",
|
|
84
|
+
`if (Math.random() > ${JSON.stringify(ctx.config.sampleRate)}) return;`,
|
|
85
|
+
`fetch(${JSON.stringify(ctx.config.scriptPath)}, {`,
|
|
86
|
+
"'method': 'POST',",
|
|
87
|
+
"'headers': { 'content-type': 'application/json' },",
|
|
88
|
+
"'keepalive': true,",
|
|
89
|
+
"'body': JSON.stringify({ path: location.pathname, referrer: document.referrer, title: document.title, at: new Date().toISOString() })",
|
|
90
|
+
"});",
|
|
91
|
+
"} catch {}",
|
|
92
|
+
"})();"
|
|
93
|
+
].join("");
|
|
94
|
+
return { bodyEnd: [{ tag: "script", children: script }] };
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
routes: [
|
|
98
|
+
{
|
|
99
|
+
method: "POST",
|
|
100
|
+
path: "/event",
|
|
101
|
+
description: "Collect a page-view event.",
|
|
102
|
+
handler: async (req, ctx) => {
|
|
103
|
+
if (!ctx.config.enabled) {
|
|
104
|
+
return { status: 204 };
|
|
105
|
+
}
|
|
106
|
+
const event = normalizeEvent(req.body && typeof req.body === "object" ? req.body : {});
|
|
107
|
+
await ctx.storage.append(eventKey(new Date(event.at)), event, {
|
|
108
|
+
ttl: ctx.config.retentionDays * 24 * 60 * 60
|
|
109
|
+
});
|
|
110
|
+
return { status: 202, body: { ok: true } };
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
method: "GET",
|
|
115
|
+
path: "/summary",
|
|
116
|
+
description: "Return today's analytics rollup.",
|
|
117
|
+
handler: async (_req, ctx) => {
|
|
118
|
+
const date = /* @__PURE__ */ new Date();
|
|
119
|
+
const rollup = await ctx.storage.get(rollupKey(date)) ?? rollupEvents(
|
|
120
|
+
(await ctx.storage.listValues(eventKey(date))).map(
|
|
121
|
+
(row) => row.value
|
|
122
|
+
)
|
|
123
|
+
);
|
|
124
|
+
return { status: 200, body: rollup };
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
],
|
|
128
|
+
scheduled: [
|
|
129
|
+
{
|
|
130
|
+
id: "daily-rollup",
|
|
131
|
+
cron: "5 0 * * *",
|
|
132
|
+
description: "Roll up the previous day's analytics events into summary counts.",
|
|
133
|
+
handler: async (ctx) => {
|
|
134
|
+
const date = previousUtcDay();
|
|
135
|
+
const events = (await ctx.storage.listValues(eventKey(date))).map(
|
|
136
|
+
(row) => row.value
|
|
137
|
+
);
|
|
138
|
+
await ctx.storage.set(rollupKey(date), rollupEvents(events), {
|
|
139
|
+
ttl: ctx.config.retentionDays * 24 * 60 * 60
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
],
|
|
144
|
+
admin: {
|
|
145
|
+
widgets: [
|
|
146
|
+
{
|
|
147
|
+
id: "today-views",
|
|
148
|
+
label: "Today's views",
|
|
149
|
+
kind: "metric",
|
|
150
|
+
actionId: "todayViews"
|
|
151
|
+
}
|
|
152
|
+
],
|
|
153
|
+
tables: [
|
|
154
|
+
{
|
|
155
|
+
id: "top-paths",
|
|
156
|
+
label: "Top paths today",
|
|
157
|
+
columns: [
|
|
158
|
+
{ name: "path", label: "Path" },
|
|
159
|
+
{ name: "views", label: "Views" }
|
|
160
|
+
],
|
|
161
|
+
rowsActionId: "topPaths",
|
|
162
|
+
emptyMessage: "No views collected today."
|
|
163
|
+
}
|
|
164
|
+
],
|
|
165
|
+
dashboardWidgets: [
|
|
166
|
+
{
|
|
167
|
+
id: "analytics-lite-today",
|
|
168
|
+
label: "Views today",
|
|
169
|
+
kind: "metric",
|
|
170
|
+
actionId: "todayViews",
|
|
171
|
+
priority: 30
|
|
172
|
+
}
|
|
173
|
+
]
|
|
174
|
+
},
|
|
175
|
+
setup: (ctx) => {
|
|
176
|
+
ctx.actions.registerMetric("todayViews", async () => {
|
|
177
|
+
const events = await ctx.storage.listValues(eventKey());
|
|
178
|
+
return npAdminMetric(events.length, `${dayKey()} local UTC key`);
|
|
179
|
+
});
|
|
180
|
+
ctx.actions.registerTable("topPaths", async () => {
|
|
181
|
+
const events = (await ctx.storage.listValues(eventKey())).map(
|
|
182
|
+
(row) => row.value
|
|
183
|
+
);
|
|
184
|
+
const rows = rollupEvents(events).topPaths;
|
|
185
|
+
return npAdminTable(rows);
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
var index_default = analyticsLitePlugin;
|
|
190
|
+
export {
|
|
191
|
+
analyticsLitePlugin,
|
|
192
|
+
index_default as default,
|
|
193
|
+
normalizeEvent,
|
|
194
|
+
previousUtcDay,
|
|
195
|
+
rollupEvents
|
|
196
|
+
};
|
|
197
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { definePlugin, npAdminMetric, npAdminTable } from \"@nexpress/plugin-sdk\";\nimport { z } from \"zod\";\n\nconst configSchema = z.object({\n enabled: z.boolean().default(true).describe(\"Enable analytics collection\"),\n respectDoNotTrack: z.boolean().default(true).describe(\"Respect Do Not Track\"),\n sampleRate: z.number().min(0).max(1).default(1).describe(\"Sampling rate\"),\n scriptPath: z.string().default(\"/api/plugins/analytics-lite/event\").describe(\"Event endpoint\"),\n retentionDays: z.number().int().min(1).max(730).default(90).describe(\"Retention window\"),\n});\n\nexport type AnalyticsLiteConfig = z.infer<typeof configSchema>;\n\nexport interface AnalyticsEventInput {\n path?: unknown;\n referrer?: unknown;\n title?: unknown;\n at?: unknown;\n}\n\nexport interface NormalizedAnalyticsEvent {\n path: string;\n referrer: string | null;\n title: string | null;\n at: string;\n}\n\nconst EVENT_PREFIX = \"events:\";\nconst ROLLUP_PREFIX = \"rollups:\";\n\nfunction dayKey(date = new Date()): string {\n return date.toISOString().slice(0, 10);\n}\n\nfunction eventKey(date = new Date()): string {\n return `${EVENT_PREFIX}${dayKey(date)}:`;\n}\n\nfunction rollupKey(date = new Date()): string {\n return `${ROLLUP_PREFIX}${dayKey(date)}`;\n}\n\nexport function previousUtcDay(date = new Date()): Date {\n const previous = new Date(date);\n previous.setUTCDate(previous.getUTCDate() - 1);\n return previous;\n}\n\nfunction cleanString(value: unknown, maxLength: number): string | null {\n if (typeof value !== \"string\") return null;\n const trimmed = value.trim();\n if (!trimmed) return null;\n return trimmed.slice(0, maxLength);\n}\n\nexport function normalizeEvent(input: AnalyticsEventInput): NormalizedAnalyticsEvent {\n return {\n path: cleanString(input.path, 2048) ?? \"/\",\n referrer: cleanString(input.referrer, 2048),\n title: cleanString(input.title, 300),\n at: cleanString(input.at, 64) ?? new Date().toISOString(),\n };\n}\n\nexport function rollupEvents(events: NormalizedAnalyticsEvent[]): {\n views: number;\n topPaths: Array<{ path: string; views: number }>;\n referrers: Array<{ referrer: string; views: number }>;\n} {\n const paths = new Map<string, number>();\n const referrers = new Map<string, number>();\n\n for (const event of events) {\n paths.set(event.path, (paths.get(event.path) ?? 0) + 1);\n if (event.referrer) {\n referrers.set(event.referrer, (referrers.get(event.referrer) ?? 0) + 1);\n }\n }\n\n const sortCounts = (entries: IterableIterator<[string, number]>) =>\n [...entries].sort((a, b) => b[1] - a[1]).slice(0, 10);\n\n return {\n views: events.length,\n topPaths: sortCounts(paths.entries()).map(([path, views]) => ({ path, views })),\n referrers: sortCounts(referrers.entries()).map(([referrer, views]) => ({\n referrer,\n views,\n })),\n };\n}\n\nexport const analyticsLitePlugin = definePlugin<AnalyticsLiteConfig>({\n manifest: {\n id: \"analytics-lite\",\n version: \"0.1.0\",\n name: \"Analytics Lite\",\n description:\n \"Adds a tiny first-party analytics collector with a render hook, plugin route, scheduled rollup, and admin metrics.\",\n author: { name: \"NexPress\" },\n license: \"MIT\",\n nexpress: { minVersion: \"0.1.0\" },\n allowedHosts: [],\n agent: {\n description:\n \"First-party page view collection for small sites. Injects a small script, stores daily events in plugin storage, and rolls up top paths.\",\n category: \"analytics\",\n tags: [\"analytics\", \"render-hook\", \"scheduled-task\", \"storage\"],\n },\n },\n configSchema,\n hooks: {\n \"render:afterPage\": ({ ctx }) => {\n if (!ctx.config.enabled) return undefined;\n\n const script = [\n \"(() => {\",\n \"try {\",\n ctx.config.respectDoNotTrack\n ? \"if (navigator.doNotTrack === '1' || window.doNotTrack === '1') return;\"\n : \"\",\n `if (Math.random() > ${JSON.stringify(ctx.config.sampleRate)}) return;`,\n `fetch(${JSON.stringify(ctx.config.scriptPath)}, {`,\n \"'method': 'POST',\",\n \"'headers': { 'content-type': 'application/json' },\",\n \"'keepalive': true,\",\n \"'body': JSON.stringify({ path: location.pathname, referrer: document.referrer, title: document.title, at: new Date().toISOString() })\",\n \"});\",\n \"} catch {}\",\n \"})();\",\n ].join(\"\");\n\n return { bodyEnd: [{ tag: \"script\", children: script }] };\n },\n },\n routes: [\n {\n method: \"POST\",\n path: \"/event\",\n description: \"Collect a page-view event.\",\n handler: async (req, ctx) => {\n if (!ctx.config.enabled) {\n return { status: 204 };\n }\n\n const event = normalizeEvent(req.body && typeof req.body === \"object\" ? req.body : {});\n await ctx.storage.append(eventKey(new Date(event.at)), event, {\n ttl: ctx.config.retentionDays * 24 * 60 * 60,\n });\n\n return { status: 202, body: { ok: true } };\n },\n },\n {\n method: \"GET\",\n path: \"/summary\",\n description: \"Return today's analytics rollup.\",\n handler: async (_req, ctx) => {\n const date = new Date();\n const rollup =\n (await ctx.storage.get<ReturnType<typeof rollupEvents>>(rollupKey(date))) ??\n rollupEvents(\n (await ctx.storage.listValues<NormalizedAnalyticsEvent>(eventKey(date))).map(\n (row) => row.value,\n ),\n );\n\n return { status: 200, body: rollup };\n },\n },\n ],\n scheduled: [\n {\n id: \"daily-rollup\",\n cron: \"5 0 * * *\",\n description: \"Roll up the previous day's analytics events into summary counts.\",\n handler: async (ctx) => {\n const date = previousUtcDay();\n const events = (await ctx.storage.listValues<NormalizedAnalyticsEvent>(eventKey(date))).map(\n (row) => row.value,\n );\n await ctx.storage.set(rollupKey(date), rollupEvents(events), {\n ttl: ctx.config.retentionDays * 24 * 60 * 60,\n });\n },\n },\n ],\n admin: {\n widgets: [\n {\n id: \"today-views\",\n label: \"Today's views\",\n kind: \"metric\",\n actionId: \"todayViews\",\n },\n ],\n tables: [\n {\n id: \"top-paths\",\n label: \"Top paths today\",\n columns: [\n { name: \"path\", label: \"Path\" },\n { name: \"views\", label: \"Views\" },\n ],\n rowsActionId: \"topPaths\",\n emptyMessage: \"No views collected today.\",\n },\n ],\n dashboardWidgets: [\n {\n id: \"analytics-lite-today\",\n label: \"Views today\",\n kind: \"metric\",\n actionId: \"todayViews\",\n priority: 30,\n },\n ],\n },\n setup: (ctx) => {\n ctx.actions.registerMetric(\"todayViews\", async () => {\n const events = await ctx.storage.listValues<NormalizedAnalyticsEvent>(eventKey());\n return npAdminMetric(events.length, `${dayKey()} local UTC key`);\n });\n\n ctx.actions.registerTable(\"topPaths\", async () => {\n const events = (await ctx.storage.listValues<NormalizedAnalyticsEvent>(eventKey())).map(\n (row) => row.value,\n );\n const rows = rollupEvents(events).topPaths;\n return npAdminTable(rows);\n });\n },\n});\n\nexport default analyticsLitePlugin;\n"],"mappings":";AAAA,SAAS,cAAc,eAAe,oBAAoB;AAC1D,SAAS,SAAS;AAElB,IAAM,eAAe,EAAE,OAAO;AAAA,EAC5B,SAAS,EAAE,QAAQ,EAAE,QAAQ,IAAI,EAAE,SAAS,6BAA6B;AAAA,EACzE,mBAAmB,EAAE,QAAQ,EAAE,QAAQ,IAAI,EAAE,SAAS,sBAAsB;AAAA,EAC5E,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC,EAAE,SAAS,eAAe;AAAA,EACxE,YAAY,EAAE,OAAO,EAAE,QAAQ,mCAAmC,EAAE,SAAS,gBAAgB;AAAA,EAC7F,eAAe,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,QAAQ,EAAE,EAAE,SAAS,kBAAkB;AACzF,CAAC;AAkBD,IAAM,eAAe;AACrB,IAAM,gBAAgB;AAEtB,SAAS,OAAO,OAAO,oBAAI,KAAK,GAAW;AACzC,SAAO,KAAK,YAAY,EAAE,MAAM,GAAG,EAAE;AACvC;AAEA,SAAS,SAAS,OAAO,oBAAI,KAAK,GAAW;AAC3C,SAAO,GAAG,YAAY,GAAG,OAAO,IAAI,CAAC;AACvC;AAEA,SAAS,UAAU,OAAO,oBAAI,KAAK,GAAW;AAC5C,SAAO,GAAG,aAAa,GAAG,OAAO,IAAI,CAAC;AACxC;AAEO,SAAS,eAAe,OAAO,oBAAI,KAAK,GAAS;AACtD,QAAM,WAAW,IAAI,KAAK,IAAI;AAC9B,WAAS,WAAW,SAAS,WAAW,IAAI,CAAC;AAC7C,SAAO;AACT;AAEA,SAAS,YAAY,OAAgB,WAAkC;AACrE,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,QAAQ,MAAM,GAAG,SAAS;AACnC;AAEO,SAAS,eAAe,OAAsD;AACnF,SAAO;AAAA,IACL,MAAM,YAAY,MAAM,MAAM,IAAI,KAAK;AAAA,IACvC,UAAU,YAAY,MAAM,UAAU,IAAI;AAAA,IAC1C,OAAO,YAAY,MAAM,OAAO,GAAG;AAAA,IACnC,IAAI,YAAY,MAAM,IAAI,EAAE,MAAK,oBAAI,KAAK,GAAE,YAAY;AAAA,EAC1D;AACF;AAEO,SAAS,aAAa,QAI3B;AACA,QAAM,QAAQ,oBAAI,IAAoB;AACtC,QAAM,YAAY,oBAAI,IAAoB;AAE1C,aAAW,SAAS,QAAQ;AAC1B,UAAM,IAAI,MAAM,OAAO,MAAM,IAAI,MAAM,IAAI,KAAK,KAAK,CAAC;AACtD,QAAI,MAAM,UAAU;AAClB,gBAAU,IAAI,MAAM,WAAW,UAAU,IAAI,MAAM,QAAQ,KAAK,KAAK,CAAC;AAAA,IACxE;AAAA,EACF;AAEA,QAAM,aAAa,CAAC,YAClB,CAAC,GAAG,OAAO,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,EAAE;AAEtD,SAAO;AAAA,IACL,OAAO,OAAO;AAAA,IACd,UAAU,WAAW,MAAM,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,MAAM,KAAK,OAAO,EAAE,MAAM,MAAM,EAAE;AAAA,IAC9E,WAAW,WAAW,UAAU,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,UAAU,KAAK,OAAO;AAAA,MACrE;AAAA,MACA;AAAA,IACF,EAAE;AAAA,EACJ;AACF;AAEO,IAAM,sBAAsB,aAAkC;AAAA,EACnE,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,MAAM;AAAA,IACN,aACE;AAAA,IACF,QAAQ,EAAE,MAAM,WAAW;AAAA,IAC3B,SAAS;AAAA,IACT,UAAU,EAAE,YAAY,QAAQ;AAAA,IAChC,cAAc,CAAC;AAAA,IACf,OAAO;AAAA,MACL,aACE;AAAA,MACF,UAAU;AAAA,MACV,MAAM,CAAC,aAAa,eAAe,kBAAkB,SAAS;AAAA,IAChE;AAAA,EACF;AAAA,EACA;AAAA,EACA,OAAO;AAAA,IACL,oBAAoB,CAAC,EAAE,IAAI,MAAM;AAC/B,UAAI,CAAC,IAAI,OAAO,QAAS,QAAO;AAEhC,YAAM,SAAS;AAAA,QACb;AAAA,QACA;AAAA,QACA,IAAI,OAAO,oBACP,2EACA;AAAA,QACJ,uBAAuB,KAAK,UAAU,IAAI,OAAO,UAAU,CAAC;AAAA,QAC5D,SAAS,KAAK,UAAU,IAAI,OAAO,UAAU,CAAC;AAAA,QAC9C;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,EAAE;AAET,aAAO,EAAE,SAAS,CAAC,EAAE,KAAK,UAAU,UAAU,OAAO,CAAC,EAAE;AAAA,IAC1D;AAAA,EACF;AAAA,EACA,QAAQ;AAAA,IACN;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS,OAAO,KAAK,QAAQ;AAC3B,YAAI,CAAC,IAAI,OAAO,SAAS;AACvB,iBAAO,EAAE,QAAQ,IAAI;AAAA,QACvB;AAEA,cAAM,QAAQ,eAAe,IAAI,QAAQ,OAAO,IAAI,SAAS,WAAW,IAAI,OAAO,CAAC,CAAC;AACrF,cAAM,IAAI,QAAQ,OAAO,SAAS,IAAI,KAAK,MAAM,EAAE,CAAC,GAAG,OAAO;AAAA,UAC5D,KAAK,IAAI,OAAO,gBAAgB,KAAK,KAAK;AAAA,QAC5C,CAAC;AAED,eAAO,EAAE,QAAQ,KAAK,MAAM,EAAE,IAAI,KAAK,EAAE;AAAA,MAC3C;AAAA,IACF;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS,OAAO,MAAM,QAAQ;AAC5B,cAAM,OAAO,oBAAI,KAAK;AACtB,cAAM,SACH,MAAM,IAAI,QAAQ,IAAqC,UAAU,IAAI,CAAC,KACvE;AAAA,WACG,MAAM,IAAI,QAAQ,WAAqC,SAAS,IAAI,CAAC,GAAG;AAAA,YACvE,CAAC,QAAQ,IAAI;AAAA,UACf;AAAA,QACF;AAEF,eAAO,EAAE,QAAQ,KAAK,MAAM,OAAO;AAAA,MACrC;AAAA,IACF;AAAA,EACF;AAAA,EACA,WAAW;AAAA,IACT;AAAA,MACE,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS,OAAO,QAAQ;AACtB,cAAM,OAAO,eAAe;AAC5B,cAAM,UAAU,MAAM,IAAI,QAAQ,WAAqC,SAAS,IAAI,CAAC,GAAG;AAAA,UACtF,CAAC,QAAQ,IAAI;AAAA,QACf;AACA,cAAM,IAAI,QAAQ,IAAI,UAAU,IAAI,GAAG,aAAa,MAAM,GAAG;AAAA,UAC3D,KAAK,IAAI,OAAO,gBAAgB,KAAK,KAAK;AAAA,QAC5C,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA,EACA,OAAO;AAAA,IACL,SAAS;AAAA,MACP;AAAA,QACE,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,MAAM;AAAA,QACN,UAAU;AAAA,MACZ;AAAA,IACF;AAAA,IACA,QAAQ;AAAA,MACN;AAAA,QACE,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,SAAS;AAAA,UACP,EAAE,MAAM,QAAQ,OAAO,OAAO;AAAA,UAC9B,EAAE,MAAM,SAAS,OAAO,QAAQ;AAAA,QAClC;AAAA,QACA,cAAc;AAAA,QACd,cAAc;AAAA,MAChB;AAAA,IACF;AAAA,IACA,kBAAkB;AAAA,MAChB;AAAA,QACE,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,MAAM;AAAA,QACN,UAAU;AAAA,QACV,UAAU;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAAA,EACA,OAAO,CAAC,QAAQ;AACd,QAAI,QAAQ,eAAe,cAAc,YAAY;AACnD,YAAM,SAAS,MAAM,IAAI,QAAQ,WAAqC,SAAS,CAAC;AAChF,aAAO,cAAc,OAAO,QAAQ,GAAG,OAAO,CAAC,gBAAgB;AAAA,IACjE,CAAC;AAED,QAAI,QAAQ,cAAc,YAAY,YAAY;AAChD,YAAM,UAAU,MAAM,IAAI,QAAQ,WAAqC,SAAS,CAAC,GAAG;AAAA,QAClF,CAAC,QAAQ,IAAI;AAAA,MACf;AACA,YAAM,OAAO,aAAa,MAAM,EAAE;AAClC,aAAO,aAAa,IAAI;AAAA,IAC1B,CAAC;AAAA,EACH;AACF,CAAC;AAED,IAAO,gBAAQ;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nexpress/plugin-analytics-lite",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "First-party lightweight analytics plugin for NexPress.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Nexpress",
|
|
7
|
+
"homepage": "https://github.com/nexpress-cms/nexpress#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/nexpress-cms/nexpress.git",
|
|
11
|
+
"directory": "packages/plugins/analytics-lite"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/nexpress-cms/nexpress/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"nexpress",
|
|
18
|
+
"plugin",
|
|
19
|
+
"analytics"
|
|
20
|
+
],
|
|
21
|
+
"type": "module",
|
|
22
|
+
"main": "./dist/index.js",
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"import": "./dist/index.js",
|
|
28
|
+
"default": "./dist/index.js"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist"
|
|
33
|
+
],
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=20"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@nexpress/plugin-sdk": "workspace:*",
|
|
39
|
+
"zod": "^4.4.3"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/node": "^22.0.0",
|
|
43
|
+
"tsup": "^8.5.0",
|
|
44
|
+
"typescript": "^5.8.0",
|
|
45
|
+
"vitest": "^4.1.6"
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "tsup",
|
|
49
|
+
"dev": "tsup --watch --no-clean",
|
|
50
|
+
"clean": "rm -rf dist",
|
|
51
|
+
"typecheck": "tsc --noEmit",
|
|
52
|
+
"test": "vitest run",
|
|
53
|
+
"lint": "eslint . --cache --cache-location node_modules/.cache/eslint"
|
|
54
|
+
}
|
|
55
|
+
}
|