@safaricom-mxl/nuxthub 0.0.3
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 +61 -0
- package/dist/module.d.mts +5 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +91 -0
- package/dist/runtime/api/_cron/mxllog-cleanup.d.ts +5 -0
- package/dist/runtime/api/_cron/mxllog-cleanup.js +13 -0
- package/dist/runtime/db/schema/events.mysql.d.ts +245 -0
- package/dist/runtime/db/schema/events.mysql.js +24 -0
- package/dist/runtime/db/schema/events.postgresql.d.ts +245 -0
- package/dist/runtime/db/schema/events.postgresql.js +24 -0
- package/dist/runtime/db/schema/events.sqlite.d.ts +269 -0
- package/dist/runtime/db/schema/events.sqlite.js +24 -0
- package/dist/runtime/drain.d.ts +2 -0
- package/dist/runtime/drain.js +107 -0
- package/dist/runtime/tasks/evlog-cleanup.d.ts +2 -0
- package/dist/runtime/tasks/evlog-cleanup.js +24 -0
- package/dist/runtime/utils/retention.d.ts +7 -0
- package/dist/runtime/utils/retention.js +51 -0
- package/dist/types.d.mts +7 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# @safaricom-mxl/nuxthub
|
|
2
|
+
|
|
3
|
+
[](https://npmjs.com/package/@safaricom-mxl/nuxthub)
|
|
4
|
+
[](https://npm.chart.dev/@safaricom-mxl/nuxthub)
|
|
5
|
+
[](https://github.com/HugoRCD/mxllog/actions/workflows/ci.yml)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
[](https://nuxt.com/)
|
|
8
|
+
[](https://mxllog.dev)
|
|
9
|
+
[](https://github.com/HugoRCD/mxllog/blob/main/LICENSE)
|
|
10
|
+
|
|
11
|
+
Self-hosted log retention for [mxllog](https://mxllog.dev) using [NuxtHub](https://hub.nuxt.com) database storage. Store, query, and automatically clean up your structured logs with zero external dependencies.
|
|
12
|
+
|
|
13
|
+
## Setup
|
|
14
|
+
|
|
15
|
+
Install the packages:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx nuxi module add @nuxthub/core @safaricom-mxl/nuxthub
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Add the module to your `nuxt.config.ts`:
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
export default defineNuxtConfig({
|
|
25
|
+
modules: ['@nuxthub/core', '@safaricom-mxl/nuxthub'],
|
|
26
|
+
|
|
27
|
+
mxllog: {
|
|
28
|
+
retention: '7d',
|
|
29
|
+
},
|
|
30
|
+
})
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
> `@safaricom-mxl/log/nuxt` and `@nuxthub/core` can be auto-installed if missing, but we recommend installing `@nuxthub/core` explicitly and registering it in `modules`.
|
|
34
|
+
|
|
35
|
+
## Configuration
|
|
36
|
+
|
|
37
|
+
| Option | Type | Default | Description |
|
|
38
|
+
| --- | --- | --- | --- |
|
|
39
|
+
| `retention` | `string` | `'7d'` | How long to keep events. Accepts `d` (days), `h` (hours), or `m` (minutes). |
|
|
40
|
+
|
|
41
|
+
The cleanup cron schedule is automatically derived from the retention value.
|
|
42
|
+
|
|
43
|
+
## Database Support
|
|
44
|
+
|
|
45
|
+
NuxtHub supports multiple database dialects. The `mxllog_events` table schema is automatically registered for:
|
|
46
|
+
|
|
47
|
+
- **SQLite** (default for Cloudflare D1)
|
|
48
|
+
- **MySQL**
|
|
49
|
+
- **PostgreSQL**
|
|
50
|
+
|
|
51
|
+
## Deployment
|
|
52
|
+
|
|
53
|
+
For Vercel deployments, the module can create a `vercel.json` with the appropriate cron schedule during `nuxi module add`. For Cloudflare and other platforms, the Nitro scheduled task handles cleanup automatically.
|
|
54
|
+
|
|
55
|
+
## Documentation
|
|
56
|
+
|
|
57
|
+
[Full documentation](https://mxllog.dev)
|
|
58
|
+
|
|
59
|
+
## License
|
|
60
|
+
|
|
61
|
+
[MIT](https://github.com/HugoRCD/mxllog/blob/main/LICENSE)
|
package/dist/module.json
ADDED
package/dist/module.mjs
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { existsSync, promises } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { defineNuxtModule, createResolver, hasNuxtModule, installModule, addTypeTemplate, addServerPlugin, addServerHandler } from '@nuxt/kit';
|
|
4
|
+
import { consola } from 'consola';
|
|
5
|
+
import { retentionToCron } from '../dist/runtime/utils/retention.js';
|
|
6
|
+
|
|
7
|
+
const name = "@safaricom-mxl/nuxthub";
|
|
8
|
+
const version = "0.0.3";
|
|
9
|
+
|
|
10
|
+
const module$1 = defineNuxtModule({
|
|
11
|
+
meta: {
|
|
12
|
+
name,
|
|
13
|
+
version
|
|
14
|
+
},
|
|
15
|
+
async onInstall(nuxt) {
|
|
16
|
+
const shouldSetup = await consola.prompt(
|
|
17
|
+
"Do you want to create a vercel.json with a cron schedule for mxllog cleanup?",
|
|
18
|
+
{ type: "confirm", initial: false }
|
|
19
|
+
);
|
|
20
|
+
if (typeof shouldSetup !== "boolean" || !shouldSetup) return;
|
|
21
|
+
const vercelJsonPath = resolve(nuxt.options.rootDir, "vercel.json");
|
|
22
|
+
let config = {};
|
|
23
|
+
if (existsSync(vercelJsonPath)) {
|
|
24
|
+
config = JSON.parse(await promises.readFile(vercelJsonPath, "utf-8"));
|
|
25
|
+
}
|
|
26
|
+
const mxllogConfig = nuxt.options.mxllog || {};
|
|
27
|
+
const retention = mxllogConfig.retention ?? "7d";
|
|
28
|
+
const cron = retentionToCron(retention);
|
|
29
|
+
const crons = config.crons || [];
|
|
30
|
+
const existing = crons.findIndex((c) => c.path === "/api/_cron/mxllog-cleanup");
|
|
31
|
+
if (existing >= 0) {
|
|
32
|
+
crons[existing].schedule = cron;
|
|
33
|
+
} else {
|
|
34
|
+
crons.push({ path: "/api/_cron/mxllog-cleanup", schedule: cron });
|
|
35
|
+
}
|
|
36
|
+
config.crons = crons;
|
|
37
|
+
await promises.writeFile(vercelJsonPath, `${JSON.stringify(config, null, 2)}
|
|
38
|
+
`, "utf-8");
|
|
39
|
+
consola.success("Created vercel.json with mxllog cleanup cron schedule");
|
|
40
|
+
},
|
|
41
|
+
async setup(_moduleOptions, nuxt) {
|
|
42
|
+
const { resolve: resolve2 } = createResolver(import.meta.url);
|
|
43
|
+
if (!hasNuxtModule("@safaricom-mxl/log/nuxt")) {
|
|
44
|
+
await installModule("@safaricom-mxl/log/nuxt");
|
|
45
|
+
}
|
|
46
|
+
if (!hasNuxtModule("@nuxthub/core")) {
|
|
47
|
+
await installModule("@nuxthub/core");
|
|
48
|
+
}
|
|
49
|
+
addTypeTemplate({
|
|
50
|
+
filename: "types/mxllog-nuxthub.d.ts",
|
|
51
|
+
getContents: () => [
|
|
52
|
+
"declare module '@safaricom-mxl/log/nuxt' {",
|
|
53
|
+
" interface ModuleOptions {",
|
|
54
|
+
" retention?: string",
|
|
55
|
+
" }",
|
|
56
|
+
"}",
|
|
57
|
+
"export {}"
|
|
58
|
+
].join("\n")
|
|
59
|
+
});
|
|
60
|
+
const mxllogConfig = nuxt.options.mxllog || {};
|
|
61
|
+
const retention = mxllogConfig.retention ?? "7d";
|
|
62
|
+
nuxt.hook("hub:db:schema:extend", ({ dialect, paths }) => {
|
|
63
|
+
paths.push(resolve2(`./runtime/db/schema/events.${dialect}`));
|
|
64
|
+
});
|
|
65
|
+
addServerPlugin(resolve2("./runtime/drain"));
|
|
66
|
+
addServerHandler({
|
|
67
|
+
route: "/api/_cron/mxllog-cleanup",
|
|
68
|
+
handler: resolve2("./runtime/api/_cron/mxllog-cleanup")
|
|
69
|
+
});
|
|
70
|
+
nuxt.hook("nitro:config", (nitroConfig) => {
|
|
71
|
+
nitroConfig.experimental = nitroConfig.experimental || {};
|
|
72
|
+
nitroConfig.experimental.tasks = true;
|
|
73
|
+
nitroConfig.tasks = nitroConfig.tasks || {};
|
|
74
|
+
nitroConfig.tasks["@safaricom-mxl/log:cleanup"] = {
|
|
75
|
+
handler: resolve2("./runtime/tasks/mxllog-cleanup")
|
|
76
|
+
};
|
|
77
|
+
const cron = retentionToCron(retention);
|
|
78
|
+
nitroConfig.scheduledTasks = nitroConfig.scheduledTasks || {};
|
|
79
|
+
const existing = nitroConfig.scheduledTasks[cron];
|
|
80
|
+
if (Array.isArray(existing)) {
|
|
81
|
+
existing.push("@safaricom-mxl/log:cleanup");
|
|
82
|
+
} else if (existing) {
|
|
83
|
+
nitroConfig.scheduledTasks[cron] = [existing, "@safaricom-mxl/log:cleanup"];
|
|
84
|
+
} else {
|
|
85
|
+
nitroConfig.scheduledTasks[cron] = ["@safaricom-mxl/log:cleanup"];
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
export { module$1 as default };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { runTask } from "nitropack/runtime";
|
|
2
|
+
import { eventHandler, getHeader, createError } from "h3";
|
|
3
|
+
export default eventHandler(async (event) => {
|
|
4
|
+
const cronSecret = process.env.CRON_SECRET;
|
|
5
|
+
if (cronSecret) {
|
|
6
|
+
const authorization = getHeader(event, "authorization");
|
|
7
|
+
if (authorization !== `Bearer ${cronSecret}`) {
|
|
8
|
+
throw createError({ statusCode: 401, statusMessage: "Unauthorized" });
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
const result = await runTask("@safaricom-mxl/log:cleanup");
|
|
12
|
+
return { success: true, ...result };
|
|
13
|
+
});
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
export declare const mxllogEvents: import("drizzle-orm/mysql-core").MySqlTableWithColumns<{
|
|
2
|
+
name: "mxllog_events";
|
|
3
|
+
schema: undefined;
|
|
4
|
+
columns: {
|
|
5
|
+
id: import("drizzle-orm/mysql-core").MySqlColumn<{
|
|
6
|
+
name: "id";
|
|
7
|
+
tableName: "mxllog_events";
|
|
8
|
+
dataType: "string";
|
|
9
|
+
columnType: "MySqlText";
|
|
10
|
+
data: string;
|
|
11
|
+
driverParam: string;
|
|
12
|
+
notNull: true;
|
|
13
|
+
hasDefault: false;
|
|
14
|
+
isPrimaryKey: true;
|
|
15
|
+
isAutoincrement: false;
|
|
16
|
+
hasRuntimeDefault: false;
|
|
17
|
+
enumValues: [string, ...string[]];
|
|
18
|
+
baseColumn: never;
|
|
19
|
+
identity: undefined;
|
|
20
|
+
generated: undefined;
|
|
21
|
+
}, {}, {}>;
|
|
22
|
+
timestamp: import("drizzle-orm/mysql-core").MySqlColumn<{
|
|
23
|
+
name: "timestamp";
|
|
24
|
+
tableName: "mxllog_events";
|
|
25
|
+
dataType: "string";
|
|
26
|
+
columnType: "MySqlText";
|
|
27
|
+
data: string;
|
|
28
|
+
driverParam: string;
|
|
29
|
+
notNull: true;
|
|
30
|
+
hasDefault: false;
|
|
31
|
+
isPrimaryKey: false;
|
|
32
|
+
isAutoincrement: false;
|
|
33
|
+
hasRuntimeDefault: false;
|
|
34
|
+
enumValues: [string, ...string[]];
|
|
35
|
+
baseColumn: never;
|
|
36
|
+
identity: undefined;
|
|
37
|
+
generated: undefined;
|
|
38
|
+
}, {}, {}>;
|
|
39
|
+
level: import("drizzle-orm/mysql-core").MySqlColumn<{
|
|
40
|
+
name: "level";
|
|
41
|
+
tableName: "mxllog_events";
|
|
42
|
+
dataType: "string";
|
|
43
|
+
columnType: "MySqlText";
|
|
44
|
+
data: string;
|
|
45
|
+
driverParam: string;
|
|
46
|
+
notNull: true;
|
|
47
|
+
hasDefault: false;
|
|
48
|
+
isPrimaryKey: false;
|
|
49
|
+
isAutoincrement: false;
|
|
50
|
+
hasRuntimeDefault: false;
|
|
51
|
+
enumValues: [string, ...string[]];
|
|
52
|
+
baseColumn: never;
|
|
53
|
+
identity: undefined;
|
|
54
|
+
generated: undefined;
|
|
55
|
+
}, {}, {}>;
|
|
56
|
+
service: import("drizzle-orm/mysql-core").MySqlColumn<{
|
|
57
|
+
name: "service";
|
|
58
|
+
tableName: "mxllog_events";
|
|
59
|
+
dataType: "string";
|
|
60
|
+
columnType: "MySqlText";
|
|
61
|
+
data: string;
|
|
62
|
+
driverParam: string;
|
|
63
|
+
notNull: true;
|
|
64
|
+
hasDefault: false;
|
|
65
|
+
isPrimaryKey: false;
|
|
66
|
+
isAutoincrement: false;
|
|
67
|
+
hasRuntimeDefault: false;
|
|
68
|
+
enumValues: [string, ...string[]];
|
|
69
|
+
baseColumn: never;
|
|
70
|
+
identity: undefined;
|
|
71
|
+
generated: undefined;
|
|
72
|
+
}, {}, {}>;
|
|
73
|
+
environment: import("drizzle-orm/mysql-core").MySqlColumn<{
|
|
74
|
+
name: "environment";
|
|
75
|
+
tableName: "mxllog_events";
|
|
76
|
+
dataType: "string";
|
|
77
|
+
columnType: "MySqlText";
|
|
78
|
+
data: string;
|
|
79
|
+
driverParam: string;
|
|
80
|
+
notNull: true;
|
|
81
|
+
hasDefault: false;
|
|
82
|
+
isPrimaryKey: false;
|
|
83
|
+
isAutoincrement: false;
|
|
84
|
+
hasRuntimeDefault: false;
|
|
85
|
+
enumValues: [string, ...string[]];
|
|
86
|
+
baseColumn: never;
|
|
87
|
+
identity: undefined;
|
|
88
|
+
generated: undefined;
|
|
89
|
+
}, {}, {}>;
|
|
90
|
+
method: import("drizzle-orm/mysql-core").MySqlColumn<{
|
|
91
|
+
name: "method";
|
|
92
|
+
tableName: "mxllog_events";
|
|
93
|
+
dataType: "string";
|
|
94
|
+
columnType: "MySqlText";
|
|
95
|
+
data: string;
|
|
96
|
+
driverParam: string;
|
|
97
|
+
notNull: false;
|
|
98
|
+
hasDefault: false;
|
|
99
|
+
isPrimaryKey: false;
|
|
100
|
+
isAutoincrement: false;
|
|
101
|
+
hasRuntimeDefault: false;
|
|
102
|
+
enumValues: [string, ...string[]];
|
|
103
|
+
baseColumn: never;
|
|
104
|
+
identity: undefined;
|
|
105
|
+
generated: undefined;
|
|
106
|
+
}, {}, {}>;
|
|
107
|
+
path: import("drizzle-orm/mysql-core").MySqlColumn<{
|
|
108
|
+
name: "path";
|
|
109
|
+
tableName: "mxllog_events";
|
|
110
|
+
dataType: "string";
|
|
111
|
+
columnType: "MySqlText";
|
|
112
|
+
data: string;
|
|
113
|
+
driverParam: string;
|
|
114
|
+
notNull: false;
|
|
115
|
+
hasDefault: false;
|
|
116
|
+
isPrimaryKey: false;
|
|
117
|
+
isAutoincrement: false;
|
|
118
|
+
hasRuntimeDefault: false;
|
|
119
|
+
enumValues: [string, ...string[]];
|
|
120
|
+
baseColumn: never;
|
|
121
|
+
identity: undefined;
|
|
122
|
+
generated: undefined;
|
|
123
|
+
}, {}, {}>;
|
|
124
|
+
status: import("drizzle-orm/mysql-core").MySqlColumn<{
|
|
125
|
+
name: "status";
|
|
126
|
+
tableName: "mxllog_events";
|
|
127
|
+
dataType: "number";
|
|
128
|
+
columnType: "MySqlInt";
|
|
129
|
+
data: number;
|
|
130
|
+
driverParam: string | number;
|
|
131
|
+
notNull: false;
|
|
132
|
+
hasDefault: false;
|
|
133
|
+
isPrimaryKey: false;
|
|
134
|
+
isAutoincrement: false;
|
|
135
|
+
hasRuntimeDefault: false;
|
|
136
|
+
enumValues: undefined;
|
|
137
|
+
baseColumn: never;
|
|
138
|
+
identity: undefined;
|
|
139
|
+
generated: undefined;
|
|
140
|
+
}, {}, {}>;
|
|
141
|
+
durationMs: import("drizzle-orm/mysql-core").MySqlColumn<{
|
|
142
|
+
name: "duration_ms";
|
|
143
|
+
tableName: "mxllog_events";
|
|
144
|
+
dataType: "number";
|
|
145
|
+
columnType: "MySqlInt";
|
|
146
|
+
data: number;
|
|
147
|
+
driverParam: string | number;
|
|
148
|
+
notNull: false;
|
|
149
|
+
hasDefault: false;
|
|
150
|
+
isPrimaryKey: false;
|
|
151
|
+
isAutoincrement: false;
|
|
152
|
+
hasRuntimeDefault: false;
|
|
153
|
+
enumValues: undefined;
|
|
154
|
+
baseColumn: never;
|
|
155
|
+
identity: undefined;
|
|
156
|
+
generated: undefined;
|
|
157
|
+
}, {}, {}>;
|
|
158
|
+
requestId: import("drizzle-orm/mysql-core").MySqlColumn<{
|
|
159
|
+
name: "request_id";
|
|
160
|
+
tableName: "mxllog_events";
|
|
161
|
+
dataType: "string";
|
|
162
|
+
columnType: "MySqlText";
|
|
163
|
+
data: string;
|
|
164
|
+
driverParam: string;
|
|
165
|
+
notNull: false;
|
|
166
|
+
hasDefault: false;
|
|
167
|
+
isPrimaryKey: false;
|
|
168
|
+
isAutoincrement: false;
|
|
169
|
+
hasRuntimeDefault: false;
|
|
170
|
+
enumValues: [string, ...string[]];
|
|
171
|
+
baseColumn: never;
|
|
172
|
+
identity: undefined;
|
|
173
|
+
generated: undefined;
|
|
174
|
+
}, {}, {}>;
|
|
175
|
+
source: import("drizzle-orm/mysql-core").MySqlColumn<{
|
|
176
|
+
name: "source";
|
|
177
|
+
tableName: "mxllog_events";
|
|
178
|
+
dataType: "string";
|
|
179
|
+
columnType: "MySqlText";
|
|
180
|
+
data: string;
|
|
181
|
+
driverParam: string;
|
|
182
|
+
notNull: false;
|
|
183
|
+
hasDefault: false;
|
|
184
|
+
isPrimaryKey: false;
|
|
185
|
+
isAutoincrement: false;
|
|
186
|
+
hasRuntimeDefault: false;
|
|
187
|
+
enumValues: [string, ...string[]];
|
|
188
|
+
baseColumn: never;
|
|
189
|
+
identity: undefined;
|
|
190
|
+
generated: undefined;
|
|
191
|
+
}, {}, {}>;
|
|
192
|
+
error: import("drizzle-orm/mysql-core").MySqlColumn<{
|
|
193
|
+
name: "error";
|
|
194
|
+
tableName: "mxllog_events";
|
|
195
|
+
dataType: "json";
|
|
196
|
+
columnType: "MySqlJson";
|
|
197
|
+
data: unknown;
|
|
198
|
+
driverParam: string;
|
|
199
|
+
notNull: false;
|
|
200
|
+
hasDefault: false;
|
|
201
|
+
isPrimaryKey: false;
|
|
202
|
+
isAutoincrement: false;
|
|
203
|
+
hasRuntimeDefault: false;
|
|
204
|
+
enumValues: undefined;
|
|
205
|
+
baseColumn: never;
|
|
206
|
+
identity: undefined;
|
|
207
|
+
generated: undefined;
|
|
208
|
+
}, {}, {}>;
|
|
209
|
+
data: import("drizzle-orm/mysql-core").MySqlColumn<{
|
|
210
|
+
name: "data";
|
|
211
|
+
tableName: "mxllog_events";
|
|
212
|
+
dataType: "json";
|
|
213
|
+
columnType: "MySqlJson";
|
|
214
|
+
data: unknown;
|
|
215
|
+
driverParam: string;
|
|
216
|
+
notNull: false;
|
|
217
|
+
hasDefault: false;
|
|
218
|
+
isPrimaryKey: false;
|
|
219
|
+
isAutoincrement: false;
|
|
220
|
+
hasRuntimeDefault: false;
|
|
221
|
+
enumValues: undefined;
|
|
222
|
+
baseColumn: never;
|
|
223
|
+
identity: undefined;
|
|
224
|
+
generated: undefined;
|
|
225
|
+
}, {}, {}>;
|
|
226
|
+
createdAt: import("drizzle-orm/mysql-core").MySqlColumn<{
|
|
227
|
+
name: "created_at";
|
|
228
|
+
tableName: "mxllog_events";
|
|
229
|
+
dataType: "string";
|
|
230
|
+
columnType: "MySqlText";
|
|
231
|
+
data: string;
|
|
232
|
+
driverParam: string;
|
|
233
|
+
notNull: true;
|
|
234
|
+
hasDefault: false;
|
|
235
|
+
isPrimaryKey: false;
|
|
236
|
+
isAutoincrement: false;
|
|
237
|
+
hasRuntimeDefault: false;
|
|
238
|
+
enumValues: [string, ...string[]];
|
|
239
|
+
baseColumn: never;
|
|
240
|
+
identity: undefined;
|
|
241
|
+
generated: undefined;
|
|
242
|
+
}, {}, {}>;
|
|
243
|
+
};
|
|
244
|
+
dialect: "mysql";
|
|
245
|
+
}>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { index, int, json, mysqlTable, text } from "drizzle-orm/mysql-core";
|
|
2
|
+
export const mxllogEvents = mysqlTable("mxllog_events", {
|
|
3
|
+
id: text("id").primaryKey(),
|
|
4
|
+
timestamp: text("timestamp").notNull(),
|
|
5
|
+
level: text("level").notNull(),
|
|
6
|
+
service: text("service").notNull(),
|
|
7
|
+
environment: text("environment").notNull(),
|
|
8
|
+
method: text("method"),
|
|
9
|
+
path: text("path"),
|
|
10
|
+
status: int("status"),
|
|
11
|
+
durationMs: int("duration_ms"),
|
|
12
|
+
requestId: text("request_id"),
|
|
13
|
+
source: text("source"),
|
|
14
|
+
error: json("error"),
|
|
15
|
+
data: json("data"),
|
|
16
|
+
createdAt: text("created_at").notNull()
|
|
17
|
+
}, (table) => [
|
|
18
|
+
index("mxllog_events_timestamp_idx").on(table.timestamp),
|
|
19
|
+
index("mxllog_events_level_idx").on(table.level),
|
|
20
|
+
index("mxllog_events_service_idx").on(table.service),
|
|
21
|
+
index("mxllog_events_status_idx").on(table.status),
|
|
22
|
+
index("mxllog_events_request_id_idx").on(table.requestId),
|
|
23
|
+
index("mxllog_events_created_at_idx").on(table.createdAt)
|
|
24
|
+
]);
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
export declare const mxllogEvents: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
2
|
+
name: "mxllog_events";
|
|
3
|
+
schema: undefined;
|
|
4
|
+
columns: {
|
|
5
|
+
id: import("drizzle-orm/pg-core").PgColumn<{
|
|
6
|
+
name: "id";
|
|
7
|
+
tableName: "mxllog_events";
|
|
8
|
+
dataType: "string";
|
|
9
|
+
columnType: "PgText";
|
|
10
|
+
data: string;
|
|
11
|
+
driverParam: string;
|
|
12
|
+
notNull: true;
|
|
13
|
+
hasDefault: false;
|
|
14
|
+
isPrimaryKey: true;
|
|
15
|
+
isAutoincrement: false;
|
|
16
|
+
hasRuntimeDefault: false;
|
|
17
|
+
enumValues: [string, ...string[]];
|
|
18
|
+
baseColumn: never;
|
|
19
|
+
identity: undefined;
|
|
20
|
+
generated: undefined;
|
|
21
|
+
}, {}, {}>;
|
|
22
|
+
timestamp: import("drizzle-orm/pg-core").PgColumn<{
|
|
23
|
+
name: "timestamp";
|
|
24
|
+
tableName: "mxllog_events";
|
|
25
|
+
dataType: "string";
|
|
26
|
+
columnType: "PgText";
|
|
27
|
+
data: string;
|
|
28
|
+
driverParam: string;
|
|
29
|
+
notNull: true;
|
|
30
|
+
hasDefault: false;
|
|
31
|
+
isPrimaryKey: false;
|
|
32
|
+
isAutoincrement: false;
|
|
33
|
+
hasRuntimeDefault: false;
|
|
34
|
+
enumValues: [string, ...string[]];
|
|
35
|
+
baseColumn: never;
|
|
36
|
+
identity: undefined;
|
|
37
|
+
generated: undefined;
|
|
38
|
+
}, {}, {}>;
|
|
39
|
+
level: import("drizzle-orm/pg-core").PgColumn<{
|
|
40
|
+
name: "level";
|
|
41
|
+
tableName: "mxllog_events";
|
|
42
|
+
dataType: "string";
|
|
43
|
+
columnType: "PgText";
|
|
44
|
+
data: string;
|
|
45
|
+
driverParam: string;
|
|
46
|
+
notNull: true;
|
|
47
|
+
hasDefault: false;
|
|
48
|
+
isPrimaryKey: false;
|
|
49
|
+
isAutoincrement: false;
|
|
50
|
+
hasRuntimeDefault: false;
|
|
51
|
+
enumValues: [string, ...string[]];
|
|
52
|
+
baseColumn: never;
|
|
53
|
+
identity: undefined;
|
|
54
|
+
generated: undefined;
|
|
55
|
+
}, {}, {}>;
|
|
56
|
+
service: import("drizzle-orm/pg-core").PgColumn<{
|
|
57
|
+
name: "service";
|
|
58
|
+
tableName: "mxllog_events";
|
|
59
|
+
dataType: "string";
|
|
60
|
+
columnType: "PgText";
|
|
61
|
+
data: string;
|
|
62
|
+
driverParam: string;
|
|
63
|
+
notNull: true;
|
|
64
|
+
hasDefault: false;
|
|
65
|
+
isPrimaryKey: false;
|
|
66
|
+
isAutoincrement: false;
|
|
67
|
+
hasRuntimeDefault: false;
|
|
68
|
+
enumValues: [string, ...string[]];
|
|
69
|
+
baseColumn: never;
|
|
70
|
+
identity: undefined;
|
|
71
|
+
generated: undefined;
|
|
72
|
+
}, {}, {}>;
|
|
73
|
+
environment: import("drizzle-orm/pg-core").PgColumn<{
|
|
74
|
+
name: "environment";
|
|
75
|
+
tableName: "mxllog_events";
|
|
76
|
+
dataType: "string";
|
|
77
|
+
columnType: "PgText";
|
|
78
|
+
data: string;
|
|
79
|
+
driverParam: string;
|
|
80
|
+
notNull: true;
|
|
81
|
+
hasDefault: false;
|
|
82
|
+
isPrimaryKey: false;
|
|
83
|
+
isAutoincrement: false;
|
|
84
|
+
hasRuntimeDefault: false;
|
|
85
|
+
enumValues: [string, ...string[]];
|
|
86
|
+
baseColumn: never;
|
|
87
|
+
identity: undefined;
|
|
88
|
+
generated: undefined;
|
|
89
|
+
}, {}, {}>;
|
|
90
|
+
method: import("drizzle-orm/pg-core").PgColumn<{
|
|
91
|
+
name: "method";
|
|
92
|
+
tableName: "mxllog_events";
|
|
93
|
+
dataType: "string";
|
|
94
|
+
columnType: "PgText";
|
|
95
|
+
data: string;
|
|
96
|
+
driverParam: string;
|
|
97
|
+
notNull: false;
|
|
98
|
+
hasDefault: false;
|
|
99
|
+
isPrimaryKey: false;
|
|
100
|
+
isAutoincrement: false;
|
|
101
|
+
hasRuntimeDefault: false;
|
|
102
|
+
enumValues: [string, ...string[]];
|
|
103
|
+
baseColumn: never;
|
|
104
|
+
identity: undefined;
|
|
105
|
+
generated: undefined;
|
|
106
|
+
}, {}, {}>;
|
|
107
|
+
path: import("drizzle-orm/pg-core").PgColumn<{
|
|
108
|
+
name: "path";
|
|
109
|
+
tableName: "mxllog_events";
|
|
110
|
+
dataType: "string";
|
|
111
|
+
columnType: "PgText";
|
|
112
|
+
data: string;
|
|
113
|
+
driverParam: string;
|
|
114
|
+
notNull: false;
|
|
115
|
+
hasDefault: false;
|
|
116
|
+
isPrimaryKey: false;
|
|
117
|
+
isAutoincrement: false;
|
|
118
|
+
hasRuntimeDefault: false;
|
|
119
|
+
enumValues: [string, ...string[]];
|
|
120
|
+
baseColumn: never;
|
|
121
|
+
identity: undefined;
|
|
122
|
+
generated: undefined;
|
|
123
|
+
}, {}, {}>;
|
|
124
|
+
status: import("drizzle-orm/pg-core").PgColumn<{
|
|
125
|
+
name: "status";
|
|
126
|
+
tableName: "mxllog_events";
|
|
127
|
+
dataType: "number";
|
|
128
|
+
columnType: "PgInteger";
|
|
129
|
+
data: number;
|
|
130
|
+
driverParam: string | number;
|
|
131
|
+
notNull: false;
|
|
132
|
+
hasDefault: false;
|
|
133
|
+
isPrimaryKey: false;
|
|
134
|
+
isAutoincrement: false;
|
|
135
|
+
hasRuntimeDefault: false;
|
|
136
|
+
enumValues: undefined;
|
|
137
|
+
baseColumn: never;
|
|
138
|
+
identity: undefined;
|
|
139
|
+
generated: undefined;
|
|
140
|
+
}, {}, {}>;
|
|
141
|
+
durationMs: import("drizzle-orm/pg-core").PgColumn<{
|
|
142
|
+
name: "duration_ms";
|
|
143
|
+
tableName: "mxllog_events";
|
|
144
|
+
dataType: "number";
|
|
145
|
+
columnType: "PgInteger";
|
|
146
|
+
data: number;
|
|
147
|
+
driverParam: string | number;
|
|
148
|
+
notNull: false;
|
|
149
|
+
hasDefault: false;
|
|
150
|
+
isPrimaryKey: false;
|
|
151
|
+
isAutoincrement: false;
|
|
152
|
+
hasRuntimeDefault: false;
|
|
153
|
+
enumValues: undefined;
|
|
154
|
+
baseColumn: never;
|
|
155
|
+
identity: undefined;
|
|
156
|
+
generated: undefined;
|
|
157
|
+
}, {}, {}>;
|
|
158
|
+
requestId: import("drizzle-orm/pg-core").PgColumn<{
|
|
159
|
+
name: "request_id";
|
|
160
|
+
tableName: "mxllog_events";
|
|
161
|
+
dataType: "string";
|
|
162
|
+
columnType: "PgText";
|
|
163
|
+
data: string;
|
|
164
|
+
driverParam: string;
|
|
165
|
+
notNull: false;
|
|
166
|
+
hasDefault: false;
|
|
167
|
+
isPrimaryKey: false;
|
|
168
|
+
isAutoincrement: false;
|
|
169
|
+
hasRuntimeDefault: false;
|
|
170
|
+
enumValues: [string, ...string[]];
|
|
171
|
+
baseColumn: never;
|
|
172
|
+
identity: undefined;
|
|
173
|
+
generated: undefined;
|
|
174
|
+
}, {}, {}>;
|
|
175
|
+
source: import("drizzle-orm/pg-core").PgColumn<{
|
|
176
|
+
name: "source";
|
|
177
|
+
tableName: "mxllog_events";
|
|
178
|
+
dataType: "string";
|
|
179
|
+
columnType: "PgText";
|
|
180
|
+
data: string;
|
|
181
|
+
driverParam: string;
|
|
182
|
+
notNull: false;
|
|
183
|
+
hasDefault: false;
|
|
184
|
+
isPrimaryKey: false;
|
|
185
|
+
isAutoincrement: false;
|
|
186
|
+
hasRuntimeDefault: false;
|
|
187
|
+
enumValues: [string, ...string[]];
|
|
188
|
+
baseColumn: never;
|
|
189
|
+
identity: undefined;
|
|
190
|
+
generated: undefined;
|
|
191
|
+
}, {}, {}>;
|
|
192
|
+
error: import("drizzle-orm/pg-core").PgColumn<{
|
|
193
|
+
name: "error";
|
|
194
|
+
tableName: "mxllog_events";
|
|
195
|
+
dataType: "json";
|
|
196
|
+
columnType: "PgJsonb";
|
|
197
|
+
data: unknown;
|
|
198
|
+
driverParam: unknown;
|
|
199
|
+
notNull: false;
|
|
200
|
+
hasDefault: false;
|
|
201
|
+
isPrimaryKey: false;
|
|
202
|
+
isAutoincrement: false;
|
|
203
|
+
hasRuntimeDefault: false;
|
|
204
|
+
enumValues: undefined;
|
|
205
|
+
baseColumn: never;
|
|
206
|
+
identity: undefined;
|
|
207
|
+
generated: undefined;
|
|
208
|
+
}, {}, {}>;
|
|
209
|
+
data: import("drizzle-orm/pg-core").PgColumn<{
|
|
210
|
+
name: "data";
|
|
211
|
+
tableName: "mxllog_events";
|
|
212
|
+
dataType: "json";
|
|
213
|
+
columnType: "PgJsonb";
|
|
214
|
+
data: unknown;
|
|
215
|
+
driverParam: unknown;
|
|
216
|
+
notNull: false;
|
|
217
|
+
hasDefault: false;
|
|
218
|
+
isPrimaryKey: false;
|
|
219
|
+
isAutoincrement: false;
|
|
220
|
+
hasRuntimeDefault: false;
|
|
221
|
+
enumValues: undefined;
|
|
222
|
+
baseColumn: never;
|
|
223
|
+
identity: undefined;
|
|
224
|
+
generated: undefined;
|
|
225
|
+
}, {}, {}>;
|
|
226
|
+
createdAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
227
|
+
name: "created_at";
|
|
228
|
+
tableName: "mxllog_events";
|
|
229
|
+
dataType: "string";
|
|
230
|
+
columnType: "PgText";
|
|
231
|
+
data: string;
|
|
232
|
+
driverParam: string;
|
|
233
|
+
notNull: true;
|
|
234
|
+
hasDefault: false;
|
|
235
|
+
isPrimaryKey: false;
|
|
236
|
+
isAutoincrement: false;
|
|
237
|
+
hasRuntimeDefault: false;
|
|
238
|
+
enumValues: [string, ...string[]];
|
|
239
|
+
baseColumn: never;
|
|
240
|
+
identity: undefined;
|
|
241
|
+
generated: undefined;
|
|
242
|
+
}, {}, {}>;
|
|
243
|
+
};
|
|
244
|
+
dialect: "pg";
|
|
245
|
+
}>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { index, integer, jsonb, pgTable, text } from "drizzle-orm/pg-core";
|
|
2
|
+
export const mxllogEvents = pgTable("mxllog_events", {
|
|
3
|
+
id: text("id").primaryKey(),
|
|
4
|
+
timestamp: text("timestamp").notNull(),
|
|
5
|
+
level: text("level").notNull(),
|
|
6
|
+
service: text("service").notNull(),
|
|
7
|
+
environment: text("environment").notNull(),
|
|
8
|
+
method: text("method"),
|
|
9
|
+
path: text("path"),
|
|
10
|
+
status: integer("status"),
|
|
11
|
+
durationMs: integer("duration_ms"),
|
|
12
|
+
requestId: text("request_id"),
|
|
13
|
+
source: text("source"),
|
|
14
|
+
error: jsonb("error"),
|
|
15
|
+
data: jsonb("data"),
|
|
16
|
+
createdAt: text("created_at").notNull()
|
|
17
|
+
}, (table) => [
|
|
18
|
+
index("mxllog_events_timestamp_idx").on(table.timestamp),
|
|
19
|
+
index("mxllog_events_level_idx").on(table.level),
|
|
20
|
+
index("mxllog_events_service_idx").on(table.service),
|
|
21
|
+
index("mxllog_events_status_idx").on(table.status),
|
|
22
|
+
index("mxllog_events_request_id_idx").on(table.requestId),
|
|
23
|
+
index("mxllog_events_created_at_idx").on(table.createdAt)
|
|
24
|
+
]);
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
export declare const mxllogEvents: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
|
|
2
|
+
name: "mxllog_events";
|
|
3
|
+
schema: undefined;
|
|
4
|
+
columns: {
|
|
5
|
+
id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
6
|
+
name: "id";
|
|
7
|
+
tableName: "mxllog_events";
|
|
8
|
+
dataType: "string";
|
|
9
|
+
columnType: "SQLiteText";
|
|
10
|
+
data: string;
|
|
11
|
+
driverParam: string;
|
|
12
|
+
notNull: true;
|
|
13
|
+
hasDefault: false;
|
|
14
|
+
isPrimaryKey: true;
|
|
15
|
+
isAutoincrement: false;
|
|
16
|
+
hasRuntimeDefault: false;
|
|
17
|
+
enumValues: [string, ...string[]];
|
|
18
|
+
baseColumn: never;
|
|
19
|
+
identity: undefined;
|
|
20
|
+
generated: undefined;
|
|
21
|
+
}, {}, {
|
|
22
|
+
length: number | undefined;
|
|
23
|
+
}>;
|
|
24
|
+
timestamp: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
25
|
+
name: "timestamp";
|
|
26
|
+
tableName: "mxllog_events";
|
|
27
|
+
dataType: "string";
|
|
28
|
+
columnType: "SQLiteText";
|
|
29
|
+
data: string;
|
|
30
|
+
driverParam: string;
|
|
31
|
+
notNull: true;
|
|
32
|
+
hasDefault: false;
|
|
33
|
+
isPrimaryKey: false;
|
|
34
|
+
isAutoincrement: false;
|
|
35
|
+
hasRuntimeDefault: false;
|
|
36
|
+
enumValues: [string, ...string[]];
|
|
37
|
+
baseColumn: never;
|
|
38
|
+
identity: undefined;
|
|
39
|
+
generated: undefined;
|
|
40
|
+
}, {}, {
|
|
41
|
+
length: number | undefined;
|
|
42
|
+
}>;
|
|
43
|
+
level: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
44
|
+
name: "level";
|
|
45
|
+
tableName: "mxllog_events";
|
|
46
|
+
dataType: "string";
|
|
47
|
+
columnType: "SQLiteText";
|
|
48
|
+
data: string;
|
|
49
|
+
driverParam: string;
|
|
50
|
+
notNull: true;
|
|
51
|
+
hasDefault: false;
|
|
52
|
+
isPrimaryKey: false;
|
|
53
|
+
isAutoincrement: false;
|
|
54
|
+
hasRuntimeDefault: false;
|
|
55
|
+
enumValues: [string, ...string[]];
|
|
56
|
+
baseColumn: never;
|
|
57
|
+
identity: undefined;
|
|
58
|
+
generated: undefined;
|
|
59
|
+
}, {}, {
|
|
60
|
+
length: number | undefined;
|
|
61
|
+
}>;
|
|
62
|
+
service: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
63
|
+
name: "service";
|
|
64
|
+
tableName: "mxllog_events";
|
|
65
|
+
dataType: "string";
|
|
66
|
+
columnType: "SQLiteText";
|
|
67
|
+
data: string;
|
|
68
|
+
driverParam: string;
|
|
69
|
+
notNull: true;
|
|
70
|
+
hasDefault: false;
|
|
71
|
+
isPrimaryKey: false;
|
|
72
|
+
isAutoincrement: false;
|
|
73
|
+
hasRuntimeDefault: false;
|
|
74
|
+
enumValues: [string, ...string[]];
|
|
75
|
+
baseColumn: never;
|
|
76
|
+
identity: undefined;
|
|
77
|
+
generated: undefined;
|
|
78
|
+
}, {}, {
|
|
79
|
+
length: number | undefined;
|
|
80
|
+
}>;
|
|
81
|
+
environment: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
82
|
+
name: "environment";
|
|
83
|
+
tableName: "mxllog_events";
|
|
84
|
+
dataType: "string";
|
|
85
|
+
columnType: "SQLiteText";
|
|
86
|
+
data: string;
|
|
87
|
+
driverParam: string;
|
|
88
|
+
notNull: true;
|
|
89
|
+
hasDefault: false;
|
|
90
|
+
isPrimaryKey: false;
|
|
91
|
+
isAutoincrement: false;
|
|
92
|
+
hasRuntimeDefault: false;
|
|
93
|
+
enumValues: [string, ...string[]];
|
|
94
|
+
baseColumn: never;
|
|
95
|
+
identity: undefined;
|
|
96
|
+
generated: undefined;
|
|
97
|
+
}, {}, {
|
|
98
|
+
length: number | undefined;
|
|
99
|
+
}>;
|
|
100
|
+
method: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
101
|
+
name: "method";
|
|
102
|
+
tableName: "mxllog_events";
|
|
103
|
+
dataType: "string";
|
|
104
|
+
columnType: "SQLiteText";
|
|
105
|
+
data: string;
|
|
106
|
+
driverParam: string;
|
|
107
|
+
notNull: false;
|
|
108
|
+
hasDefault: false;
|
|
109
|
+
isPrimaryKey: false;
|
|
110
|
+
isAutoincrement: false;
|
|
111
|
+
hasRuntimeDefault: false;
|
|
112
|
+
enumValues: [string, ...string[]];
|
|
113
|
+
baseColumn: never;
|
|
114
|
+
identity: undefined;
|
|
115
|
+
generated: undefined;
|
|
116
|
+
}, {}, {
|
|
117
|
+
length: number | undefined;
|
|
118
|
+
}>;
|
|
119
|
+
path: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
120
|
+
name: "path";
|
|
121
|
+
tableName: "mxllog_events";
|
|
122
|
+
dataType: "string";
|
|
123
|
+
columnType: "SQLiteText";
|
|
124
|
+
data: string;
|
|
125
|
+
driverParam: string;
|
|
126
|
+
notNull: false;
|
|
127
|
+
hasDefault: false;
|
|
128
|
+
isPrimaryKey: false;
|
|
129
|
+
isAutoincrement: false;
|
|
130
|
+
hasRuntimeDefault: false;
|
|
131
|
+
enumValues: [string, ...string[]];
|
|
132
|
+
baseColumn: never;
|
|
133
|
+
identity: undefined;
|
|
134
|
+
generated: undefined;
|
|
135
|
+
}, {}, {
|
|
136
|
+
length: number | undefined;
|
|
137
|
+
}>;
|
|
138
|
+
status: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
139
|
+
name: "status";
|
|
140
|
+
tableName: "mxllog_events";
|
|
141
|
+
dataType: "number";
|
|
142
|
+
columnType: "SQLiteInteger";
|
|
143
|
+
data: number;
|
|
144
|
+
driverParam: number;
|
|
145
|
+
notNull: false;
|
|
146
|
+
hasDefault: false;
|
|
147
|
+
isPrimaryKey: false;
|
|
148
|
+
isAutoincrement: false;
|
|
149
|
+
hasRuntimeDefault: false;
|
|
150
|
+
enumValues: undefined;
|
|
151
|
+
baseColumn: never;
|
|
152
|
+
identity: undefined;
|
|
153
|
+
generated: undefined;
|
|
154
|
+
}, {}, {}>;
|
|
155
|
+
durationMs: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
156
|
+
name: "duration_ms";
|
|
157
|
+
tableName: "mxllog_events";
|
|
158
|
+
dataType: "number";
|
|
159
|
+
columnType: "SQLiteInteger";
|
|
160
|
+
data: number;
|
|
161
|
+
driverParam: number;
|
|
162
|
+
notNull: false;
|
|
163
|
+
hasDefault: false;
|
|
164
|
+
isPrimaryKey: false;
|
|
165
|
+
isAutoincrement: false;
|
|
166
|
+
hasRuntimeDefault: false;
|
|
167
|
+
enumValues: undefined;
|
|
168
|
+
baseColumn: never;
|
|
169
|
+
identity: undefined;
|
|
170
|
+
generated: undefined;
|
|
171
|
+
}, {}, {}>;
|
|
172
|
+
requestId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
173
|
+
name: "request_id";
|
|
174
|
+
tableName: "mxllog_events";
|
|
175
|
+
dataType: "string";
|
|
176
|
+
columnType: "SQLiteText";
|
|
177
|
+
data: string;
|
|
178
|
+
driverParam: string;
|
|
179
|
+
notNull: false;
|
|
180
|
+
hasDefault: false;
|
|
181
|
+
isPrimaryKey: false;
|
|
182
|
+
isAutoincrement: false;
|
|
183
|
+
hasRuntimeDefault: false;
|
|
184
|
+
enumValues: [string, ...string[]];
|
|
185
|
+
baseColumn: never;
|
|
186
|
+
identity: undefined;
|
|
187
|
+
generated: undefined;
|
|
188
|
+
}, {}, {
|
|
189
|
+
length: number | undefined;
|
|
190
|
+
}>;
|
|
191
|
+
source: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
192
|
+
name: "source";
|
|
193
|
+
tableName: "mxllog_events";
|
|
194
|
+
dataType: "string";
|
|
195
|
+
columnType: "SQLiteText";
|
|
196
|
+
data: string;
|
|
197
|
+
driverParam: string;
|
|
198
|
+
notNull: false;
|
|
199
|
+
hasDefault: false;
|
|
200
|
+
isPrimaryKey: false;
|
|
201
|
+
isAutoincrement: false;
|
|
202
|
+
hasRuntimeDefault: false;
|
|
203
|
+
enumValues: [string, ...string[]];
|
|
204
|
+
baseColumn: never;
|
|
205
|
+
identity: undefined;
|
|
206
|
+
generated: undefined;
|
|
207
|
+
}, {}, {
|
|
208
|
+
length: number | undefined;
|
|
209
|
+
}>;
|
|
210
|
+
error: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
211
|
+
name: "error";
|
|
212
|
+
tableName: "mxllog_events";
|
|
213
|
+
dataType: "string";
|
|
214
|
+
columnType: "SQLiteText";
|
|
215
|
+
data: string;
|
|
216
|
+
driverParam: string;
|
|
217
|
+
notNull: false;
|
|
218
|
+
hasDefault: false;
|
|
219
|
+
isPrimaryKey: false;
|
|
220
|
+
isAutoincrement: false;
|
|
221
|
+
hasRuntimeDefault: false;
|
|
222
|
+
enumValues: [string, ...string[]];
|
|
223
|
+
baseColumn: never;
|
|
224
|
+
identity: undefined;
|
|
225
|
+
generated: undefined;
|
|
226
|
+
}, {}, {
|
|
227
|
+
length: number | undefined;
|
|
228
|
+
}>;
|
|
229
|
+
data: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
230
|
+
name: "data";
|
|
231
|
+
tableName: "mxllog_events";
|
|
232
|
+
dataType: "string";
|
|
233
|
+
columnType: "SQLiteText";
|
|
234
|
+
data: string;
|
|
235
|
+
driverParam: string;
|
|
236
|
+
notNull: false;
|
|
237
|
+
hasDefault: false;
|
|
238
|
+
isPrimaryKey: false;
|
|
239
|
+
isAutoincrement: false;
|
|
240
|
+
hasRuntimeDefault: false;
|
|
241
|
+
enumValues: [string, ...string[]];
|
|
242
|
+
baseColumn: never;
|
|
243
|
+
identity: undefined;
|
|
244
|
+
generated: undefined;
|
|
245
|
+
}, {}, {
|
|
246
|
+
length: number | undefined;
|
|
247
|
+
}>;
|
|
248
|
+
createdAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
249
|
+
name: "created_at";
|
|
250
|
+
tableName: "mxllog_events";
|
|
251
|
+
dataType: "string";
|
|
252
|
+
columnType: "SQLiteText";
|
|
253
|
+
data: string;
|
|
254
|
+
driverParam: string;
|
|
255
|
+
notNull: true;
|
|
256
|
+
hasDefault: false;
|
|
257
|
+
isPrimaryKey: false;
|
|
258
|
+
isAutoincrement: false;
|
|
259
|
+
hasRuntimeDefault: false;
|
|
260
|
+
enumValues: [string, ...string[]];
|
|
261
|
+
baseColumn: never;
|
|
262
|
+
identity: undefined;
|
|
263
|
+
generated: undefined;
|
|
264
|
+
}, {}, {
|
|
265
|
+
length: number | undefined;
|
|
266
|
+
}>;
|
|
267
|
+
};
|
|
268
|
+
dialect: "sqlite";
|
|
269
|
+
}>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { index, integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
|
|
2
|
+
export const mxllogEvents = sqliteTable("mxllog_events", {
|
|
3
|
+
id: text("id").primaryKey(),
|
|
4
|
+
timestamp: text("timestamp").notNull(),
|
|
5
|
+
level: text("level").notNull(),
|
|
6
|
+
service: text("service").notNull(),
|
|
7
|
+
environment: text("environment").notNull(),
|
|
8
|
+
method: text("method"),
|
|
9
|
+
path: text("path"),
|
|
10
|
+
status: integer("status"),
|
|
11
|
+
durationMs: integer("duration_ms"),
|
|
12
|
+
requestId: text("request_id"),
|
|
13
|
+
source: text("source"),
|
|
14
|
+
error: text("error"),
|
|
15
|
+
data: text("data"),
|
|
16
|
+
createdAt: text("created_at").notNull()
|
|
17
|
+
}, (table) => [
|
|
18
|
+
index("mxllog_events_timestamp_idx").on(table.timestamp),
|
|
19
|
+
index("mxllog_events_level_idx").on(table.level),
|
|
20
|
+
index("mxllog_events_service_idx").on(table.service),
|
|
21
|
+
index("mxllog_events_status_idx").on(table.status),
|
|
22
|
+
index("mxllog_events_request_id_idx").on(table.requestId),
|
|
23
|
+
index("mxllog_events_created_at_idx").on(table.createdAt)
|
|
24
|
+
]);
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { defineNitroPlugin } from "nitropack/runtime";
|
|
2
|
+
import { db, schema } from "@nuxthub/db";
|
|
3
|
+
function parseDurationMs(event) {
|
|
4
|
+
if (typeof event.durationMs === "number") return event.durationMs;
|
|
5
|
+
if (typeof event.duration === "number") return event.duration;
|
|
6
|
+
if (typeof event.duration === "string") {
|
|
7
|
+
const str = event.duration;
|
|
8
|
+
const msMatch = str.match(/^([\d.]+)\s*ms$/);
|
|
9
|
+
if (msMatch) return Math.round(Number.parseFloat(msMatch[1]));
|
|
10
|
+
const sMatch = str.match(/^([\d.]+)\s*s$/);
|
|
11
|
+
if (sMatch) return Math.round(Number.parseFloat(sMatch[1]) * 1e3);
|
|
12
|
+
}
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
const INDEXED_FIELDS = /* @__PURE__ */ new Set([
|
|
16
|
+
"timestamp",
|
|
17
|
+
"level",
|
|
18
|
+
"service",
|
|
19
|
+
"environment",
|
|
20
|
+
"method",
|
|
21
|
+
"path",
|
|
22
|
+
"status",
|
|
23
|
+
"durationMs",
|
|
24
|
+
"duration",
|
|
25
|
+
"requestId",
|
|
26
|
+
"source",
|
|
27
|
+
"error"
|
|
28
|
+
]);
|
|
29
|
+
function extractRow(ctx) {
|
|
30
|
+
const { event, request } = ctx;
|
|
31
|
+
const data = {};
|
|
32
|
+
for (const [key, value] of Object.entries(event)) {
|
|
33
|
+
if (!INDEXED_FIELDS.has(key) && value !== void 0) {
|
|
34
|
+
data[key] = value;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const errorValue = event.error;
|
|
38
|
+
let errorJson = null;
|
|
39
|
+
if (errorValue !== void 0 && errorValue !== null) {
|
|
40
|
+
if (typeof errorValue === "string") {
|
|
41
|
+
errorJson = errorValue;
|
|
42
|
+
} else {
|
|
43
|
+
try {
|
|
44
|
+
errorJson = JSON.stringify(errorValue);
|
|
45
|
+
} catch {
|
|
46
|
+
errorJson = String(errorValue);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
id: crypto.randomUUID(),
|
|
52
|
+
timestamp: event.timestamp,
|
|
53
|
+
level: event.level,
|
|
54
|
+
service: event.service,
|
|
55
|
+
environment: event.environment,
|
|
56
|
+
method: (request?.method ?? event.method) || null,
|
|
57
|
+
path: (request?.path ?? event.path) || null,
|
|
58
|
+
status: typeof event.status === "number" ? event.status : null,
|
|
59
|
+
durationMs: parseDurationMs(event),
|
|
60
|
+
requestId: (request?.requestId ?? event.requestId) || null,
|
|
61
|
+
source: event.source || null,
|
|
62
|
+
error: errorJson,
|
|
63
|
+
data: Object.keys(data).length > 0 ? JSON.stringify(data) : null,
|
|
64
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const MAX_ATTEMPTS = 3;
|
|
68
|
+
const INITIAL_DELAY_MS = 500;
|
|
69
|
+
const RETRYABLE_CODES = /* @__PURE__ */ new Set([
|
|
70
|
+
"CONNECT_TIMEOUT",
|
|
71
|
+
"ETIMEDOUT",
|
|
72
|
+
"ECONNREFUSED",
|
|
73
|
+
"ECONNRESET",
|
|
74
|
+
"CONNECTION_ENDED"
|
|
75
|
+
]);
|
|
76
|
+
function isRetryable(error) {
|
|
77
|
+
if (error instanceof Error) {
|
|
78
|
+
const cause = error.cause;
|
|
79
|
+
if (cause && typeof cause.code === "string") {
|
|
80
|
+
return RETRYABLE_CODES.has(cause.code);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
async function insertWithRetry(rows) {
|
|
86
|
+
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
|
|
87
|
+
try {
|
|
88
|
+
await db.insert(schema.mxllogEvents).values(rows);
|
|
89
|
+
return;
|
|
90
|
+
} catch (error) {
|
|
91
|
+
if (attempt === MAX_ATTEMPTS || !isRetryable(error)) throw error;
|
|
92
|
+
await new Promise((r) => setTimeout(r, INITIAL_DELAY_MS * 2 ** (attempt - 1)));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
export default defineNitroPlugin((nitroApp) => {
|
|
97
|
+
nitroApp.hooks.hook("@safaricom-mxl/log:drain", async (ctx) => {
|
|
98
|
+
try {
|
|
99
|
+
const contexts = Array.isArray(ctx) ? ctx : [ctx];
|
|
100
|
+
if (contexts.length === 0) return;
|
|
101
|
+
const rows = contexts.map(extractRow);
|
|
102
|
+
await insertWithRetry(rows);
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.error("[mxllog/nuxthub] Failed to insert events:", error);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { defineTask, useRuntimeConfig } from "nitropack/runtime";
|
|
2
|
+
import { lt } from "drizzle-orm";
|
|
3
|
+
import { db, schema } from "@nuxthub/db";
|
|
4
|
+
import { parseRetention } from "../utils/retention.js";
|
|
5
|
+
export default defineTask({
|
|
6
|
+
meta: {
|
|
7
|
+
name: "@safaricom-mxl/log:cleanup",
|
|
8
|
+
description: "Clean up expired mxllog events based on retention policy"
|
|
9
|
+
},
|
|
10
|
+
async run() {
|
|
11
|
+
const config = useRuntimeConfig();
|
|
12
|
+
const retention = config.mxllog?.retention ?? "7d";
|
|
13
|
+
const { totalMs } = parseRetention(retention);
|
|
14
|
+
const cutoff = new Date(Date.now() - totalMs).toISOString();
|
|
15
|
+
try {
|
|
16
|
+
const result = await db.delete(schema.mxllogEvents).where(lt(schema.mxllogEvents.createdAt, cutoff));
|
|
17
|
+
console.log(`[mxllog/nuxthub] Cleanup: deleted events older than ${retention} (before ${cutoff})`, result);
|
|
18
|
+
return { result: "success" };
|
|
19
|
+
} catch (error) {
|
|
20
|
+
console.error("[mxllog/nuxthub] Cleanup task failed:", error);
|
|
21
|
+
return { result: "error" };
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { createMxllogError } from "@safaricom-mxl/log";
|
|
2
|
+
export function parseRetention(retention) {
|
|
3
|
+
const match = retention.match(/^(\d+)(d|h|m)$/);
|
|
4
|
+
if (!match) {
|
|
5
|
+
throw createMxllogError({
|
|
6
|
+
message: `[mxllog/nuxthub] Invalid retention format: "${retention}"`,
|
|
7
|
+
why: "The retention value must be a number followed by a unit: d (days), h (hours), or m (minutes)",
|
|
8
|
+
fix: `Change retention to a valid format, e.g., "30d", "24h", or "60m"`,
|
|
9
|
+
link: "https://mxllog.dev/nuxthub/retention"
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
const [, numStr, unit] = match;
|
|
13
|
+
const num = Number(numStr);
|
|
14
|
+
let totalMinutes;
|
|
15
|
+
switch (unit) {
|
|
16
|
+
case "m":
|
|
17
|
+
totalMinutes = num;
|
|
18
|
+
break;
|
|
19
|
+
case "h":
|
|
20
|
+
totalMinutes = num * 60;
|
|
21
|
+
break;
|
|
22
|
+
case "d":
|
|
23
|
+
totalMinutes = num * 24 * 60;
|
|
24
|
+
break;
|
|
25
|
+
default:
|
|
26
|
+
throw createMxllogError({
|
|
27
|
+
message: `[mxllog/nuxthub] Unknown retention unit: "${unit}"`,
|
|
28
|
+
why: "The retention value must use one of the supported units: d (days), h (hours), or m (minutes)",
|
|
29
|
+
fix: `Change retention to a valid format, e.g., "30d", "24h", or "60m"`,
|
|
30
|
+
link: "https://mxllog.dev/nuxthub/retention"
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
value: num,
|
|
35
|
+
unit,
|
|
36
|
+
totalMinutes,
|
|
37
|
+
totalMs: totalMinutes * 60 * 1e3
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export function retentionToCron(retention) {
|
|
41
|
+
const { totalMinutes } = parseRetention(retention);
|
|
42
|
+
const halfMinutes = Math.max(1, Math.floor(totalMinutes / 2));
|
|
43
|
+
if (halfMinutes < 60) {
|
|
44
|
+
return `*/${halfMinutes} * * * *`;
|
|
45
|
+
}
|
|
46
|
+
const halfHours = Math.floor(halfMinutes / 60);
|
|
47
|
+
if (halfHours >= 24) {
|
|
48
|
+
return "0 3 * * *";
|
|
49
|
+
}
|
|
50
|
+
return `0 */${halfHours} * * *`;
|
|
51
|
+
}
|
package/dist/types.d.mts
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@safaricom-mxl/nuxthub",
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"description": "Self-hosted log retention for mxllog using NuxtHub database storage",
|
|
5
|
+
"author": "Francis Konde <fkonde@safaricom.co.ke>",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"sideEffects": false,
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/types.d.mts",
|
|
12
|
+
"import": "./dist/module.mjs"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"main": "./dist/module.mjs",
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"keywords": [
|
|
21
|
+
"nuxthub",
|
|
22
|
+
"mxllog",
|
|
23
|
+
"logging",
|
|
24
|
+
"nuxt",
|
|
25
|
+
"drizzle",
|
|
26
|
+
"database"
|
|
27
|
+
],
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "nuxt-module-build build",
|
|
30
|
+
"dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@nuxt/module-builder": "^1.0.2",
|
|
34
|
+
"@safaricom-mxl/log": "workspace:*",
|
|
35
|
+
"typescript": "^5.9.3"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"@safaricom-mxl/log": "workspace:*",
|
|
39
|
+
"@nuxthub/core": "^0.10.6",
|
|
40
|
+
"drizzle-orm": ">=0.45.1"
|
|
41
|
+
},
|
|
42
|
+
"peerDependenciesMeta": {
|
|
43
|
+
"drizzle-orm": {
|
|
44
|
+
"optional": false
|
|
45
|
+
},
|
|
46
|
+
"@safaricom-mxl/log": {
|
|
47
|
+
"optional": false
|
|
48
|
+
},
|
|
49
|
+
"@nuxthub/core": {
|
|
50
|
+
"optional": false
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"publishConfig": {
|
|
54
|
+
"access": "public"
|
|
55
|
+
}
|
|
56
|
+
}
|