@murumets-ee/logging 0.9.0 → 0.11.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/admin.mjs +1 -1
- package/dist/admin.mjs.map +1 -1
- package/package.json +5 -2
package/dist/admin.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{z as e}from"zod";const t=/^[a-zA-Z0-9_-]{1,255}$/,n=e.object({action:e.string().max(100).optional(),entityType:e.string().max(100).optional(),entityId:e.string().regex(t,`Invalid ID format`).optional(),userId:e.string().regex(t,`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 r(e,t=200){return new Response(JSON.stringify(e),{status:t,headers:{"Content-Type":`application/json`}})}function i(e,t){return r({error:e},t)}function a(e){return{prefix:`logs`,resource:`audit-logs`,actions:[`view`],handlers:{GET:async(t,{segments:a})=>{let o=e();if(a.length===1&&
|
|
1
|
+
import{z as e}from"zod";const t=/^[a-zA-Z0-9_-]{1,255}$/,n=e.object({action:e.string().max(100).optional(),entityType:e.string().max(100).optional(),entityId:e.string().regex(t,`Invalid ID format`).optional(),userId:e.string().regex(t,`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 r(e,t=200){return new Response(JSON.stringify(e),{status:t,headers:{"Content-Type":`application/json`}})}function i(e,t){return r({error:e},t)}function a(e){return{prefix:`logs`,resource:`audit-logs`,actions:[`view`],handlers:{GET:async(t,{segments:a})=>{let o=e(),s=a[0];if(a.length===1&&s===`filters`){let[e,t]=await Promise.all([o.getDistinctEntityTypes(),o.getDistinctActions()]);return r({entityTypes:e,actions:t})}if(a.length===1&&s!==void 0&&s!==`filters`){let e=await o.findById(s);return e?r(e):i(`Audit log entry not found`,404)}let c=new URL(t.url),l=Object.fromEntries(c.searchParams),u=n.safeParse(l);return u.success?r(await o.query({...u.data,dateFrom:u.data.dateFrom?new Date(u.data.dateFrom):void 0,dateTo:u.data.dateTo?new Date(u.data.dateTo):void 0})):i(`Invalid query params: ${u.error.issues.map(e=>e.message).join(`, `)}`,400)}}}}export{a as logRoutes};
|
|
2
2
|
//# sourceMappingURL=admin.mjs.map
|
package/dist/admin.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin.mjs","names":[],"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 &&
|
|
1
|
+
{"version":3,"file":"admin.mjs","names":[],"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 const firstSegment = segments[0]\n if (segments.length === 1 && firstSegment === '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 && firstSegment !== undefined && firstSegment !== 'filters') {\n const entry = await client.findById(firstSegment)\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":"wBAkDA,MAAM,EAAW,yBAEX,EAAsB,EAAE,OAAO,CACnC,OAAQ,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC,UAAU,CACtC,WAAY,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC,UAAU,CAC1C,SAAU,EAAE,QAAQ,CAAC,MAAM,EAAU,oBAAoB,CAAC,UAAU,CACpE,OAAQ,EAAE,QAAQ,CAAC,MAAM,EAAU,yBAAyB,CAAC,UAAU,CACvE,SAAU,EAAE,QAAQ,CAAC,SAAS,CAAE,OAAQ,GAAM,QAAS,mBAAoB,CAAC,CAAC,UAAU,CACvF,OAAQ,EAAE,QAAQ,CAAC,SAAS,CAAE,OAAQ,GAAM,QAAS,mBAAoB,CAAC,CAAC,UAAU,CACrF,OAAQ,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC,UAAU,CACtC,MAAO,EAAE,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,QAAQ,GAAG,CACpD,OAAQ,EAAE,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,CAC3C,UAAW,EAAE,KAAK,CAAC,YAAa,SAAU,aAAa,CAAC,CAAC,QAAQ,YAAY,CAC7E,cAAe,EAAE,KAAK,CAAC,MAAO,OAAO,CAAC,CAAC,QAAQ,OAAO,CACvD,CAAC,CAMF,SAAS,EAAK,EAAe,EAAS,IAAe,CACnD,OAAO,IAAI,SAAS,KAAK,UAAU,EAAK,CAAE,CACxC,SACA,QAAS,CAAE,eAAgB,mBAAoB,CAChD,CAAC,CAGJ,SAAS,EAAU,EAAiB,EAA0B,CAC5D,OAAO,EAAK,CAAE,MAAO,EAAS,CAAE,EAAO,CAkBzC,SAAgB,EAAU,EAAiD,CACzE,MAAO,CACL,OAAQ,OACR,SAAU,aACV,QAAS,CAAC,OAAO,CACjB,SAAU,CACR,IAAK,MAAO,EAAK,CAAE,cAAe,CAEhC,IAAM,EAAS,GAAW,CAGpB,EAAe,EAAS,GAC9B,GAAI,EAAS,SAAW,GAAK,IAAiB,UAAW,CACvD,GAAM,CAAC,EAAa,GAAW,MAAM,QAAQ,IAAI,CAC/C,EAAO,wBAAwB,CAC/B,EAAO,oBAAoB,CAC5B,CAAC,CACF,OAAO,EAAK,CAAE,cAAa,UAAS,CAAC,CAIvC,GAAI,EAAS,SAAW,GAAK,IAAiB,IAAA,IAAa,IAAiB,UAAW,CACrF,IAAM,EAAQ,MAAM,EAAO,SAAS,EAAa,CAEjD,OADK,EACE,EAAK,EAAM,CADC,EAAU,4BAA6B,IAAI,CAKhE,IAAM,EAAM,IAAI,IAAI,EAAI,IAAI,CACtB,EAAS,OAAO,YAAY,EAAI,aAAa,CAC7C,EAAS,EAAoB,UAAU,EAAO,CAcpD,OAbK,EAAO,QAaL,EANQ,MAAM,EAAO,MAAM,CAChC,GAAG,EAAO,KACV,SAAU,EAAO,KAAK,SAAW,IAAI,KAAK,EAAO,KAAK,SAAS,CAAG,IAAA,GAClE,OAAQ,EAAO,KAAK,OAAS,IAAI,KAAK,EAAO,KAAK,OAAO,CAAG,IAAA,GAC7D,CAAC,CAEiB,CAZV,EACL,yBAAyB,EAAO,MAAM,OAAO,IAAK,GAAM,EAAE,QAAQ,CAAC,KAAK,KAAK,GAC7E,IACD,EAYN,CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@murumets-ee/logging",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"license": "Elastic-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -28,13 +28,16 @@
|
|
|
28
28
|
"drizzle-orm": "^0.45.2",
|
|
29
29
|
"pino": "^9.5.0",
|
|
30
30
|
"zod": "^3.24.1",
|
|
31
|
-
"@murumets-ee/db": "0.
|
|
31
|
+
"@murumets-ee/db": "0.11.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"tsdown": "^0.21.7",
|
|
35
35
|
"typescript": "^5.7.2",
|
|
36
36
|
"vitest": "^2.1.8"
|
|
37
37
|
},
|
|
38
|
+
"typeCoverage": {
|
|
39
|
+
"atLeast": 99.07
|
|
40
|
+
},
|
|
38
41
|
"scripts": {
|
|
39
42
|
"build": "tsdown",
|
|
40
43
|
"dev": "tsdown --watch",
|