@payfit/audit-log 3.11.0 → 3.12.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.
@@ -0,0 +1,2 @@
1
+ export declare function compress(input: string): string;
2
+ export declare function decompress(input: string): string;
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";var v=Object.defineProperty;var p=(s,t,e)=>t in s?v(s,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):s[t]=e;var n=(s,t,e)=>(p(s,typeof t!="symbol"?t+"":t,e),e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const f=require("uuid"),o=require("winston"),S=require("hot-shots"),m=require("@aws-sdk/client-sqs"),E="audit-logs",_="@payfit/audit-log",L=()=>{const s=process.env.LOG_LEVEL;return s&&s.trim()!==""?s.trim():"info"},q=(s,t)=>o.createLogger({level:L(),silent:process.env.NODE_ENV==="test",exitOnError:!1,defaultMeta:{namespace:E,sdk:_,service:s,environment:t},format:o.format.combine(o.format.timestamp(),o.format.errors({stack:!0}),o.format.json()),transports:[new o.transports.Console]}),y="payfit.audit-logs.",d=s=>Object.entries(s).filter(([,t])=>t!==void 0&&t!=="").map(([t,e])=>`${t}:${String(e)}`);class A{constructor(){n(this,"client");this.client=new S.StatsD({prefix:y,errorHandler:()=>{},cacheDns:!0})}increment(t,e){this.client.increment(t,1,d(e))}histogram(t,e,i){this.client.histogram(t,e,d(i))}async close(){await new Promise(t=>{this.client.close(()=>t())})}}const M=()=>new A,D="eu-west-3",U={dev:"https://sqs.eu-west-3.amazonaws.com/533547282673/audit-logs-ingest",staging:"https://sqs.eu-west-3.amazonaws.com/589883667243/audit-logs-ingest",prod:"https://sqs.eu-west-3.amazonaws.com/614948436281/audit-logs-ingest"},C={working:"staging",production:"prod"};class O{constructor(t){n(this,"environment");n(this,"client");n(this,"queueUrl");this.environment=t;const e=C[t]??t,i=U[e];if(!i)throw new Error(`audit-logs SDK: no SQS queue URL configured for environment "${t}"`);this.queueUrl=i,this.client=new m.SQSClient({region:D})}async create(t){await this.client.send(new m.SendMessageCommand({QueueUrl:this.queueUrl,MessageBody:JSON.stringify(t)}))}}class N{constructor(t,e={}){n(this,"params");n(this,"transport");n(this,"logger");n(this,"metrics");this.params=t,this.transport=e.transport??new O(t.environment),this.logger=e.logger??q(t.service,t.environment),this.metrics=e.metrics??M()}async log({scope:t,account:e,...i}){const h=f.v4(),{environment:c,service:g}=this.params,r={...i,...e,service:g,id:h,environment:c,...t&&{scope:t}},a={service:g,environment:c,namespace:r.namespace,event:r.event,target:r.target},l=Date.now();try{await this.transport.create(r),this.metrics.increment("sent",a),this.metrics.histogram("send_duration_ms",Date.now()-l,a),this.logger.debug("audit-log sent",{id:r.id,event:r.event,target:r.target})}catch(w){this.metrics.increment("send_failed",a),this.metrics.histogram("send_duration_ms",Date.now()-l,a);const u=w.message;try{this.logger.error("audit-log write failed",{audit_log:r,error:u})}catch{this.metrics.increment("serialization_failed",a);try{this.logger.error("audit-log write failed (serialization failed)",{audit_log_meta:{id:r.id,service:r.service,environment:r.environment,namespace:r.namespace,event:r.event,target:r.target},error:u})}catch{}}}}}exports.AuditLogger=N;
1
+ "use strict";var f=Object.defineProperty;var w=(s,e,t)=>e in s?f(s,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[e]=t;var n=(s,e,t)=>(w(s,typeof e!="symbol"?e+"":e,t),t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const S=require("uuid"),a=require("winston"),v=require("hot-shots"),h=require("@aws-sdk/client-sqs"),E=require("zlib"),y="audit-logs",_="@payfit/audit-log",q=()=>{const s=process.env.LOG_LEVEL;return s&&s.trim()!==""?s.trim():"info"},L=(s,e)=>a.createLogger({level:q(),silent:process.env.NODE_ENV==="test",exitOnError:!1,defaultMeta:{namespace:y,sdk:_,service:s,environment:e},format:a.format.combine(a.format.timestamp(),a.format.errors({stack:!0}),a.format.json()),transports:[new a.transports.Console]}),M="payfit.audit_logs.",p=s=>Object.entries(s).filter(([,e])=>e!==void 0&&e!=="").map(([e,t])=>`${e}:${String(t)}`);class A{constructor(){n(this,"client");this.client=new v.StatsD({prefix:M,errorHandler:()=>{},cacheDns:!0})}increment(e,t){this.client.increment(e,1,p(t))}histogram(e,t,i){this.client.histogram(e,t,p(i))}async close(){await new Promise(e=>{this.client.close(()=>e())})}}const b=()=>new A;function C(s){return E.brotliCompressSync(Buffer.from(s,"utf8")).toString("base64")}function U(s){return s instanceof Error&&s.message.includes("Message must be shorter than")}const O="eu-west-3",z={dev:"https://sqs.eu-west-3.amazonaws.com/533547282673/audit-logs-ingest",staging:"https://sqs.eu-west-3.amazonaws.com/589883667243/audit-logs-ingest",prod:"https://sqs.eu-west-3.amazonaws.com/614948436281/audit-logs-ingest"},D={working:"staging",production:"prod"};class N{constructor(e,t){n(this,"environment");n(this,"logger");n(this,"client");n(this,"queueUrl");this.environment=e,this.logger=t;const i=D[e]??e,o=z[i];if(!o)throw new Error(`audit-logs SDK: no SQS queue URL configured for environment "${e}"`);this.queueUrl=o,this.client=new h.SQSClient({region:O})}async create(e){var i;const t=JSON.stringify(e);try{return await this.send(t),{compressed:!1}}catch(o){if(!U(o))throw o;return(i=this.logger)==null||i.info("audit-log payload exceeds the SQS size limit, retrying with Brotli compression",{id:e.id,namespace:e.namespace}),await this.send(C(t)),{compressed:!0}}}async send(e){await this.client.send(new h.SendMessageCommand({QueueUrl:this.queueUrl,MessageBody:e}))}}class Q{constructor(e,t={}){n(this,"params");n(this,"transport");n(this,"logger");n(this,"metrics");this.params=e,this.logger=t.logger??L(e.service,e.environment),this.transport=t.transport??new N(e.environment,this.logger),this.metrics=t.metrics??b()}async log({scope:e,account:t,...i}){const o=S.v4(),{environment:l,service:m}=this.params,r={...i,...t,service:m,id:o,environment:l,...e&&{scope:e}},c={service:m,environment:l,namespace:r.namespace,event:r.event,target:r.target},u=Date.now();try{const{compressed:g}=await this.transport.create(r);this.metrics.increment("sent",{...c,compressed:String(g)}),this.metrics.histogram("send_duration_ms",Date.now()-u,c),this.logger.debug("audit-log sent",{id:r.id,event:r.event,target:r.target})}catch(g){this.metrics.increment("send_failed",c),this.metrics.histogram("send_duration_ms",Date.now()-u,c);const d=g.message;try{this.logger.error("audit-log write failed",{audit_log:r,error:d})}catch{this.metrics.increment("serialization_failed",c);try{this.logger.error("audit-log write failed (serialization failed)",{audit_log_meta:{id:r.id,service:r.service,environment:r.environment,namespace:r.namespace,event:r.event,target:r.target},error:d})}catch{}}}}}exports.AuditLogger=Q;
package/dist/index.mjs CHANGED
@@ -1,114 +1,138 @@
1
1
  var p = Object.defineProperty;
2
- var w = (s, t, e) => t in s ? p(s, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : s[t] = e;
3
- var i = (s, t, e) => (w(s, typeof t != "symbol" ? t + "" : t, e), e);
4
- import { v4 as v } from "uuid";
5
- import { createLogger as f, format as a, transports as E } from "winston";
6
- import { StatsD as _ } from "hot-shots";
7
- import { SQSClient as S, SendMessageCommand as L } from "@aws-sdk/client-sqs";
8
- const y = "audit-logs", A = "@payfit/audit-log", D = () => {
2
+ var f = (s, e, t) => e in s ? p(s, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[e] = t;
3
+ var i = (s, e, t) => (f(s, typeof e != "symbol" ? e + "" : e, t), t);
4
+ import { v4 as w } from "uuid";
5
+ import { createLogger as v, format as c, transports as S } from "winston";
6
+ import { StatsD as E } from "hot-shots";
7
+ import { SQSClient as _, SendMessageCommand as y } from "@aws-sdk/client-sqs";
8
+ import { brotliCompressSync as L } from "zlib";
9
+ const M = "audit-logs", A = "@payfit/audit-log", C = () => {
9
10
  const s = process.env.LOG_LEVEL;
10
11
  return s && s.trim() !== "" ? s.trim() : "info";
11
- }, M = (s, t) => f({
12
- level: D(),
12
+ }, U = (s, e) => v({
13
+ level: C(),
13
14
  silent: process.env.NODE_ENV === "test",
14
15
  exitOnError: !1,
15
16
  defaultMeta: {
16
- namespace: y,
17
+ namespace: M,
17
18
  sdk: A,
18
19
  service: s,
19
- environment: t
20
+ environment: e
20
21
  },
21
- format: a.combine(a.timestamp(), a.errors({ stack: !0 }), a.json()),
22
- transports: [new E.Console()]
23
- }), U = "payfit.audit-logs.", d = (s) => Object.entries(s).filter(([, t]) => t !== void 0 && t !== "").map(([t, e]) => `${t}:${String(e)}`);
24
- class q {
22
+ format: c.combine(c.timestamp(), c.errors({ stack: !0 }), c.json()),
23
+ transports: [new S.Console()]
24
+ }), q = "payfit.audit_logs.", h = (s) => Object.entries(s).filter(([, e]) => e !== void 0 && e !== "").map(([e, t]) => `${e}:${String(t)}`);
25
+ class b {
25
26
  constructor() {
26
27
  i(this, "client");
27
- this.client = new _({
28
- prefix: U,
28
+ this.client = new E({
29
+ prefix: q,
29
30
  // Loss of metrics never breaks the caller — DogStatsD UDP is best-effort by design.
30
31
  errorHandler: () => {
31
32
  },
32
33
  cacheDns: !0
33
34
  });
34
35
  }
35
- increment(t, e) {
36
- this.client.increment(t, 1, d(e));
36
+ increment(e, t) {
37
+ this.client.increment(e, 1, h(t));
37
38
  }
38
- histogram(t, e, n) {
39
- this.client.histogram(t, e, d(n));
39
+ histogram(e, t, n) {
40
+ this.client.histogram(e, t, h(n));
40
41
  }
41
42
  async close() {
42
- await new Promise((t) => {
43
- this.client.close(() => t());
43
+ await new Promise((e) => {
44
+ this.client.close(() => e());
44
45
  });
45
46
  }
46
47
  }
47
- const C = () => new q(), N = "eu-west-3", O = {
48
+ const D = () => new b();
49
+ function N(s) {
50
+ return L(Buffer.from(s, "utf8")).toString("base64");
51
+ }
52
+ function O(s) {
53
+ return s instanceof Error && s.message.includes("Message must be shorter than");
54
+ }
55
+ const z = "eu-west-3", Q = {
48
56
  dev: "https://sqs.eu-west-3.amazonaws.com/533547282673/audit-logs-ingest",
49
57
  staging: "https://sqs.eu-west-3.amazonaws.com/589883667243/audit-logs-ingest",
50
58
  prod: "https://sqs.eu-west-3.amazonaws.com/614948436281/audit-logs-ingest"
51
- }, z = {
59
+ }, R = {
52
60
  working: "staging",
53
61
  production: "prod"
54
62
  };
55
- class R {
56
- constructor(t) {
63
+ class k {
64
+ constructor(e, t) {
57
65
  i(this, "environment");
66
+ i(this, "logger");
58
67
  i(this, "client");
59
68
  i(this, "queueUrl");
60
- this.environment = t;
61
- const e = z[t] ?? t, n = O[e];
62
- if (!n)
63
- throw new Error(`audit-logs SDK: no SQS queue URL configured for environment "${t}"`);
64
- this.queueUrl = n, this.client = new S({ region: N });
69
+ this.environment = e, this.logger = t;
70
+ const n = R[e] ?? e, o = Q[n];
71
+ if (!o)
72
+ throw new Error(`audit-logs SDK: no SQS queue URL configured for environment "${e}"`);
73
+ this.queueUrl = o, this.client = new _({ region: z });
74
+ }
75
+ async create(e) {
76
+ var n;
77
+ const t = JSON.stringify(e);
78
+ try {
79
+ return await this.send(t), { compressed: !1 };
80
+ } catch (o) {
81
+ if (!O(o))
82
+ throw o;
83
+ return (n = this.logger) == null || n.info("audit-log payload exceeds the SQS size limit, retrying with Brotli compression", { id: e.id, namespace: e.namespace }), await this.send(N(t)), { compressed: !0 };
84
+ }
65
85
  }
66
- async create(t) {
67
- await this.client.send(new L({
86
+ async send(e) {
87
+ await this.client.send(new y({
68
88
  QueueUrl: this.queueUrl,
69
- MessageBody: JSON.stringify(t)
89
+ MessageBody: e
70
90
  }));
71
91
  }
72
92
  }
73
- class x {
74
- constructor(t, e = {}) {
93
+ class V {
94
+ constructor(e, t = {}) {
75
95
  i(this, "params");
76
96
  i(this, "transport");
77
97
  i(this, "logger");
78
98
  i(this, "metrics");
79
- this.params = t, this.transport = e.transport ?? new R(t.environment), this.logger = e.logger ?? M(t.service, t.environment), this.metrics = e.metrics ?? C();
99
+ this.params = e, this.logger = t.logger ?? U(e.service, e.environment), this.transport = t.transport ?? new k(e.environment, this.logger), this.metrics = t.metrics ?? D();
80
100
  }
81
- async log({ scope: t, account: e, ...n }) {
82
- const u = v(), { environment: c, service: g } = this.params, r = {
101
+ async log({ scope: e, account: t, ...n }) {
102
+ const o = w(), { environment: m, service: l } = this.params, r = {
83
103
  ...n,
84
- ...e,
85
- service: g,
86
- id: u,
87
- environment: c,
88
- ...t && { scope: t }
89
- }, o = {
90
- service: g,
91
- environment: c,
104
+ ...t,
105
+ service: l,
106
+ id: o,
107
+ environment: m,
108
+ ...e && { scope: e }
109
+ }, a = {
110
+ service: l,
111
+ environment: m,
92
112
  namespace: r.namespace,
93
113
  event: r.event,
94
114
  target: r.target
95
- }, l = Date.now();
115
+ }, d = Date.now();
96
116
  try {
97
- await this.transport.create(r), this.metrics.increment("sent", o), this.metrics.histogram("send_duration_ms", Date.now() - l, o), this.logger.debug("audit-log sent", {
117
+ const { compressed: g } = await this.transport.create(r);
118
+ this.metrics.increment("sent", {
119
+ ...a,
120
+ compressed: String(g)
121
+ }), this.metrics.histogram("send_duration_ms", Date.now() - d, a), this.logger.debug("audit-log sent", {
98
122
  id: r.id,
99
123
  event: r.event,
100
124
  target: r.target
101
125
  });
102
- } catch (h) {
103
- this.metrics.increment("send_failed", o), this.metrics.histogram("send_duration_ms", Date.now() - l, o);
104
- const m = h.message;
126
+ } catch (g) {
127
+ this.metrics.increment("send_failed", a), this.metrics.histogram("send_duration_ms", Date.now() - d, a);
128
+ const u = g.message;
105
129
  try {
106
130
  this.logger.error("audit-log write failed", {
107
131
  audit_log: r,
108
- error: m
132
+ error: u
109
133
  });
110
134
  } catch {
111
- this.metrics.increment("serialization_failed", o);
135
+ this.metrics.increment("serialization_failed", a);
112
136
  try {
113
137
  this.logger.error("audit-log write failed (serialization failed)", {
114
138
  audit_log_meta: {
@@ -119,7 +143,7 @@ class x {
119
143
  event: r.event,
120
144
  target: r.target
121
145
  },
122
- error: m
146
+ error: u
123
147
  });
124
148
  } catch {
125
149
  }
@@ -128,5 +152,5 @@ class x {
128
152
  }
129
153
  }
130
154
  export {
131
- x as AuditLogger
155
+ V as AuditLogger
132
156
  };
package/dist/metrics.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export declare const METRIC_PREFIX = "payfit.audit-logs.";
1
+ export declare const METRIC_PREFIX = "payfit.audit_logs.";
2
2
  export type MetricName = 'sent' | 'send_failed' | 'serialization_failed' | 'send_duration_ms';
3
3
  export interface MetricTags {
4
4
  service: string;
@@ -6,6 +6,7 @@ export interface MetricTags {
6
6
  namespace?: string;
7
7
  event?: string;
8
8
  target?: string;
9
+ compressed?: string;
9
10
  }
10
11
  export interface IMetricsClient {
11
12
  increment(name: MetricName, tags: MetricTags): void;
@@ -1,8 +1,11 @@
1
- import { IAuditLogCreationData, IAuditLogTransport } from './interface';
1
+ import type { Logger } from 'winston';
2
+ import { IAuditLogCreationData, IAuditLogCreationResult, IAuditLogTransport } from './interface';
2
3
  export declare class Transport implements IAuditLogTransport {
3
4
  protected environment: string;
5
+ private logger?;
4
6
  private client;
5
7
  private queueUrl;
6
- constructor(environment: string);
7
- create(auditLogData: IAuditLogCreationData): Promise<void>;
8
+ constructor(environment: string, logger?: Logger | undefined);
9
+ create(auditLogData: IAuditLogCreationData): Promise<IAuditLogCreationResult>;
10
+ private send;
8
11
  }
@@ -20,6 +20,9 @@ export interface IAuditLogCreationData {
20
20
  specialRole?: string;
21
21
  email?: string;
22
22
  }
23
+ export interface IAuditLogCreationResult {
24
+ compressed: boolean;
25
+ }
23
26
  export interface IAuditLogTransport {
24
- create: (data: IAuditLogCreationData) => Promise<void>;
27
+ create: (data: IAuditLogCreationData) => Promise<IAuditLogCreationResult>;
25
28
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payfit/audit-log",
3
- "version": "3.11.0",
3
+ "version": "3.12.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/PayFit/audit-logs.git",