@murumets-ee/logging 0.1.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/LICENSE +94 -0
- package/README.md +15 -0
- package/dist/admin.d.ts +44 -0
- package/dist/admin.js +1 -0
- package/dist/admin.js.map +1 -0
- package/dist/chunk-PQXD7TOP.js +1 -0
- package/dist/chunk-XTE6WERT.js +31 -0
- package/dist/chunk-XTE6WERT.js.map +1 -0
- package/dist/index.d.ts +121 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -0
- package/dist/schema.d.ts +178 -0
- package/dist/schema.js +1 -0
- package/dist/schema.js.map +1 -0
- package/package.json +38 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
Elastic License 2.0 (ELv2)
|
|
2
|
+
|
|
3
|
+
URL: https://www.elastic.co/licensing/elastic-license
|
|
4
|
+
|
|
5
|
+
## Acceptance
|
|
6
|
+
|
|
7
|
+
By using the software, you agree to all of the terms and conditions below.
|
|
8
|
+
|
|
9
|
+
## Copyright License
|
|
10
|
+
|
|
11
|
+
The licensor grants you a non-exclusive, royalty-free, worldwide,
|
|
12
|
+
non-sublicensable, non-transferable license to use, copy, distribute, make
|
|
13
|
+
available, and prepare derivative works of the software, in each case subject
|
|
14
|
+
to the limitations and conditions below.
|
|
15
|
+
|
|
16
|
+
## Limitations
|
|
17
|
+
|
|
18
|
+
You may not provide the software to third parties as a hosted or managed
|
|
19
|
+
service, where the service provides users with access to any substantial set
|
|
20
|
+
of the features or functionality of the software.
|
|
21
|
+
|
|
22
|
+
You may not move, change, disable, or circumvent the license key functionality
|
|
23
|
+
in the software, and you may not remove or obscure any functionality in the
|
|
24
|
+
software that is protected by the license key.
|
|
25
|
+
|
|
26
|
+
You may not alter, remove, or obscure any licensing, copyright, or other
|
|
27
|
+
notices of the licensor in the software. Any use of the licensor's trademarks
|
|
28
|
+
is subject to applicable law.
|
|
29
|
+
|
|
30
|
+
## Patents
|
|
31
|
+
|
|
32
|
+
The licensor grants you a license, under any patent claims the licensor can
|
|
33
|
+
license, or becomes able to license, to make, have made, use, sell, offer for
|
|
34
|
+
sale, import and have imported the software, in each case subject to the
|
|
35
|
+
limitations and conditions in this license. This license does not cover any
|
|
36
|
+
patent claims that you cause to be infringed by modifications or additions to
|
|
37
|
+
the software. If you or your company make any written claim that the software
|
|
38
|
+
infringes or contributes to infringement of any patent, your patent license
|
|
39
|
+
for the software granted under these terms ends immediately. If your company
|
|
40
|
+
makes such a claim, your patent license ends immediately for work on behalf
|
|
41
|
+
of your company.
|
|
42
|
+
|
|
43
|
+
## Notices
|
|
44
|
+
|
|
45
|
+
You must ensure that anyone who gets a copy of any part of the software from
|
|
46
|
+
you also gets a copy of these terms.
|
|
47
|
+
|
|
48
|
+
If you modify the software, you must include in any modified copies of the
|
|
49
|
+
software prominent notices stating that you have modified the software.
|
|
50
|
+
|
|
51
|
+
## No Other Rights
|
|
52
|
+
|
|
53
|
+
These terms do not imply any licenses other than those expressly granted in
|
|
54
|
+
these terms.
|
|
55
|
+
|
|
56
|
+
## Termination
|
|
57
|
+
|
|
58
|
+
If you use the software in violation of these terms, such use is not licensed,
|
|
59
|
+
and your licenses will automatically terminate. If the licensor provides you
|
|
60
|
+
with a notice of your violation, and you cease all violation of this license
|
|
61
|
+
no later than 30 days after you receive that notice, your licenses will be
|
|
62
|
+
reinstated retroactively. However, if you violate these terms after such
|
|
63
|
+
reinstatement, any additional violation of these terms will cause your
|
|
64
|
+
licenses to terminate automatically and permanently.
|
|
65
|
+
|
|
66
|
+
## No Liability
|
|
67
|
+
|
|
68
|
+
As far as the law allows, the software comes as is, without any warranty or
|
|
69
|
+
condition, and the licensor will not be liable to you for any damages arising
|
|
70
|
+
out of these terms or the use or nature of the software, under any kind of
|
|
71
|
+
legal claim.
|
|
72
|
+
|
|
73
|
+
## Definitions
|
|
74
|
+
|
|
75
|
+
The **licensor** is the entity offering these terms, and the **software** is
|
|
76
|
+
the software the licensor makes available under these terms, including any
|
|
77
|
+
portion of it.
|
|
78
|
+
|
|
79
|
+
**you** refers to the individual or entity agreeing to these terms.
|
|
80
|
+
|
|
81
|
+
**your company** is any legal entity, sole proprietorship, or other kind of
|
|
82
|
+
organization that you work for, plus all organizations that have control over,
|
|
83
|
+
are under the control of, or are under common control with that organization.
|
|
84
|
+
**control** means ownership of substantially all the assets of an entity, or
|
|
85
|
+
the power to direct the management and policies of an entity (for example, by
|
|
86
|
+
voting right, contract, or otherwise). Control can be direct or indirect.
|
|
87
|
+
|
|
88
|
+
**your licenses** are all the licenses granted to you for the software under
|
|
89
|
+
these terms.
|
|
90
|
+
|
|
91
|
+
**use** means anything you do with the software requiring one of your
|
|
92
|
+
licenses.
|
|
93
|
+
|
|
94
|
+
**trademark** means trademarks, service marks, and similar rights.
|
package/README.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# @murumets-ee/logging
|
|
2
|
+
|
|
3
|
+
Structured logging and audit trail — Pino logger, audit log table, and context-bound child loggers.
|
|
4
|
+
|
|
5
|
+
Part of [Lumi CMS](https://github.com/murumets-ee/lumi-cms) — a modular, type-safe CMS toolkit for Node.js.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @murumets-ee/logging
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## License
|
|
14
|
+
|
|
15
|
+
[Elastic License 2.0 (ELv2)](../../LICENSE)
|
package/dist/admin.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit log admin routes for the centralized admin API handler.
|
|
3
|
+
*
|
|
4
|
+
* Read-only: only GET handlers. Audit logs are immutable.
|
|
5
|
+
* Admin-only: explicit role check before any data access.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { createAdminApiHandler } from '@murumets-ee/admin-ui/server'
|
|
10
|
+
* import { logRoutes } from '@murumets-ee/logging/admin'
|
|
11
|
+
* import { AuditLogClient } from '@murumets-ee/logging'
|
|
12
|
+
*
|
|
13
|
+
* const handler = createAdminApiHandler({
|
|
14
|
+
* authenticate: async (req) => { ... },
|
|
15
|
+
* entities: [...],
|
|
16
|
+
* routes: [logRoutes(() => new AuditLogClient(db))],
|
|
17
|
+
* })
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
interface AdminRoute {
|
|
21
|
+
prefix: string;
|
|
22
|
+
resource?: string;
|
|
23
|
+
actions?: readonly string[];
|
|
24
|
+
handlers: Partial<Record<string, (req: Request, ctx: {
|
|
25
|
+
segments: string[];
|
|
26
|
+
user: {
|
|
27
|
+
id: string;
|
|
28
|
+
role?: string;
|
|
29
|
+
};
|
|
30
|
+
checkPermission: (resource: string, action: string) => boolean;
|
|
31
|
+
}) => Promise<Response>>>;
|
|
32
|
+
}
|
|
33
|
+
interface AuditLogClientLike {
|
|
34
|
+
query(options: Record<string, unknown>): Promise<{
|
|
35
|
+
items: unknown[];
|
|
36
|
+
total: number;
|
|
37
|
+
}>;
|
|
38
|
+
findById(id: string): Promise<unknown | null>;
|
|
39
|
+
getDistinctEntityTypes(): Promise<string[]>;
|
|
40
|
+
getDistinctActions(): Promise<string[]>;
|
|
41
|
+
}
|
|
42
|
+
declare function logRoutes(getClient: () => AuditLogClientLike): AdminRoute;
|
|
43
|
+
|
|
44
|
+
export { logRoutes };
|
package/dist/admin.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{z as e}from"zod";var d=/^[a-zA-Z0-9_-]{1,255}$/,f=e.object({action:e.string().max(100).optional(),entityType:e.string().max(100).optional(),entityId:e.string().regex(d,"Invalid ID format").optional(),userId:e.string().regex(d,"Invalid user ID format").optional(),dateFrom:e.string().datetime({offset:!0,message:"Invalid ISO date"}).optional(),dateTo:e.string().datetime({offset:!0,message:"Invalid ISO date"}).optional(),search:e.string().max(200).optional(),limit:e.coerce.number().min(1).max(100).default(50),offset:e.coerce.number().min(0).default(0),sortField:e.enum(["createdAt","action","entityType"]).default("createdAt"),sortDirection:e.enum(["asc","desc"]).default("desc")});function a(r,i=200){return new Response(JSON.stringify(r),{status:i,headers:{"Content-Type":"application/json"}})}function u(r,i){return a({error:r},i)}function p(r){return{prefix:"logs",resource:"audit-logs",actions:["view"],handlers:{GET:async(i,{segments:o})=>{let s=r();if(o.length===1&&o[0]==="filters"){let[n,g]=await Promise.all([s.getDistinctEntityTypes(),s.getDistinctActions()]);return a({entityTypes:n,actions:g})}if(o.length===1&&o[0]!=="filters"){let n=await s.findById(o[0]);return n?a(n):u("Audit log entry not found",404)}let c=new URL(i.url),l=Object.fromEntries(c.searchParams),t=f.safeParse(l);if(!t.success)return u(`Invalid query params: ${t.error.issues.map(n=>n.message).join(", ")}`,400);let m=await s.query({...t.data,dateFrom:t.data.dateFrom?new Date(t.data.dateFrom):void 0,dateTo:t.data.dateTo?new Date(t.data.dateTo):void 0});return a(m)}}}}export{p as logRoutes};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/admin/routes.ts"],"sourcesContent":["/**\n * Audit log admin routes for the centralized admin API handler.\n *\n * Read-only: only GET handlers. Audit logs are immutable.\n * Admin-only: explicit role check before any data access.\n *\n * @example\n * ```typescript\n * import { createAdminApiHandler } from '@murumets-ee/admin-ui/server'\n * import { logRoutes } from '@murumets-ee/logging/admin'\n * import { AuditLogClient } from '@murumets-ee/logging'\n *\n * const handler = createAdminApiHandler({\n * authenticate: async (req) => { ... },\n * entities: [...],\n * routes: [logRoutes(() => new AuditLogClient(db))],\n * })\n * ```\n */\n\nimport { z } from 'zod'\n\n// ---------------------------------------------------------------------------\n// Local route type — avoids circular build dep: logging → core → logging.\n// Structurally compatible with AdminRoute from @murumets-ee/core.\n// ---------------------------------------------------------------------------\n\ninterface AdminRoute {\n prefix: string\n resource?: string\n actions?: readonly string[]\n handlers: Partial<\n Record<\n string,\n (\n req: Request,\n ctx: {\n segments: string[]\n user: { id: string; role?: string }\n checkPermission: (resource: string, action: string) => boolean\n },\n ) => Promise<Response>\n >\n >\n}\n\n// ---------------------------------------------------------------------------\n// Query param validation\n// ---------------------------------------------------------------------------\n\nconst ID_REGEX = /^[a-zA-Z0-9_-]{1,255}$/\n\nconst auditLogQuerySchema = z.object({\n action: z.string().max(100).optional(),\n entityType: z.string().max(100).optional(),\n entityId: z.string().regex(ID_REGEX, 'Invalid ID format').optional(),\n userId: z.string().regex(ID_REGEX, 'Invalid user ID format').optional(),\n dateFrom: z.string().datetime({ offset: true, message: 'Invalid ISO date' }).optional(),\n dateTo: z.string().datetime({ offset: true, message: 'Invalid ISO date' }).optional(),\n search: z.string().max(200).optional(),\n limit: z.coerce.number().min(1).max(100).default(50),\n offset: z.coerce.number().min(0).default(0),\n sortField: z.enum(['createdAt', 'action', 'entityType']).default('createdAt'),\n sortDirection: z.enum(['asc', 'desc']).default('desc'),\n})\n\n// ---------------------------------------------------------------------------\n// Response helpers\n// ---------------------------------------------------------------------------\n\nfunction json(data: unknown, status = 200): Response {\n return new Response(JSON.stringify(data), {\n status,\n headers: { 'Content-Type': 'application/json' },\n })\n}\n\nfunction errorJson(message: string, status: number): Response {\n return json({ error: message }, status)\n}\n\n// ---------------------------------------------------------------------------\n// AuditLogClient interface (avoids importing from ../audit-client.js)\n// ---------------------------------------------------------------------------\n\ninterface AuditLogClientLike {\n query(options: Record<string, unknown>): Promise<{ items: unknown[]; total: number }>\n findById(id: string): Promise<unknown | null>\n getDistinctEntityTypes(): Promise<string[]>\n getDistinctActions(): Promise<string[]>\n}\n\n// ---------------------------------------------------------------------------\n// Route factory\n// ---------------------------------------------------------------------------\n\nexport function logRoutes(getClient: () => AuditLogClientLike): AdminRoute {\n return {\n prefix: 'logs',\n resource: 'audit-logs',\n actions: ['view'],\n handlers: {\n GET: async (req, { segments }) => {\n // Permission check handled by framework via resource: 'audit-logs'\n const client = getClient()\n\n // GET /logs/filters — distinct values for filter dropdowns\n if (segments.length === 1 && segments[0] === 'filters') {\n const [entityTypes, actions] = await Promise.all([\n client.getDistinctEntityTypes(),\n client.getDistinctActions(),\n ])\n return json({ entityTypes, actions })\n }\n\n // GET /logs/:id — single entry detail\n if (segments.length === 1 && segments[0] !== 'filters') {\n const entry = await client.findById(segments[0])\n if (!entry) return errorJson('Audit log entry not found', 404)\n return json(entry)\n }\n\n // GET /logs — list with filters + pagination\n const url = new URL(req.url)\n const params = Object.fromEntries(url.searchParams)\n const parsed = auditLogQuerySchema.safeParse(params)\n if (!parsed.success) {\n return errorJson(\n `Invalid query params: ${parsed.error.issues.map((i) => i.message).join(', ')}`,\n 400,\n )\n }\n\n const result = await client.query({\n ...parsed.data,\n dateFrom: parsed.data.dateFrom ? new Date(parsed.data.dateFrom) : undefined,\n dateTo: parsed.data.dateTo ? new Date(parsed.data.dateTo) : undefined,\n })\n\n return json(result)\n },\n // No POST, PATCH, DELETE — audit logs are append-only\n },\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{index as e,jsonb as i,pgTable as n,timestamp as a,uuid as r,varchar as d}from"drizzle-orm/pg-core";var _=n("toolkit_audit_logs",{id:r("id").primaryKey().defaultRandom(),action:d("action",{length:100}).notNull(),entityType:d("entity_type",{length:100}),entityId:d("entity_id",{length:255}),userId:d("user_id",{length:255}),userName:d("user_name",{length:255}),changes:i("changes").$type(),metadata:i("metadata").$type(),createdAt:a("created_at",{withTimezone:!0}).notNull().defaultNow()},t=>({entityTypeCreatedAtIdx:e("audit_entity_type_created_at_idx").on(t.entityType,t.createdAt),userIdCreatedAtIdx:e("audit_user_id_created_at_idx").on(t.userId,t.createdAt),actionCreatedAtIdx:e("audit_action_created_at_idx").on(t.action,t.createdAt),createdAtIdx:e("audit_created_at_idx").on(t.createdAt),entityIdIdx:e("audit_entity_id_idx").on(t.entityId)}));export{_ as a};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// src/schema.ts
|
|
2
|
+
import { index, jsonb, pgTable, timestamp, uuid, varchar } from "drizzle-orm/pg-core";
|
|
3
|
+
var toolkitAuditLogs = pgTable(
|
|
4
|
+
"toolkit_audit_logs",
|
|
5
|
+
{
|
|
6
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
7
|
+
action: varchar("action", { length: 100 }).notNull(),
|
|
8
|
+
entityType: varchar("entity_type", { length: 100 }),
|
|
9
|
+
entityId: varchar("entity_id", { length: 255 }),
|
|
10
|
+
userId: varchar("user_id", { length: 255 }),
|
|
11
|
+
userName: varchar("user_name", { length: 255 }),
|
|
12
|
+
changes: jsonb("changes").$type(),
|
|
13
|
+
metadata: jsonb("metadata").$type(),
|
|
14
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
|
|
15
|
+
},
|
|
16
|
+
(table) => ({
|
|
17
|
+
entityTypeCreatedAtIdx: index("audit_entity_type_created_at_idx").on(
|
|
18
|
+
table.entityType,
|
|
19
|
+
table.createdAt
|
|
20
|
+
),
|
|
21
|
+
userIdCreatedAtIdx: index("audit_user_id_created_at_idx").on(table.userId, table.createdAt),
|
|
22
|
+
actionCreatedAtIdx: index("audit_action_created_at_idx").on(table.action, table.createdAt),
|
|
23
|
+
createdAtIdx: index("audit_created_at_idx").on(table.createdAt),
|
|
24
|
+
entityIdIdx: index("audit_entity_id_idx").on(table.entityId)
|
|
25
|
+
})
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
export {
|
|
29
|
+
toolkitAuditLogs
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=chunk-XTE6WERT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/schema.ts"],"sourcesContent":["import { index, jsonb, pgTable, timestamp, uuid, varchar } from 'drizzle-orm/pg-core'\n\nexport const toolkitAuditLogs = pgTable(\n 'toolkit_audit_logs',\n {\n id: uuid('id').primaryKey().defaultRandom(),\n action: varchar('action', { length: 100 }).notNull(),\n entityType: varchar('entity_type', { length: 100 }),\n entityId: varchar('entity_id', { length: 255 }),\n userId: varchar('user_id', { length: 255 }),\n userName: varchar('user_name', { length: 255 }),\n changes: jsonb('changes').$type<Record<string, unknown>>(),\n metadata: jsonb('metadata').$type<Record<string, unknown>>(),\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => ({\n entityTypeCreatedAtIdx: index('audit_entity_type_created_at_idx').on(\n table.entityType,\n table.createdAt,\n ),\n userIdCreatedAtIdx: index('audit_user_id_created_at_idx').on(table.userId, table.createdAt),\n actionCreatedAtIdx: index('audit_action_created_at_idx').on(table.action, table.createdAt),\n createdAtIdx: index('audit_created_at_idx').on(table.createdAt),\n entityIdIdx: index('audit_entity_id_idx').on(table.entityId),\n }),\n)\n"],"mappings":";AAAA,SAAS,OAAO,OAAO,SAAS,WAAW,MAAM,eAAe;AAEzD,IAAM,mBAAmB;AAAA,EAC9B;AAAA,EACA;AAAA,IACE,IAAI,KAAK,IAAI,EAAE,WAAW,EAAE,cAAc;AAAA,IAC1C,QAAQ,QAAQ,UAAU,EAAE,QAAQ,IAAI,CAAC,EAAE,QAAQ;AAAA,IACnD,YAAY,QAAQ,eAAe,EAAE,QAAQ,IAAI,CAAC;AAAA,IAClD,UAAU,QAAQ,aAAa,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC9C,QAAQ,QAAQ,WAAW,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC1C,UAAU,QAAQ,aAAa,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC9C,SAAS,MAAM,SAAS,EAAE,MAA+B;AAAA,IACzD,UAAU,MAAM,UAAU,EAAE,MAA+B;AAAA,IAC3D,WAAW,UAAU,cAAc,EAAE,cAAc,KAAK,CAAC,EAAE,QAAQ,EAAE,WAAW;AAAA,EAClF;AAAA,EACA,CAAC,WAAW;AAAA,IACV,wBAAwB,MAAM,kCAAkC,EAAE;AAAA,MAChE,MAAM;AAAA,MACN,MAAM;AAAA,IACR;AAAA,IACA,oBAAoB,MAAM,8BAA8B,EAAE,GAAG,MAAM,QAAQ,MAAM,SAAS;AAAA,IAC1F,oBAAoB,MAAM,6BAA6B,EAAE,GAAG,MAAM,QAAQ,MAAM,SAAS;AAAA,IACzF,cAAc,MAAM,sBAAsB,EAAE,GAAG,MAAM,SAAS;AAAA,IAC9D,aAAa,MAAM,qBAAqB,EAAE,GAAG,MAAM,QAAQ;AAAA,EAC7D;AACF;","names":[]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { PostgresJsDatabase } from 'drizzle-orm/postgres-js';
|
|
2
|
+
import { Logger as Logger$1 } from 'pino';
|
|
3
|
+
export { toolkitAuditLogs } from './schema.js';
|
|
4
|
+
import 'drizzle-orm/pg-core';
|
|
5
|
+
|
|
6
|
+
type Logger = Logger$1;
|
|
7
|
+
interface LoggerConfig {
|
|
8
|
+
name?: string;
|
|
9
|
+
level?: string;
|
|
10
|
+
redact?: string[];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Create a logger instance
|
|
14
|
+
* If no config provided, returns the root logger
|
|
15
|
+
* If config provided, returns a child logger with the specified context
|
|
16
|
+
*/
|
|
17
|
+
declare function createLogger(config?: LoggerConfig): Logger;
|
|
18
|
+
/**
|
|
19
|
+
* Create a child logger from an existing logger with additional context
|
|
20
|
+
*/
|
|
21
|
+
declare function createChildLogger(parent: Logger, context: Record<string, unknown>): Logger;
|
|
22
|
+
|
|
23
|
+
interface AuditEntry {
|
|
24
|
+
action: string;
|
|
25
|
+
entityType?: string;
|
|
26
|
+
entityId?: string;
|
|
27
|
+
userId?: string;
|
|
28
|
+
userName?: string;
|
|
29
|
+
changes?: Record<string, unknown>;
|
|
30
|
+
metadata?: Record<string, unknown>;
|
|
31
|
+
}
|
|
32
|
+
interface AuditConfig {
|
|
33
|
+
logger: Logger;
|
|
34
|
+
dbWriter?: (entry: AuditEntry) => Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
interface AuditLogger {
|
|
37
|
+
log: (entry: AuditEntry) => Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Create a dbWriter callback wired to AuditLogClient.
|
|
41
|
+
*
|
|
42
|
+
* Pass the returned function as `dbWriter` to `createAuditLogger`:
|
|
43
|
+
* ```typescript
|
|
44
|
+
* const auditLogger = createAuditLogger({
|
|
45
|
+
* logger,
|
|
46
|
+
* dbWriter: createAuditDbWriter(db),
|
|
47
|
+
* })
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
declare function createAuditDbWriter(db: PostgresJsDatabase): (entry: AuditEntry) => Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Create an audit logger
|
|
53
|
+
*
|
|
54
|
+
* Audit logs are written to stdout immediately (non-blocking).
|
|
55
|
+
* Optionally, they can also be written to the database if dbWriter is provided.
|
|
56
|
+
*
|
|
57
|
+
* Database writes are fire-and-forget to avoid blocking the main operation.
|
|
58
|
+
* If DB write fails, it's logged to stderr but doesn't throw.
|
|
59
|
+
*/
|
|
60
|
+
declare function createAuditLogger(config: AuditConfig): AuditLogger;
|
|
61
|
+
|
|
62
|
+
interface AuditLogQueryOptions {
|
|
63
|
+
action?: string;
|
|
64
|
+
entityType?: string;
|
|
65
|
+
entityId?: string;
|
|
66
|
+
userId?: string;
|
|
67
|
+
dateFrom?: Date;
|
|
68
|
+
dateTo?: Date;
|
|
69
|
+
/** Free-text search across action, entityType, userName */
|
|
70
|
+
search?: string;
|
|
71
|
+
/** Default 50, max 100 */
|
|
72
|
+
limit?: number;
|
|
73
|
+
offset?: number;
|
|
74
|
+
sortField?: 'createdAt' | 'action' | 'entityType';
|
|
75
|
+
sortDirection?: 'asc' | 'desc';
|
|
76
|
+
}
|
|
77
|
+
interface AuditLogEntry {
|
|
78
|
+
id: string;
|
|
79
|
+
action: string;
|
|
80
|
+
entityType: string | null;
|
|
81
|
+
entityId: string | null;
|
|
82
|
+
userId: string | null;
|
|
83
|
+
userName: string | null;
|
|
84
|
+
changes: Record<string, unknown> | null;
|
|
85
|
+
metadata: Record<string, unknown> | null;
|
|
86
|
+
createdAt: Date;
|
|
87
|
+
}
|
|
88
|
+
interface AuditLogListResult {
|
|
89
|
+
items: AuditLogEntry[];
|
|
90
|
+
total: number;
|
|
91
|
+
}
|
|
92
|
+
declare class AuditLogClient {
|
|
93
|
+
private db;
|
|
94
|
+
constructor(db: PostgresJsDatabase);
|
|
95
|
+
/** Write a single audit log entry */
|
|
96
|
+
write(entry: Omit<AuditLogEntry, 'id' | 'createdAt'>): Promise<void>;
|
|
97
|
+
/** Query audit logs with filters and pagination */
|
|
98
|
+
query(options?: AuditLogQueryOptions): Promise<AuditLogListResult>;
|
|
99
|
+
/** Get a single audit log entry by ID */
|
|
100
|
+
findById(id: string): Promise<AuditLogEntry | null>;
|
|
101
|
+
/** Get distinct entity types present in the audit log */
|
|
102
|
+
getDistinctEntityTypes(): Promise<string[]>;
|
|
103
|
+
/** Get distinct actions present in the audit log */
|
|
104
|
+
getDistinctActions(): Promise<string[]>;
|
|
105
|
+
private buildConditions;
|
|
106
|
+
private buildOrderBy;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
interface RequestContext {
|
|
110
|
+
requestId?: string;
|
|
111
|
+
userId?: string;
|
|
112
|
+
teamId?: string;
|
|
113
|
+
locale?: string;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Bind request context to a logger
|
|
117
|
+
* Returns a child logger with the context automatically included in all log entries
|
|
118
|
+
*/
|
|
119
|
+
declare function bindRequestContext(logger: Logger, context: RequestContext): Logger;
|
|
120
|
+
|
|
121
|
+
export { type AuditConfig, type AuditEntry, AuditLogClient, type AuditLogEntry, type AuditLogListResult, type AuditLogQueryOptions, type AuditLogger, type Logger, type LoggerConfig, type RequestContext, bindRequestContext, createAuditDbWriter, createAuditLogger, createChildLogger, createLogger };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as r}from"./chunk-PQXD7TOP.js";import{and as f,asc as a,count as L,desc as A,eq as o,gte as h,ilike as d,isNotNull as I,lte as T,or as w}from"drizzle-orm";var b=100,x=50,s=class{constructor(t){this.db=t}async write(t){await this.db.insert(r).values({action:t.action,entityType:t.entityType,entityId:t.entityId,userId:t.userId,userName:t.userName,changes:t.changes,metadata:t.metadata})}async query(t={}){let e=Math.min(Math.max(t.limit??x,1),b),n=Math.max(t.offset??0,0),g=this.buildConditions(t),c=g.length>0?f(...g):void 0,y=this.buildOrderBy(t.sortField,t.sortDirection),[m,p]=await Promise.all([this.db.select().from(r).where(c).orderBy(y).limit(e).offset(n),this.db.select({count:L()}).from(r).where(c)]);return{items:m,total:p[0]?.count??0}}async findById(t){return(await this.db.select().from(r).where(o(r.id,t)).limit(1))[0]??null}async getDistinctEntityTypes(){return(await this.db.selectDistinct({entityType:r.entityType}).from(r).where(I(r.entityType)).orderBy(a(r.entityType))).map(e=>e.entityType).filter(Boolean)}async getDistinctActions(){return(await this.db.selectDistinct({action:r.action}).from(r).orderBy(a(r.action))).map(e=>e.action)}buildConditions(t){let e=[];if(t.action&&e.push(o(r.action,t.action)),t.entityType&&e.push(o(r.entityType,t.entityType)),t.entityId&&e.push(o(r.entityId,t.entityId)),t.userId&&e.push(o(r.userId,t.userId)),t.dateFrom&&e.push(h(r.createdAt,t.dateFrom)),t.dateTo&&e.push(T(r.createdAt,t.dateTo)),t.search){let n=`%${t.search}%`;e.push(w(d(r.action,n),d(r.entityType,n),d(r.userName,n)))}return e}buildOrderBy(t,e){let n=e==="asc"?a:A;switch(t){case"action":return n(r.action);case"entityType":return n(r.entityType);default:return n(r.createdAt)}}};function E(i){let t=new s(i);return e=>t.write({action:e.action,entityType:e.entityType??null,entityId:e.entityId??null,userId:e.userId??null,userName:e.userName??null,changes:e.changes??null,metadata:e.metadata??null})}function D(i){return{log:async t=>{i.logger.info({audit:!0,action:t.action,entityType:t.entityType,entityId:t.entityId,userId:t.userId,userName:t.userName,changes:t.changes,metadata:t.metadata},`Audit: ${t.action}`),i.dbWriter&&i.dbWriter(t).catch(e=>{i.logger.error({err:e,auditEntry:t},"Failed to write audit log to database")})}}}function v(i,t){return i.child(t)}import u from"pino";var l=u({level:process.env.LOG_LEVEL||"info",formatters:{level:i=>({level:i})},timestamp:!1,serializers:{err:u.stdSerializers.err,error:u.stdSerializers.err},redact:{paths:["password","token","secret","apiKey","accessToken","refreshToken"],censor:"[REDACTED]"}});function C(i){if(!i)return l;let t={};i.name&&(t.name=i.name);let e={};return i.level&&(e.level=i.level),l.child(t,e)}function R(i,t){return i.child(t)}export{s as AuditLogClient,v as bindRequestContext,E as createAuditDbWriter,D as createAuditLogger,R as createChildLogger,C as createLogger,r as toolkitAuditLogs};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/audit-client.ts","../src/audit.ts","../src/context.ts","../src/logger.ts"],"sourcesContent":["import { and, asc, count, desc, eq, gte, ilike, isNotNull, lte, or, type SQL } from 'drizzle-orm'\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js'\nimport { toolkitAuditLogs } from './schema.js'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface AuditLogQueryOptions {\n action?: string\n entityType?: string\n entityId?: string\n userId?: string\n dateFrom?: Date\n dateTo?: Date\n /** Free-text search across action, entityType, userName */\n search?: string\n /** Default 50, max 100 */\n limit?: number\n offset?: number\n sortField?: 'createdAt' | 'action' | 'entityType'\n sortDirection?: 'asc' | 'desc'\n}\n\nexport interface AuditLogEntry {\n id: string\n action: string\n entityType: string | null\n entityId: string | null\n userId: string | null\n userName: string | null\n changes: Record<string, unknown> | null\n metadata: Record<string, unknown> | null\n createdAt: Date\n}\n\nexport interface AuditLogListResult {\n items: AuditLogEntry[]\n total: number\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst MAX_LIMIT = 100\nconst DEFAULT_LIMIT = 50\n\n// ---------------------------------------------------------------------------\n// Client\n// ---------------------------------------------------------------------------\n\nexport class AuditLogClient {\n constructor(private db: PostgresJsDatabase) {}\n\n /** Write a single audit log entry */\n async write(entry: Omit<AuditLogEntry, 'id' | 'createdAt'>): Promise<void> {\n await this.db.insert(toolkitAuditLogs).values({\n action: entry.action,\n entityType: entry.entityType,\n entityId: entry.entityId,\n userId: entry.userId,\n userName: entry.userName,\n changes: entry.changes,\n metadata: entry.metadata,\n })\n }\n\n /** Query audit logs with filters and pagination */\n async query(options: AuditLogQueryOptions = {}): Promise<AuditLogListResult> {\n const limit = Math.min(Math.max(options.limit ?? DEFAULT_LIMIT, 1), MAX_LIMIT)\n const offset = Math.max(options.offset ?? 0, 0)\n\n const conditions = this.buildConditions(options)\n const where = conditions.length > 0 ? and(...conditions) : undefined\n const orderBy = this.buildOrderBy(options.sortField, options.sortDirection)\n\n const [items, totalResult] = await Promise.all([\n this.db\n .select()\n .from(toolkitAuditLogs)\n .where(where)\n .orderBy(orderBy)\n .limit(limit)\n .offset(offset),\n this.db.select({ count: count() }).from(toolkitAuditLogs).where(where),\n ])\n\n return {\n items: items as AuditLogEntry[],\n total: totalResult[0]?.count ?? 0,\n }\n }\n\n /** Get a single audit log entry by ID */\n async findById(id: string): Promise<AuditLogEntry | null> {\n const rows = await this.db\n .select()\n .from(toolkitAuditLogs)\n .where(eq(toolkitAuditLogs.id, id))\n .limit(1)\n\n return (rows[0] as AuditLogEntry) ?? null\n }\n\n /** Get distinct entity types present in the audit log */\n async getDistinctEntityTypes(): Promise<string[]> {\n const rows = await this.db\n .selectDistinct({ entityType: toolkitAuditLogs.entityType })\n .from(toolkitAuditLogs)\n .where(isNotNull(toolkitAuditLogs.entityType))\n .orderBy(asc(toolkitAuditLogs.entityType))\n\n return rows.map((r) => r.entityType!).filter(Boolean)\n }\n\n /** Get distinct actions present in the audit log */\n async getDistinctActions(): Promise<string[]> {\n const rows = await this.db\n .selectDistinct({ action: toolkitAuditLogs.action })\n .from(toolkitAuditLogs)\n .orderBy(asc(toolkitAuditLogs.action))\n\n return rows.map((r) => r.action)\n }\n\n // -------------------------------------------------------------------------\n // Private helpers\n // -------------------------------------------------------------------------\n\n private buildConditions(options: AuditLogQueryOptions): SQL[] {\n const conditions: SQL[] = []\n\n if (options.action) {\n conditions.push(eq(toolkitAuditLogs.action, options.action))\n }\n if (options.entityType) {\n conditions.push(eq(toolkitAuditLogs.entityType, options.entityType))\n }\n if (options.entityId) {\n conditions.push(eq(toolkitAuditLogs.entityId, options.entityId))\n }\n if (options.userId) {\n conditions.push(eq(toolkitAuditLogs.userId, options.userId))\n }\n if (options.dateFrom) {\n conditions.push(gte(toolkitAuditLogs.createdAt, options.dateFrom))\n }\n if (options.dateTo) {\n conditions.push(lte(toolkitAuditLogs.createdAt, options.dateTo))\n }\n if (options.search) {\n const pattern = `%${options.search}%`\n conditions.push(\n or(\n ilike(toolkitAuditLogs.action, pattern),\n ilike(toolkitAuditLogs.entityType, pattern),\n ilike(toolkitAuditLogs.userName, pattern),\n )!,\n )\n }\n\n return conditions\n }\n\n private buildOrderBy(sortField?: string, sortDirection?: string): SQL {\n const dirFn = sortDirection === 'asc' ? asc : desc\n switch (sortField) {\n case 'action':\n return dirFn(toolkitAuditLogs.action)\n case 'entityType':\n return dirFn(toolkitAuditLogs.entityType)\n case 'createdAt':\n default:\n return dirFn(toolkitAuditLogs.createdAt)\n }\n }\n}\n","import type { PostgresJsDatabase } from 'drizzle-orm/postgres-js'\nimport { AuditLogClient } from './audit-client.js'\nimport type { Logger } from './logger.js'\n\nexport interface AuditEntry {\n action: string\n entityType?: string\n entityId?: string\n userId?: string\n userName?: string\n changes?: Record<string, unknown>\n metadata?: Record<string, unknown>\n}\n\nexport interface AuditConfig {\n logger: Logger\n dbWriter?: (entry: AuditEntry) => Promise<void>\n}\n\nexport interface AuditLogger {\n log: (entry: AuditEntry) => Promise<void>\n}\n\n/**\n * Create a dbWriter callback wired to AuditLogClient.\n *\n * Pass the returned function as `dbWriter` to `createAuditLogger`:\n * ```typescript\n * const auditLogger = createAuditLogger({\n * logger,\n * dbWriter: createAuditDbWriter(db),\n * })\n * ```\n */\nexport function createAuditDbWriter(db: PostgresJsDatabase): (entry: AuditEntry) => Promise<void> {\n const client = new AuditLogClient(db)\n return (entry) =>\n client.write({\n action: entry.action,\n entityType: entry.entityType ?? null,\n entityId: entry.entityId ?? null,\n userId: entry.userId ?? null,\n userName: entry.userName ?? null,\n changes: entry.changes ?? null,\n metadata: entry.metadata ?? null,\n })\n}\n\n/**\n * Create an audit logger\n *\n * Audit logs are written to stdout immediately (non-blocking).\n * Optionally, they can also be written to the database if dbWriter is provided.\n *\n * Database writes are fire-and-forget to avoid blocking the main operation.\n * If DB write fails, it's logged to stderr but doesn't throw.\n */\nexport function createAuditLogger(config: AuditConfig): AuditLogger {\n return {\n log: async (entry: AuditEntry) => {\n // Log to stdout immediately (structured log with audit: true marker)\n config.logger.info(\n {\n audit: true,\n action: entry.action,\n entityType: entry.entityType,\n entityId: entry.entityId,\n userId: entry.userId,\n userName: entry.userName,\n changes: entry.changes,\n metadata: entry.metadata,\n },\n `Audit: ${entry.action}`,\n )\n\n // Write to DB if configured (fire and forget)\n if (config.dbWriter) {\n config.dbWriter(entry).catch((err) => {\n config.logger.error({ err, auditEntry: entry }, 'Failed to write audit log to database')\n })\n }\n },\n }\n}\n","import type { Logger } from './logger.js'\n\nexport interface RequestContext {\n requestId?: string\n userId?: string\n teamId?: string\n locale?: string\n}\n\n/**\n * Bind request context to a logger\n * Returns a child logger with the context automatically included in all log entries\n */\nexport function bindRequestContext(logger: Logger, context: RequestContext): Logger {\n return logger.child(context)\n}\n","import pino, { type Logger as PinoLogger } from 'pino'\n\nexport type Logger = PinoLogger\n\nexport interface LoggerConfig {\n name?: string\n level?: string\n redact?: string[]\n}\n\n/**\n * Root logger instance\n *\n * IMPORTANT: No transports are used to avoid Next.js bundler issues.\n * Pino transports use worker threads that break webpack/turbopack.\n *\n * For dev pretty-printing, pipe to pino-pretty:\n * pnpm dev | pnpm pino-pretty\n */\nconst rootLogger = pino({\n level: process.env.LOG_LEVEL || 'info',\n formatters: {\n level: (label) => ({ level: label }),\n },\n timestamp: false,\n serializers: {\n err: pino.stdSerializers.err,\n error: pino.stdSerializers.err,\n },\n redact: {\n paths: ['password', 'token', 'secret', 'apiKey', 'accessToken', 'refreshToken'],\n censor: '[REDACTED]',\n },\n})\n\n/**\n * Create a logger instance\n * If no config provided, returns the root logger\n * If config provided, returns a child logger with the specified context\n */\nexport function createLogger(config?: LoggerConfig): Logger {\n if (!config) {\n return rootLogger\n }\n\n const bindings: Record<string, unknown> = {}\n if (config.name) {\n bindings.name = config.name\n }\n\n const options: { level?: string } = {}\n if (config.level) {\n options.level = config.level\n }\n\n return rootLogger.child(bindings, options)\n}\n\n/**\n * Create a child logger from an existing logger with additional context\n */\nexport function createChildLogger(parent: Logger, context: Record<string, unknown>): Logger {\n return parent.child(context)\n}\n"],"mappings":"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","names":[]}
|
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
|
|
2
|
+
|
|
3
|
+
declare const toolkitAuditLogs: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
4
|
+
name: "toolkit_audit_logs";
|
|
5
|
+
schema: undefined;
|
|
6
|
+
columns: {
|
|
7
|
+
id: drizzle_orm_pg_core.PgColumn<{
|
|
8
|
+
name: "id";
|
|
9
|
+
tableName: "toolkit_audit_logs";
|
|
10
|
+
dataType: "string";
|
|
11
|
+
columnType: "PgUUID";
|
|
12
|
+
data: string;
|
|
13
|
+
driverParam: string;
|
|
14
|
+
notNull: true;
|
|
15
|
+
hasDefault: true;
|
|
16
|
+
isPrimaryKey: true;
|
|
17
|
+
isAutoincrement: false;
|
|
18
|
+
hasRuntimeDefault: false;
|
|
19
|
+
enumValues: undefined;
|
|
20
|
+
baseColumn: never;
|
|
21
|
+
identity: undefined;
|
|
22
|
+
generated: undefined;
|
|
23
|
+
}, {}, {}>;
|
|
24
|
+
action: drizzle_orm_pg_core.PgColumn<{
|
|
25
|
+
name: "action";
|
|
26
|
+
tableName: "toolkit_audit_logs";
|
|
27
|
+
dataType: "string";
|
|
28
|
+
columnType: "PgVarchar";
|
|
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: 100;
|
|
42
|
+
}>;
|
|
43
|
+
entityType: drizzle_orm_pg_core.PgColumn<{
|
|
44
|
+
name: "entity_type";
|
|
45
|
+
tableName: "toolkit_audit_logs";
|
|
46
|
+
dataType: "string";
|
|
47
|
+
columnType: "PgVarchar";
|
|
48
|
+
data: string;
|
|
49
|
+
driverParam: string;
|
|
50
|
+
notNull: false;
|
|
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: 100;
|
|
61
|
+
}>;
|
|
62
|
+
entityId: drizzle_orm_pg_core.PgColumn<{
|
|
63
|
+
name: "entity_id";
|
|
64
|
+
tableName: "toolkit_audit_logs";
|
|
65
|
+
dataType: "string";
|
|
66
|
+
columnType: "PgVarchar";
|
|
67
|
+
data: string;
|
|
68
|
+
driverParam: string;
|
|
69
|
+
notNull: false;
|
|
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: 255;
|
|
80
|
+
}>;
|
|
81
|
+
userId: drizzle_orm_pg_core.PgColumn<{
|
|
82
|
+
name: "user_id";
|
|
83
|
+
tableName: "toolkit_audit_logs";
|
|
84
|
+
dataType: "string";
|
|
85
|
+
columnType: "PgVarchar";
|
|
86
|
+
data: string;
|
|
87
|
+
driverParam: string;
|
|
88
|
+
notNull: false;
|
|
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: 255;
|
|
99
|
+
}>;
|
|
100
|
+
userName: drizzle_orm_pg_core.PgColumn<{
|
|
101
|
+
name: "user_name";
|
|
102
|
+
tableName: "toolkit_audit_logs";
|
|
103
|
+
dataType: "string";
|
|
104
|
+
columnType: "PgVarchar";
|
|
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: 255;
|
|
118
|
+
}>;
|
|
119
|
+
changes: drizzle_orm_pg_core.PgColumn<{
|
|
120
|
+
name: "changes";
|
|
121
|
+
tableName: "toolkit_audit_logs";
|
|
122
|
+
dataType: "json";
|
|
123
|
+
columnType: "PgJsonb";
|
|
124
|
+
data: Record<string, unknown>;
|
|
125
|
+
driverParam: unknown;
|
|
126
|
+
notNull: false;
|
|
127
|
+
hasDefault: false;
|
|
128
|
+
isPrimaryKey: false;
|
|
129
|
+
isAutoincrement: false;
|
|
130
|
+
hasRuntimeDefault: false;
|
|
131
|
+
enumValues: undefined;
|
|
132
|
+
baseColumn: never;
|
|
133
|
+
identity: undefined;
|
|
134
|
+
generated: undefined;
|
|
135
|
+
}, {}, {
|
|
136
|
+
$type: Record<string, unknown>;
|
|
137
|
+
}>;
|
|
138
|
+
metadata: drizzle_orm_pg_core.PgColumn<{
|
|
139
|
+
name: "metadata";
|
|
140
|
+
tableName: "toolkit_audit_logs";
|
|
141
|
+
dataType: "json";
|
|
142
|
+
columnType: "PgJsonb";
|
|
143
|
+
data: Record<string, unknown>;
|
|
144
|
+
driverParam: unknown;
|
|
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
|
+
$type: Record<string, unknown>;
|
|
156
|
+
}>;
|
|
157
|
+
createdAt: drizzle_orm_pg_core.PgColumn<{
|
|
158
|
+
name: "created_at";
|
|
159
|
+
tableName: "toolkit_audit_logs";
|
|
160
|
+
dataType: "date";
|
|
161
|
+
columnType: "PgTimestamp";
|
|
162
|
+
data: Date;
|
|
163
|
+
driverParam: string;
|
|
164
|
+
notNull: true;
|
|
165
|
+
hasDefault: true;
|
|
166
|
+
isPrimaryKey: false;
|
|
167
|
+
isAutoincrement: false;
|
|
168
|
+
hasRuntimeDefault: false;
|
|
169
|
+
enumValues: undefined;
|
|
170
|
+
baseColumn: never;
|
|
171
|
+
identity: undefined;
|
|
172
|
+
generated: undefined;
|
|
173
|
+
}, {}, {}>;
|
|
174
|
+
};
|
|
175
|
+
dialect: "pg";
|
|
176
|
+
}>;
|
|
177
|
+
|
|
178
|
+
export { toolkitAuditLogs };
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a}from"./chunk-PQXD7TOP.js";export{a as toolkitAuditLogs};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@murumets-ee/logging",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "Elastic-2.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"import": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"./schema": {
|
|
12
|
+
"types": "./dist/schema.d.ts",
|
|
13
|
+
"import": "./dist/schema.js"
|
|
14
|
+
},
|
|
15
|
+
"./admin": {
|
|
16
|
+
"types": "./dist/admin.d.ts",
|
|
17
|
+
"import": "./dist/admin.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"drizzle-orm": ">=0.40.0",
|
|
25
|
+
"pino": "^9.5.0",
|
|
26
|
+
"zod": ">=3.0.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"tsup": "^8.3.5",
|
|
30
|
+
"typescript": "^5.7.2",
|
|
31
|
+
"vitest": "^2.1.8"
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsup",
|
|
35
|
+
"dev": "tsup --watch",
|
|
36
|
+
"test": "vitest"
|
|
37
|
+
}
|
|
38
|
+
}
|