@murumets-ee/logging 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { toolkitAuditLogs } from "./schema.mjs";
1
+ import { t as toolkitAuditLogs } from "./schema-BDO1jkrJ.mjs";
2
2
  import { Logger as Logger$1 } from "pino";
3
3
  import { PostgresJsDatabase } from "drizzle-orm/postgres-js";
4
4
 
@@ -92,7 +92,7 @@ interface AuditLogListResult {
92
92
  total: number;
93
93
  }
94
94
  declare class AuditLogClient {
95
- private db;
95
+ private client;
96
96
  constructor(db: PostgresJsDatabase);
97
97
  /** Write a single audit log entry */
98
98
  write(entry: Omit<AuditLogEntry, 'id' | 'createdAt'>): Promise<void>;
@@ -104,7 +104,7 @@ declare class AuditLogClient {
104
104
  getDistinctEntityTypes(): Promise<string[]>;
105
105
  /** Get distinct actions present in the audit log */
106
106
  getDistinctActions(): Promise<string[]>;
107
- private buildConditions;
107
+ private buildWhere;
108
108
  private buildOrderBy;
109
109
  }
110
110
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/logger.ts","../src/audit.ts","../src/audit-client.ts","../src/context.ts"],"mappings":";;;;;KAEY,MAAA,GAAS,QAAA;AAAA,UAEJ,YAAA;EACf,IAAA;EACA,KAAA;EACA,MAAA;AAAA;;;;AAHF;;iBAoCgB,YAAA,CAAa,MAAA,GAAS,YAAA,GAAe,MAAA;;;;iBAqBrC,iBAAA,CAAkB,MAAA,EAAQ,MAAA,EAAQ,OAAA,EAAS,MAAA,oBAA0B,MAAA;;;UCzDpE,UAAA;EACf,MAAA;EACA,UAAA;EACA,QAAA;EACA,MAAA;EACA,QAAA;EACA,OAAA,GAAU,MAAA;EACV,QAAA,GAAW,MAAA;AAAA;AAAA,UAGI,WAAA;EACf,MAAA,EAAQ,MAAA;EACR,QAAA,IAAY,KAAA,EAAO,UAAA,KAAe,OAAA;AAAA;AAAA,UAGnB,WAAA;EACf,GAAA,GAAM,KAAA,EAAO,UAAA,KAAe,OAAA;AAAA;;ADoB9B;;;;;;;;;AAqBA;iBC3BgB,mBAAA,CAAoB,EAAA,EAAI,kBAAA,IAAsB,KAAA,EAAO,UAAA,KAAe,OAAA;;;;;;;;;;iBAuBpE,iBAAA,CAAkB,MAAA,EAAQ,WAAA,GAAc,WAAA;;;UCjDvC,oBAAA;EACf,MAAA;EACA,UAAA;EACA,QAAA;EACA,MAAA;EACA,QAAA,GAAW,IAAA;EACX,MAAA,GAAS,IAAA;EFZU;EEcnB,MAAA;EFZe;EEcf,KAAA;EACA,MAAA;EACA,SAAA;EACA,aAAA;AAAA;AAAA,UAGe,aAAA;EACf,EAAA;EACA,MAAA;EACA,UAAA;EACA,QAAA;EACA,MAAA;EACA,QAAA;EACA,OAAA,EAAS,MAAA;EACT,QAAA,EAAU,MAAA;EACV,SAAA,EAAW,IAAA;AAAA;AAAA,UAGI,kBAAA;EACf,KAAA,EAAO,aAAA;EACP,KAAA;AAAA;AAAA,cAcW,cAAA;EAAA,QACS,EAAA;cAAA,EAAA,EAAI,kBAAA;EFQiE;EELnF,KAAA,CAAM,KAAA,EAAO,IAAA,CAAK,aAAA,wBAAqC,OAAA;EFKrB;EEQlC,KAAA,CAAM,OAAA,GAAS,oBAAA,GAA4B,OAAA,CAAQ,kBAAA;EFRA;EEkCnD,QAAA,CAAS,EAAA,WAAa,OAAA,CAAQ,aAAA;EFlC+C;EE6C7E,sBAAA,CAAA,GAA0B,OAAA;EF7CyD;EEwDnF,kBAAA,CAAA,GAAsB,OAAA;EAAA,QAapB,eAAA;EAAA,QAmCA,YAAA;AAAA;;;UCnKO,cAAA;EACf,SAAA;EACA,MAAA;EACA,MAAA;EACA,MAAA;AAAA;;;;AHFF;iBGSgB,kBAAA,CAAmB,MAAA,EAAQ,MAAA,EAAQ,OAAA,EAAS,cAAA,GAAiB,MAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/logger.ts","../src/audit.ts","../src/audit-client.ts","../src/context.ts"],"mappings":";;;;;KAEY,MAAA,GAAS,QAAA;AAAA,UAEJ,YAAA;EACf,IAAA;EACA,KAAA;EACA,MAAA;AAAA;;;;AAHF;;iBAoCgB,YAAA,CAAa,MAAA,GAAS,YAAA,GAAe,MAAA;;;;iBAqBrC,iBAAA,CAAkB,MAAA,EAAQ,MAAA,EAAQ,OAAA,EAAS,MAAA,oBAA0B,MAAA;;;UCzDpE,UAAA;EACf,MAAA;EACA,UAAA;EACA,QAAA;EACA,MAAA;EACA,QAAA;EACA,OAAA,GAAU,MAAA;EACV,QAAA,GAAW,MAAA;AAAA;AAAA,UAGI,WAAA;EACf,MAAA,EAAQ,MAAA;EACR,QAAA,IAAY,KAAA,EAAO,UAAA,KAAe,OAAA;AAAA;AAAA,UAGnB,WAAA;EACf,GAAA,GAAM,KAAA,EAAO,UAAA,KAAe,OAAA;AAAA;;ADoB9B;;;;;;;;;AAqBA;iBC3BgB,mBAAA,CAAoB,EAAA,EAAI,kBAAA,IAAsB,KAAA,EAAO,UAAA,KAAe,OAAA;;;;;;;;;;iBAuBpE,iBAAA,CAAkB,MAAA,EAAQ,WAAA,GAAc,WAAA;;;UCjDvC,oBAAA;EACf,MAAA;EACA,UAAA;EACA,QAAA;EACA,MAAA;EACA,QAAA,GAAW,IAAA;EACX,MAAA,GAAS,IAAA;EFZU;EEcnB,MAAA;EFZe;EEcf,KAAA;EACA,MAAA;EACA,SAAA;EACA,aAAA;AAAA;AAAA,UAGe,aAAA;EACf,EAAA;EACA,MAAA;EACA,UAAA;EACA,QAAA;EACA,MAAA;EACA,QAAA;EACA,OAAA,EAAS,MAAA;EACT,QAAA,EAAU,MAAA;EACV,SAAA,EAAW,IAAA;AAAA;AAAA,UAGI,kBAAA;EACf,KAAA,EAAO,aAAA;EACP,KAAA;AAAA;AAAA,cAqBW,cAAA;EAAA,QACH,MAAA;cAEI,EAAA,EAAI,kBAAA;EFDyE;EEMnF,KAAA,CAAM,KAAA,EAAO,IAAA,CAAK,aAAA,wBAAqC,OAAA;EFNrB;EEmBlC,KAAA,CAAM,OAAA,GAAS,oBAAA,GAA4B,OAAA,CAAQ,kBAAA;EFnBA;EEsCnD,QAAA,CAAS,EAAA,WAAa,OAAA,CAAQ,aAAA;EFtC+C;EE2C7E,sBAAA,CAAA,GAA0B,OAAA;EF3CyD;EEkDnF,kBAAA,CAAA,GAAsB,OAAA;EAAA,QAQpB,UAAA;EAAA,QAgCA,YAAA;AAAA;;;UCrJO,cAAA;EACf,SAAA;EACA,MAAA;EACA,MAAA;EACA,MAAA;AAAA;;;;AHFF;iBGSgB,kBAAA,CAAmB,MAAA,EAAQ,MAAA,EAAQ,OAAA,EAAS,cAAA,GAAiB,MAAA"}
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import{toolkitAuditLogs as e}from"./schema.mjs";import{and as t,asc as n,count as r,desc as i,eq as a,gte as o,ilike as s,isNotNull as c,lte as l,or as u}from"drizzle-orm";import d from"pino";var f=class{constructor(e){this.db=e}async write(t){await this.db.insert(e).values({action:t.action,entityType:t.entityType,entityId:t.entityId,userId:t.userId,userName:t.userName,changes:t.changes,metadata:t.metadata})}async query(n={}){let i=Math.min(Math.max(n.limit??50,1),100),a=Math.max(n.offset??0,0),o=this.buildConditions(n),s=o.length>0?t(...o):void 0,c=this.buildOrderBy(n.sortField,n.sortDirection),[l,u]=await Promise.all([this.db.select().from(e).where(s).orderBy(c).limit(i).offset(a),this.db.select({count:r()}).from(e).where(s)]);return{items:l,total:u[0]?.count??0}}async findById(t){return(await this.db.select().from(e).where(a(e.id,t)).limit(1))[0]??null}async getDistinctEntityTypes(){return(await this.db.selectDistinct({entityType:e.entityType}).from(e).where(c(e.entityType)).orderBy(n(e.entityType))).map(e=>e.entityType).filter(Boolean)}async getDistinctActions(){return(await this.db.selectDistinct({action:e.action}).from(e).orderBy(n(e.action))).map(e=>e.action)}buildConditions(t){let n=[];if(t.action&&n.push(a(e.action,t.action)),t.entityType&&n.push(a(e.entityType,t.entityType)),t.entityId&&n.push(a(e.entityId,t.entityId)),t.userId&&n.push(a(e.userId,t.userId)),t.dateFrom&&n.push(o(e.createdAt,t.dateFrom)),t.dateTo&&n.push(l(e.createdAt,t.dateTo)),t.search){let r=`%${t.search}%`;n.push(u(s(e.action,r),s(e.entityType,r),s(e.userName,r)))}return n}buildOrderBy(t,r){let a=r===`asc`?n:i;switch(t){case`action`:return a(e.action);case`entityType`:return a(e.entityType);default:return a(e.createdAt)}}};function p(e){let t=new f(e);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 m(e){return{log:async t=>{e.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}`),e.dbWriter&&e.dbWriter(t).catch(n=>{e.logger.error({err:n,auditEntry:t},`Failed to write audit log to database`)})}}}function h(e,t){return e.child(t)}const g=d({level:process.env.LOG_LEVEL||`info`,formatters:{level:e=>({level:e})},timestamp:!1,serializers:{err:d.stdSerializers.err,error:d.stdSerializers.err},redact:{paths:[`password`,`token`,`secret`,`apiKey`,`accessToken`,`refreshToken`],censor:`[REDACTED]`}});function _(e){if(!e)return g;let t={};e.name&&(t.name=e.name);let n={};return e.level&&(n.level=e.level),g.child(t,n)}function v(e,t){return e.child(t)}export{f as AuditLogClient,h as bindRequestContext,p as createAuditDbWriter,m as createAuditLogger,v as createChildLogger,_ as createLogger,e as toolkitAuditLogs};
1
+ import{n as e,t}from"./schema-D9vWDK2q.mjs";import n from"pino";var r=class{client;constructor(e){this.client=t.makeClient(e)}async write(e){await this.client.insert({action:e.action,entityType:e.entityType,entityId:e.entityId,userId:e.userId,userName:e.userName,changes:e.changes,metadata:e.metadata})}async query(e={}){let t=Math.min(Math.max(e.limit??50,1),100),n=Math.max(e.offset??0,0),r=this.buildWhere(e),i=this.buildOrderBy(e.sortField,e.sortDirection),[a,o]=await Promise.all([this.client.findMany({where:r,orderBy:i,limit:t,offset:n}),this.client.count(r)]);return{items:a,total:o}}async findById(e){return this.client.findOne({id:e})}async getDistinctEntityTypes(){return this.client.distinct(`entityType`,{orderBy:`asc`})}async getDistinctActions(){return this.client.distinct(`action`,{orderBy:`asc`})}buildWhere(e){let t=[];if(e.action&&t.push({action:e.action}),e.entityType&&t.push({entityType:e.entityType}),e.entityId&&t.push({entityId:e.entityId}),e.userId&&t.push({userId:e.userId}),e.dateFrom||e.dateTo){let n={};e.dateFrom&&(n.gte=e.dateFrom),e.dateTo&&(n.lte=e.dateTo),t.push({createdAt:n})}if(e.search&&t.push({$or:[{action:{ilike:e.search}},{entityType:{ilike:e.search}},{userName:{ilike:e.search}}]}),t.length!==0)return t.length===1?t[0]:{$and:t}}buildOrderBy(e,t){let n=t===`asc`?`asc`:`desc`;switch(e){case`action`:return[{column:`action`,dir:n}];case`entityType`:return[{column:`entityType`,dir:n}];default:return[{column:`createdAt`,dir:n}]}}};function i(e){let t=new r(e);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 a(e){return{log:async t=>{e.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}`),e.dbWriter&&e.dbWriter(t).catch(n=>{e.logger.error({err:n,auditEntry:t},`Failed to write audit log to database`)})}}}function o(e,t){return e.child(t)}const s=n({level:process.env.LOG_LEVEL||`info`,formatters:{level:e=>({level:e})},timestamp:!1,serializers:{err:n.stdSerializers.err,error:n.stdSerializers.err},redact:{paths:[`password`,`token`,`secret`,`apiKey`,`accessToken`,`refreshToken`],censor:`[REDACTED]`}});function c(e){if(!e)return s;let t={};e.name&&(t.name=e.name);let n={};return e.level&&(n.level=e.level),s.child(t,n)}function l(e,t){return e.child(t)}export{r as AuditLogClient,o as bindRequestContext,i as createAuditDbWriter,a as createAuditLogger,l as createChildLogger,c as createLogger,e as toolkitAuditLogs};
2
2
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"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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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/audit-client.ts","../src/audit.ts","../src/context.ts","../src/logger.ts"],"sourcesContent":["import type { PostgresJsDatabase } from 'drizzle-orm/postgres-js'\nimport type { TableClient, WhereClause } from '@murumets-ee/db'\nimport { auditLogTable } from './audit-table.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// Internal types\n// ---------------------------------------------------------------------------\n\ntype AuditCols = typeof auditLogTable.schema.columns\ntype AuditWhere = WhereClause<AuditCols>\n\n// ---------------------------------------------------------------------------\n// Client\n// ---------------------------------------------------------------------------\n\nexport class AuditLogClient {\n private client: TableClient<AuditCols>\n\n constructor(db: PostgresJsDatabase) {\n this.client = auditLogTable.makeClient(db)\n }\n\n /** Write a single audit log entry */\n async write(entry: Omit<AuditLogEntry, 'id' | 'createdAt'>): Promise<void> {\n await this.client.insert({\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 where = this.buildWhere(options)\n const orderBy = this.buildOrderBy(options.sortField, options.sortDirection)\n\n const [items, total] = await Promise.all([\n this.client.findMany({ where, orderBy, limit, offset }),\n this.client.count(where),\n ])\n\n return {\n items: items as AuditLogEntry[],\n total,\n }\n }\n\n /** Get a single audit log entry by ID */\n async findById(id: string): Promise<AuditLogEntry | null> {\n return this.client.findOne({ id }) as Promise<AuditLogEntry | null>\n }\n\n /** Get distinct entity types present in the audit log */\n async getDistinctEntityTypes(): Promise<string[]> {\n // entityType is nullable, but distinct() excludes nulls by default —\n // the cast is safe because includeNull is not set.\n return this.client.distinct('entityType', { orderBy: 'asc' }) as Promise<string[]>\n }\n\n /** Get distinct actions present in the audit log */\n async getDistinctActions(): Promise<string[]> {\n return this.client.distinct('action', { orderBy: 'asc' })\n }\n\n // -------------------------------------------------------------------------\n // Private helpers\n // -------------------------------------------------------------------------\n\n private buildWhere(options: AuditLogQueryOptions): AuditWhere | undefined {\n const parts: AuditWhere[] = []\n\n if (options.action) parts.push({ action: options.action })\n if (options.entityType) parts.push({ entityType: options.entityType })\n if (options.entityId) parts.push({ entityId: options.entityId })\n if (options.userId) parts.push({ userId: options.userId })\n\n // Date range: combine into a single createdAt condition\n if (options.dateFrom || options.dateTo) {\n const dateOps: Record<string, unknown> = {}\n if (options.dateFrom) dateOps.gte = options.dateFrom\n if (options.dateTo) dateOps.lte = options.dateTo\n parts.push({ createdAt: dateOps } as AuditWhere)\n }\n\n // Free-text search across action, entityType, userName\n if (options.search) {\n parts.push({\n $or: [\n { action: { ilike: options.search } },\n { entityType: { ilike: options.search } },\n { userName: { ilike: options.search } },\n ],\n })\n }\n\n if (parts.length === 0) return undefined\n if (parts.length === 1) return parts[0]\n return { $and: parts }\n }\n\n private buildOrderBy(\n sortField?: string,\n sortDirection?: string,\n ): { column: keyof AuditCols & string; dir: 'asc' | 'desc' }[] {\n const dir: 'asc' | 'desc' = sortDirection === 'asc' ? 'asc' : 'desc'\n switch (sortField) {\n case 'action':\n return [{ column: 'action', dir }]\n case 'entityType':\n return [{ column: 'entityType', dir }]\n case 'createdAt':\n default:\n return [{ column: 'createdAt', dir }]\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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"}
package/dist/plugin.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import{toolkitAuditLogs as e}from"./schema.mjs";function t(){return{name:`@murumets-ee/logging`,tables:{toolkitAuditLogs:e}}}export{t as logging};
1
+ import{n as e}from"./schema-D9vWDK2q.mjs";function t(){return{name:`@murumets-ee/logging`,tables:{toolkitAuditLogs:e}}}export{t as logging};
2
2
  //# sourceMappingURL=plugin.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.mjs","names":[],"sources":["../src/plugin.ts"],"sourcesContent":["// biome-ignore lint/suspicious/noExplicitAny: structural PgTable\nimport type { PgTable } from 'drizzle-orm/pg-core'\nimport { toolkitAuditLogs } from './schema.js'\n\n// Structural Plugin shape — kept in sync with @murumets-ee/core. Not imported\n// from core because core depends on logging (circular dep would fail).\ninterface LoggingPlugin {\n name: string\n // biome-ignore lint/suspicious/noExplicitAny: as above\n tables: Record<string, PgTable<any>>\n}\n\n/**\n * Logging plugin — registers the `toolkit_audit_logs` table so it shows up\n * in generated migrations. Zero runtime behavior; the audit logger is wired\n * up separately via `createAuditLogger()`.\n *\n * @example\n * ```typescript\n * import { logging } from '@murumets-ee/logging/plugin'\n *\n * export default defineConfig({\n * plugins: [logging()],\n * })\n * ```\n */\nexport function logging(): LoggingPlugin {\n return {\n name: '@murumets-ee/logging',\n tables: { toolkitAuditLogs },\n }\n}\n"],"mappings":"gDA0BA,SAAgB,GAAyB,CACvC,MAAO,CACL,KAAM,uBACN,OAAQ,CAAE,mBAAkB,CAC7B"}
1
+ {"version":3,"file":"plugin.mjs","names":[],"sources":["../src/plugin.ts"],"sourcesContent":["// biome-ignore lint/suspicious/noExplicitAny: structural PgTable\nimport type { PgTable } from 'drizzle-orm/pg-core'\nimport { toolkitAuditLogs } from './schema.js'\n\n// Structural Plugin shape — kept in sync with @murumets-ee/core. Not imported\n// from core because core depends on logging (circular dep would fail).\ninterface LoggingPlugin {\n name: string\n // biome-ignore lint/suspicious/noExplicitAny: as above\n tables: Record<string, PgTable<any>>\n}\n\n/**\n * Logging plugin — registers the `toolkit_audit_logs` table so it shows up\n * in generated migrations. Zero runtime behavior; the audit logger is wired\n * up separately via `createAuditLogger()`.\n *\n * @example\n * ```typescript\n * import { logging } from '@murumets-ee/logging/plugin'\n *\n * export default defineConfig({\n * plugins: [logging()],\n * })\n * ```\n */\nexport function logging(): LoggingPlugin {\n return {\n name: '@murumets-ee/logging',\n tables: { toolkitAuditLogs },\n }\n}\n"],"mappings":"0CA0BA,SAAgB,GAAyB,CACvC,MAAO,CACL,KAAM,uBACN,OAAQ,CAAE,mBAAkB,CAC7B"}
@@ -0,0 +1,8 @@
1
+ import * as _$drizzle_orm_pg_core0 from "drizzle-orm/pg-core";
2
+
3
+ //#region src/audit-table.d.ts
4
+ /** Backward-compatible re-export — consumers importing `toolkitAuditLogs` see the same PgTable. */
5
+ declare const toolkitAuditLogs: _$drizzle_orm_pg_core0.PgTableWithColumns<_$drizzle_orm_pg_core0.TableConfig>;
6
+ //#endregion
7
+ export { toolkitAuditLogs as t };
8
+ //# sourceMappingURL=schema-BDO1jkrJ.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-BDO1jkrJ.d.mts","names":[],"sources":["../src/audit-table.ts"],"mappings":";;;;cAsCa,gBAAA,EAAgB,sBAAA,CAAA,kBAAA,CAAsB,sBAAA,CAAtB,WAAA"}
@@ -0,0 +1,2 @@
1
+ import{column as e,defineTable as t}from"@murumets-ee/db";const n=t({name:`toolkit_audit_logs`,columns:{id:e.uuid({primaryKey:!0,defaultRandom:!0}),action:e.varchar({length:100,notNull:!0}),entityType:e.varchar({length:100,pgName:`entity_type`}),entityId:e.varchar({length:255,pgName:`entity_id`}),userId:e.varchar({length:255,pgName:`user_id`}),userName:e.varchar({length:255,pgName:`user_name`}),changes:e.jsonb(),metadata:e.jsonb(),createdAt:e.timestamp({notNull:!0,defaultNow:!0,withTimezone:!0,pgName:`created_at`})},indexes:[{on:[`entityType`,`createdAt`],name:`audit_entity_type_created_at_idx`},{on:[`userId`,`createdAt`],name:`audit_user_id_created_at_idx`},{on:[`action`,`createdAt`],name:`audit_action_created_at_idx`},{on:[`createdAt`],name:`audit_created_at_idx`},{on:[`entityId`],name:`audit_entity_id_idx`}]}),r=n.table;export{r as n,n as t};
2
+ //# sourceMappingURL=schema-D9vWDK2q.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-D9vWDK2q.mjs","names":[],"sources":["../src/audit-table.ts"],"sourcesContent":["/**\n * `toolkit_audit_logs` table definition via `defineTable`.\n *\n * Replaces the hand-written `pgTable` in `schema.ts`. Uses `pgName` to\n * preserve the existing snake_case Postgres column names so no migration\n * is required.\n */\n\nimport { column, defineTable } from '@murumets-ee/db'\n\nexport const auditLogTable = defineTable({\n name: 'toolkit_audit_logs',\n columns: {\n id: column.uuid({ primaryKey: true, defaultRandom: true }),\n action: column.varchar({ length: 100, notNull: true }),\n entityType: column.varchar({ length: 100, pgName: 'entity_type' }),\n entityId: column.varchar({ length: 255, pgName: 'entity_id' }),\n userId: column.varchar({ length: 255, pgName: 'user_id' }),\n userName: column.varchar({ length: 255, pgName: 'user_name' }),\n changes: column.jsonb<Record<string, unknown>>(),\n metadata: column.jsonb<Record<string, unknown>>(),\n createdAt: column.timestamp({\n notNull: true,\n defaultNow: true,\n withTimezone: true,\n pgName: 'created_at',\n }),\n },\n indexes: [\n { on: ['entityType', 'createdAt'], name: 'audit_entity_type_created_at_idx' },\n { on: ['userId', 'createdAt'], name: 'audit_user_id_created_at_idx' },\n { on: ['action', 'createdAt'], name: 'audit_action_created_at_idx' },\n { on: ['createdAt'], name: 'audit_created_at_idx' },\n { on: ['entityId'], name: 'audit_entity_id_idx' },\n ],\n})\n\n/** Backward-compatible re-export — consumers importing `toolkitAuditLogs` see the same PgTable. */\nexport const toolkitAuditLogs = auditLogTable.table\n"],"mappings":"0DAUA,MAAa,EAAgB,EAAY,CACvC,KAAM,qBACN,QAAS,CACP,GAAI,EAAO,KAAK,CAAE,WAAY,GAAM,cAAe,GAAM,CAAC,CAC1D,OAAQ,EAAO,QAAQ,CAAE,OAAQ,IAAK,QAAS,GAAM,CAAC,CACtD,WAAY,EAAO,QAAQ,CAAE,OAAQ,IAAK,OAAQ,cAAe,CAAC,CAClE,SAAU,EAAO,QAAQ,CAAE,OAAQ,IAAK,OAAQ,YAAa,CAAC,CAC9D,OAAQ,EAAO,QAAQ,CAAE,OAAQ,IAAK,OAAQ,UAAW,CAAC,CAC1D,SAAU,EAAO,QAAQ,CAAE,OAAQ,IAAK,OAAQ,YAAa,CAAC,CAC9D,QAAS,EAAO,OAAgC,CAChD,SAAU,EAAO,OAAgC,CACjD,UAAW,EAAO,UAAU,CAC1B,QAAS,GACT,WAAY,GACZ,aAAc,GACd,OAAQ,aACT,CAAC,CACH,CACD,QAAS,CACP,CAAE,GAAI,CAAC,aAAc,YAAY,CAAE,KAAM,mCAAoC,CAC7E,CAAE,GAAI,CAAC,SAAU,YAAY,CAAE,KAAM,+BAAgC,CACrE,CAAE,GAAI,CAAC,SAAU,YAAY,CAAE,KAAM,8BAA+B,CACpE,CAAE,GAAI,CAAC,YAAY,CAAE,KAAM,uBAAwB,CACnD,CAAE,GAAI,CAAC,WAAW,CAAE,KAAM,sBAAuB,CAClD,CACF,CAAC,CAGW,EAAmB,EAAc"}
package/dist/schema.d.mts CHANGED
@@ -1,180 +1,2 @@
1
- import * as _$drizzle_orm_pg_core0 from "drizzle-orm/pg-core";
2
-
3
- //#region src/schema.d.ts
4
- declare const toolkitAuditLogs: _$drizzle_orm_pg_core0.PgTableWithColumns<{
5
- name: "toolkit_audit_logs";
6
- schema: undefined;
7
- columns: {
8
- id: _$drizzle_orm_pg_core0.PgColumn<{
9
- name: "id";
10
- tableName: "toolkit_audit_logs";
11
- dataType: "string";
12
- columnType: "PgUUID";
13
- data: string;
14
- driverParam: string;
15
- notNull: true;
16
- hasDefault: true;
17
- isPrimaryKey: true;
18
- isAutoincrement: false;
19
- hasRuntimeDefault: false;
20
- enumValues: undefined;
21
- baseColumn: never;
22
- identity: undefined;
23
- generated: undefined;
24
- }, {}, {}>;
25
- action: _$drizzle_orm_pg_core0.PgColumn<{
26
- name: "action";
27
- tableName: "toolkit_audit_logs";
28
- dataType: "string";
29
- columnType: "PgVarchar";
30
- data: string;
31
- driverParam: string;
32
- notNull: true;
33
- hasDefault: false;
34
- isPrimaryKey: false;
35
- isAutoincrement: false;
36
- hasRuntimeDefault: false;
37
- enumValues: [string, ...string[]];
38
- baseColumn: never;
39
- identity: undefined;
40
- generated: undefined;
41
- }, {}, {
42
- length: 100;
43
- }>;
44
- entityType: _$drizzle_orm_pg_core0.PgColumn<{
45
- name: "entity_type";
46
- tableName: "toolkit_audit_logs";
47
- dataType: "string";
48
- columnType: "PgVarchar";
49
- data: string;
50
- driverParam: string;
51
- notNull: false;
52
- hasDefault: false;
53
- isPrimaryKey: false;
54
- isAutoincrement: false;
55
- hasRuntimeDefault: false;
56
- enumValues: [string, ...string[]];
57
- baseColumn: never;
58
- identity: undefined;
59
- generated: undefined;
60
- }, {}, {
61
- length: 100;
62
- }>;
63
- entityId: _$drizzle_orm_pg_core0.PgColumn<{
64
- name: "entity_id";
65
- tableName: "toolkit_audit_logs";
66
- dataType: "string";
67
- columnType: "PgVarchar";
68
- data: string;
69
- driverParam: string;
70
- notNull: false;
71
- hasDefault: false;
72
- isPrimaryKey: false;
73
- isAutoincrement: false;
74
- hasRuntimeDefault: false;
75
- enumValues: [string, ...string[]];
76
- baseColumn: never;
77
- identity: undefined;
78
- generated: undefined;
79
- }, {}, {
80
- length: 255;
81
- }>;
82
- userId: _$drizzle_orm_pg_core0.PgColumn<{
83
- name: "user_id";
84
- tableName: "toolkit_audit_logs";
85
- dataType: "string";
86
- columnType: "PgVarchar";
87
- data: string;
88
- driverParam: string;
89
- notNull: false;
90
- hasDefault: false;
91
- isPrimaryKey: false;
92
- isAutoincrement: false;
93
- hasRuntimeDefault: false;
94
- enumValues: [string, ...string[]];
95
- baseColumn: never;
96
- identity: undefined;
97
- generated: undefined;
98
- }, {}, {
99
- length: 255;
100
- }>;
101
- userName: _$drizzle_orm_pg_core0.PgColumn<{
102
- name: "user_name";
103
- tableName: "toolkit_audit_logs";
104
- dataType: "string";
105
- columnType: "PgVarchar";
106
- data: string;
107
- driverParam: string;
108
- notNull: false;
109
- hasDefault: false;
110
- isPrimaryKey: false;
111
- isAutoincrement: false;
112
- hasRuntimeDefault: false;
113
- enumValues: [string, ...string[]];
114
- baseColumn: never;
115
- identity: undefined;
116
- generated: undefined;
117
- }, {}, {
118
- length: 255;
119
- }>;
120
- changes: _$drizzle_orm_pg_core0.PgColumn<{
121
- name: "changes";
122
- tableName: "toolkit_audit_logs";
123
- dataType: "json";
124
- columnType: "PgJsonb";
125
- data: Record<string, unknown>;
126
- driverParam: unknown;
127
- notNull: false;
128
- hasDefault: false;
129
- isPrimaryKey: false;
130
- isAutoincrement: false;
131
- hasRuntimeDefault: false;
132
- enumValues: undefined;
133
- baseColumn: never;
134
- identity: undefined;
135
- generated: undefined;
136
- }, {}, {
137
- $type: Record<string, unknown>;
138
- }>;
139
- metadata: _$drizzle_orm_pg_core0.PgColumn<{
140
- name: "metadata";
141
- tableName: "toolkit_audit_logs";
142
- dataType: "json";
143
- columnType: "PgJsonb";
144
- data: Record<string, unknown>;
145
- driverParam: unknown;
146
- notNull: false;
147
- hasDefault: false;
148
- isPrimaryKey: false;
149
- isAutoincrement: false;
150
- hasRuntimeDefault: false;
151
- enumValues: undefined;
152
- baseColumn: never;
153
- identity: undefined;
154
- generated: undefined;
155
- }, {}, {
156
- $type: Record<string, unknown>;
157
- }>;
158
- createdAt: _$drizzle_orm_pg_core0.PgColumn<{
159
- name: "created_at";
160
- tableName: "toolkit_audit_logs";
161
- dataType: "date";
162
- columnType: "PgTimestamp";
163
- data: Date;
164
- driverParam: string;
165
- notNull: true;
166
- hasDefault: true;
167
- isPrimaryKey: false;
168
- isAutoincrement: false;
169
- hasRuntimeDefault: false;
170
- enumValues: undefined;
171
- baseColumn: never;
172
- identity: undefined;
173
- generated: undefined;
174
- }, {}, {}>;
175
- };
176
- dialect: "pg";
177
- }>;
178
- //#endregion
179
- export { toolkitAuditLogs };
180
- //# sourceMappingURL=schema.d.mts.map
1
+ import { t as toolkitAuditLogs } from "./schema-BDO1jkrJ.mjs";
2
+ export { toolkitAuditLogs };
package/dist/schema.mjs CHANGED
@@ -1,2 +1 @@
1
- import{index as e,jsonb as t,pgTable as n,timestamp as r,uuid as i,varchar as a}from"drizzle-orm/pg-core";const o=n(`toolkit_audit_logs`,{id:i(`id`).primaryKey().defaultRandom(),action:a(`action`,{length:100}).notNull(),entityType:a(`entity_type`,{length:100}),entityId:a(`entity_id`,{length:255}),userId:a(`user_id`,{length:255}),userName:a(`user_name`,{length:255}),changes:t(`changes`).$type(),metadata:t(`metadata`).$type(),createdAt:r(`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{o as toolkitAuditLogs};
2
- //# sourceMappingURL=schema.mjs.map
1
+ import{n as e}from"./schema-D9vWDK2q.mjs";export{e as toolkitAuditLogs};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@murumets-ee/logging",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "license": "Elastic-2.0",
5
5
  "type": "module",
6
6
  "exports": {
@@ -24,7 +24,13 @@
24
24
  "files": [
25
25
  "dist"
26
26
  ],
27
+ "scripts": {
28
+ "build": "tsdown",
29
+ "dev": "tsdown --watch",
30
+ "test": "vitest"
31
+ },
27
32
  "dependencies": {
33
+ "@murumets-ee/db": "workspace:*",
28
34
  "drizzle-orm": ">=0.40.0",
29
35
  "pino": "^9.5.0",
30
36
  "zod": ">=3.0.0"
@@ -33,10 +39,5 @@
33
39
  "tsdown": "^0.21.7",
34
40
  "typescript": "^5.7.2",
35
41
  "vitest": "^2.1.8"
36
- },
37
- "scripts": {
38
- "build": "tsdown",
39
- "dev": "tsdown --watch",
40
- "test": "vitest"
41
42
  }
42
- }
43
+ }
package/LICENSE DELETED
@@ -1,94 +0,0 @@
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.
@@ -1 +0,0 @@
1
- {"version":3,"file":"schema.d.mts","names":[],"sources":["../src/schema.ts"],"mappings":";;;cAEa,gBAAA,yBAAgB,kBAAA;;;;QAuB5B,sBAAA,CAAA,QAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"schema.mjs","names":[],"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":"0GAEA,MAAa,EAAmB,EAC9B,qBACA,CACE,GAAI,EAAK,KAAK,CAAC,YAAY,CAAC,eAAe,CAC3C,OAAQ,EAAQ,SAAU,CAAE,OAAQ,IAAK,CAAC,CAAC,SAAS,CACpD,WAAY,EAAQ,cAAe,CAAE,OAAQ,IAAK,CAAC,CACnD,SAAU,EAAQ,YAAa,CAAE,OAAQ,IAAK,CAAC,CAC/C,OAAQ,EAAQ,UAAW,CAAE,OAAQ,IAAK,CAAC,CAC3C,SAAU,EAAQ,YAAa,CAAE,OAAQ,IAAK,CAAC,CAC/C,QAAS,EAAM,UAAU,CAAC,OAAgC,CAC1D,SAAU,EAAM,WAAW,CAAC,OAAgC,CAC5D,UAAW,EAAU,aAAc,CAAE,aAAc,GAAM,CAAC,CAAC,SAAS,CAAC,YAAY,CAClF,CACA,IAAW,CACV,uBAAwB,EAAM,mCAAmC,CAAC,GAChE,EAAM,WACN,EAAM,UACP,CACD,mBAAoB,EAAM,+BAA+B,CAAC,GAAG,EAAM,OAAQ,EAAM,UAAU,CAC3F,mBAAoB,EAAM,8BAA8B,CAAC,GAAG,EAAM,OAAQ,EAAM,UAAU,CAC1F,aAAc,EAAM,uBAAuB,CAAC,GAAG,EAAM,UAAU,CAC/D,YAAa,EAAM,sBAAsB,CAAC,GAAG,EAAM,SAAS,CAC7D,EACF"}