@lokalise/fastify-extras 25.5.0 → 26.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/README.md CHANGED
@@ -213,7 +213,8 @@ The plugin decorates your Fastify instance with a `NewRelicTransactionManager`,
213
213
 
214
214
  - `start()`, which takes a `jobName`, and starts a background transaction with the provided name;
215
215
  - `stop()`, which takes a `jobId`, and ends the background transaction referenced by the ID;
216
- - `addCustomAttribute()`, which takes `attrName` and `attrValue` and records the custom attribute as such defined. `attrValue` can be a string, a number, or a boolean.
216
+ - `addCustomAttribute()`, which takes `attrName` and `attrValue` and adds the custom attribute to the current transaction. `attrValue` can be a string, a number, or a boolean.
217
+ - `addCustomAttributes()`, which passes `atts` map of the custom attributes to the current transaction. `_uniqueTransactionKey` argument is not used (because New Relic doesn't support setting custom attributes directly on the transaction handle), any string can be passed.
217
218
 
218
219
  ### Amplitude Plugin
219
220
 
@@ -239,6 +240,10 @@ Additionally, you have the option to enhance the safety and accuracy of your eve
239
240
 
240
241
  > 📘Check [`AmplitudeAdapter.spec.ts](./lib/plugins/amplitude/amplitudePlugin.spec.ts) for a practical example
241
242
 
243
+ ### Strip Trailing Slash Plugin
244
+
245
+ This plugin helps with SEO and SSR by ensuring search engines index only one version of a URL, avoiding duplicate content. It redirects URLs with a trailing slash to the version without it, making it easier for search engines to crawl your site consistently.
246
+
242
247
  ### UnhandledException Plugin
243
248
 
244
249
  This plugin provides a mechanism for handling uncaught exceptions within your Fastify application, ensuring that such exceptions are logged and reported. It's especially useful for capturing unforeseen exceptions and provides a controlled shutdown of the Fastify server, thereby ensuring no potential data corruption.
package/dist/index.d.ts CHANGED
@@ -25,6 +25,7 @@ export { amplitudePlugin, type AmplitudeConfig, type CreateApiTrackingEventFn, }
25
25
  export { Amplitude } from './plugins/amplitude/Amplitude';
26
26
  export { AmplitudeAdapter, AMPLITUDE_BASE_MESSAGE_SCHEMA, type AmplitudeMessage, type AmplitudeAdapterDependencies, } from './plugins/amplitude/AmplitudeAdapter';
27
27
  export type { FastifyReplyWithPayload } from './types';
28
+ export { stripTrailingSlashPlugin } from './plugins/stripTrailingSlashPlugin';
28
29
  export { unhandledExceptionPlugin, commonErrorObjectResolver, } from './plugins/unhandledExceptionPlugin';
29
30
  export type { UnhandledExceptionPluginOptions } from './plugins/unhandledExceptionPlugin';
30
31
  export { createErrorHandler, isZodError, type ErrorResponseObject } from './errors/errorHandler';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createStaticTokenAuthPreHandler = exports.decodeJwtToken = exports.generateJwtToken = exports.isZodError = exports.createErrorHandler = exports.commonErrorObjectResolver = exports.unhandledExceptionPlugin = exports.AMPLITUDE_BASE_MESSAGE_SCHEMA = exports.AmplitudeAdapter = exports.Amplitude = exports.amplitudePlugin = exports.commonHealthcheckPlugin = exports.wrapHealthCheck = exports.publicHealthcheckPlugin = exports.metricsPlugin = exports.BackgroundJobsBasedQueueDiscoverer = exports.RedisBasedQueueDiscoverer = exports.bullMqMetricsPlugin = exports.PrometheusCounterTransactionManager = exports.wrapHealthCheckForPrometheus = exports.healthcheckMetricsPlugin = exports.SplitIOFeatureManager = exports.splitIOFeatureManagerPlugin = exports.NewRelicTransactionManager = exports.newrelicTransactionManagerPlugin = exports.getRequestIdFastifyAppConfig = exports.requestContextProviderPlugin = exports.addFeatureFlag = exports.bugsnagErrorReporter = exports.reportErrorToBugsnag = exports.bugsnagPlugin = void 0;
3
+ exports.createStaticTokenAuthPreHandler = exports.decodeJwtToken = exports.generateJwtToken = exports.isZodError = exports.createErrorHandler = exports.commonErrorObjectResolver = exports.unhandledExceptionPlugin = exports.stripTrailingSlashPlugin = exports.AMPLITUDE_BASE_MESSAGE_SCHEMA = exports.AmplitudeAdapter = exports.Amplitude = exports.amplitudePlugin = exports.commonHealthcheckPlugin = exports.wrapHealthCheck = exports.publicHealthcheckPlugin = exports.metricsPlugin = exports.BackgroundJobsBasedQueueDiscoverer = exports.RedisBasedQueueDiscoverer = exports.bullMqMetricsPlugin = exports.PrometheusCounterTransactionManager = exports.wrapHealthCheckForPrometheus = exports.healthcheckMetricsPlugin = exports.SplitIOFeatureManager = exports.splitIOFeatureManagerPlugin = exports.NewRelicTransactionManager = exports.newrelicTransactionManagerPlugin = exports.getRequestIdFastifyAppConfig = exports.requestContextProviderPlugin = exports.addFeatureFlag = exports.bugsnagErrorReporter = exports.reportErrorToBugsnag = exports.bugsnagPlugin = void 0;
4
4
  var bugsnagPlugin_1 = require("./plugins/bugsnagPlugin");
5
5
  Object.defineProperty(exports, "bugsnagPlugin", { enumerable: true, get: function () { return bugsnagPlugin_1.bugsnagPlugin; } });
6
6
  Object.defineProperty(exports, "reportErrorToBugsnag", { enumerable: true, get: function () { return bugsnagPlugin_1.reportErrorToBugsnag; } });
@@ -40,6 +40,8 @@ Object.defineProperty(exports, "Amplitude", { enumerable: true, get: function ()
40
40
  var AmplitudeAdapter_1 = require("./plugins/amplitude/AmplitudeAdapter");
41
41
  Object.defineProperty(exports, "AmplitudeAdapter", { enumerable: true, get: function () { return AmplitudeAdapter_1.AmplitudeAdapter; } });
42
42
  Object.defineProperty(exports, "AMPLITUDE_BASE_MESSAGE_SCHEMA", { enumerable: true, get: function () { return AmplitudeAdapter_1.AMPLITUDE_BASE_MESSAGE_SCHEMA; } });
43
+ var stripTrailingSlashPlugin_1 = require("./plugins/stripTrailingSlashPlugin");
44
+ Object.defineProperty(exports, "stripTrailingSlashPlugin", { enumerable: true, get: function () { return stripTrailingSlashPlugin_1.stripTrailingSlashPlugin; } });
43
45
  var unhandledExceptionPlugin_1 = require("./plugins/unhandledExceptionPlugin");
44
46
  Object.defineProperty(exports, "unhandledExceptionPlugin", { enumerable: true, get: function () { return unhandledExceptionPlugin_1.unhandledExceptionPlugin; } });
45
47
  Object.defineProperty(exports, "commonErrorObjectResolver", { enumerable: true, get: function () { return unhandledExceptionPlugin_1.commonErrorObjectResolver; } });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":";;;AAAA,yDAKgC;AAJ9B,8GAAA,aAAa,OAAA;AACb,qHAAA,oBAAoB,OAAA;AACpB,qHAAA,oBAAoB,OAAA;AACpB,+GAAA,cAAc,OAAA;AAIhB,uFAG+C;AAF7C,4IAAA,4BAA4B,OAAA;AAC5B,4IAAA,4BAA4B,OAAA;AAI9B,+FAGmD;AAFjD,oJAAA,gCAAgC,OAAA;AAChC,8IAAA,0BAA0B,OAAA;AAI5B,qFAG8C;AAF5C,0IAAA,2BAA2B,OAAA;AAC3B,oIAAA,qBAAqB,OAAA;AAIvB,2FAGuD;AAFrD,oIAAA,wBAAwB,OAAA;AACxB,wIAAA,4BAA4B,OAAA;AAQ9B,gHAA8G;AAArG,0JAAA,mCAAmC,OAAA;AAE5C,qEAAmE;AAA1D,0HAAA,mBAAmB,OAAA;AAE5B,+EAGmD;AAFjD,6HAAA,yBAAyB,OAAA;AACzB,sIAAA,kCAAkC,OAAA;AAIpC,yDAAuD;AAA9C,8GAAA,aAAa,OAAA;AAMtB,yFAAuF;AAA9E,kIAAA,uBAAuB,OAAA;AAOhC,+EAA0E;AAAjE,qHAAA,eAAe,OAAA;AAGxB,yFAAuF;AAA9E,kIAAA,uBAAuB,OAAA;AAGhC,uEAI4C;AAH1C,kHAAA,eAAe,OAAA;AAIjB,2DAAyD;AAAhD,sGAAA,SAAS,OAAA;AAClB,yEAK6C;AAJ3C,oHAAA,gBAAgB,OAAA;AAChB,iIAAA,6BAA6B,OAAA;AAO/B,+EAG2C;AAFzC,oIAAA,wBAAwB,OAAA;AACxB,qIAAA,yBAAyB,OAAA;AAI3B,sDAAgG;AAAvF,kHAAA,kBAAkB,OAAA;AAAE,0GAAA,UAAU,OAAA;AAGvC,qDAAyE;AAAhE,8GAAA,gBAAgB,OAAA;AAAE,4GAAA,cAAc,OAAA;AAEzC,iEAA+E;AAAtE,kIAAA,+BAA+B,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":";;;AAAA,yDAKgC;AAJ9B,8GAAA,aAAa,OAAA;AACb,qHAAA,oBAAoB,OAAA;AACpB,qHAAA,oBAAoB,OAAA;AACpB,+GAAA,cAAc,OAAA;AAIhB,uFAG+C;AAF7C,4IAAA,4BAA4B,OAAA;AAC5B,4IAAA,4BAA4B,OAAA;AAI9B,+FAGmD;AAFjD,oJAAA,gCAAgC,OAAA;AAChC,8IAAA,0BAA0B,OAAA;AAI5B,qFAG8C;AAF5C,0IAAA,2BAA2B,OAAA;AAC3B,oIAAA,qBAAqB,OAAA;AAIvB,2FAGuD;AAFrD,oIAAA,wBAAwB,OAAA;AACxB,wIAAA,4BAA4B,OAAA;AAQ9B,gHAA8G;AAArG,0JAAA,mCAAmC,OAAA;AAE5C,qEAAmE;AAA1D,0HAAA,mBAAmB,OAAA;AAE5B,+EAGmD;AAFjD,6HAAA,yBAAyB,OAAA;AACzB,sIAAA,kCAAkC,OAAA;AAIpC,yDAAuD;AAA9C,8GAAA,aAAa,OAAA;AAMtB,yFAAuF;AAA9E,kIAAA,uBAAuB,OAAA;AAOhC,+EAA0E;AAAjE,qHAAA,eAAe,OAAA;AAGxB,yFAAuF;AAA9E,kIAAA,uBAAuB,OAAA;AAGhC,uEAI4C;AAH1C,kHAAA,eAAe,OAAA;AAIjB,2DAAyD;AAAhD,sGAAA,SAAS,OAAA;AAClB,yEAK6C;AAJ3C,oHAAA,gBAAgB,OAAA;AAChB,iIAAA,6BAA6B,OAAA;AAO/B,+EAA6E;AAApE,oIAAA,wBAAwB,OAAA;AAEjC,+EAG2C;AAFzC,oIAAA,wBAAwB,OAAA;AACxB,qIAAA,yBAAyB,OAAA;AAI3B,sDAAgG;AAAvF,kHAAA,kBAAkB,OAAA;AAAE,0GAAA,UAAU,OAAA;AAGvC,qDAAyE;AAAhE,8GAAA,gBAAgB,OAAA;AAAE,4GAAA,cAAc,OAAA;AAEzC,iEAA+E;AAAtE,kIAAA,+BAA+B,OAAA"}
@@ -5,6 +5,7 @@ export interface CommonHealthcheckPluginOptions {
5
5
  logLevel?: 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace' | 'silent';
6
6
  healthChecks: readonly HealthCheck[];
7
7
  infoProviders?: readonly InfoProvider[];
8
+ isRootRouteEnabled?: boolean;
8
9
  }
9
10
  export type InfoProvider = {
10
11
  name: string;
@@ -43,31 +43,26 @@ function addRoute(app, opts, routeOpts) {
43
43
  let isPartiallyHealthy = false;
44
44
  let healthChecks = {};
45
45
  if (opts.healthChecks.length) {
46
- const results = await Promise.all(opts.healthChecks.map((healthcheck) => {
47
- return healthcheck.checker(app).then((result) => {
48
- if (result.error) {
49
- app.log.error(result.error, `${healthcheck.name} healthcheck has failed`);
50
- }
51
- return {
52
- name: healthcheck.name,
53
- result,
54
- isMandatory: healthcheck.isMandatory,
55
- };
56
- });
46
+ const results = await Promise.all(opts.healthChecks.map(async (healthcheck) => {
47
+ const result = await healthcheck.checker(app);
48
+ if (result.error) {
49
+ app.log.error(result.error, `${healthcheck.name} healthcheck has failed`);
50
+ }
51
+ return {
52
+ name: healthcheck.name,
53
+ result,
54
+ isMandatory: healthcheck.isMandatory,
55
+ };
57
56
  }));
58
57
  const resolvedHealthcheckResponse = resolveHealthcheckResults(results, opts);
59
58
  healthChecks = resolvedHealthcheckResponse.healthChecks;
60
59
  isFullyHealthy = resolvedHealthcheckResponse.isFullyHealthy;
61
60
  isPartiallyHealthy = resolvedHealthcheckResponse.isPartiallyHealthy;
62
61
  }
63
- const extraInfo = opts.infoProviders
64
- ? opts.infoProviders.map((infoProvider) => {
65
- return {
66
- name: infoProvider.name,
67
- value: infoProvider.dataResolver(),
68
- };
69
- })
70
- : undefined;
62
+ const extraInfo = opts.infoProviders?.map((infoProvider) => ({
63
+ name: infoProvider.name,
64
+ value: infoProvider.dataResolver(),
65
+ }));
71
66
  const heartbeat = isFullyHealthy
72
67
  ? 'HEALTHY'
73
68
  : isPartiallyHealthy
@@ -84,17 +79,20 @@ function addRoute(app, opts, routeOpts) {
84
79
  },
85
80
  });
86
81
  }
87
- function plugin(app, opts, done) {
88
- addRoute(app, opts, {
89
- url: '/',
90
- isPublicRoute: true,
91
- });
82
+ const plugin = (app, opts, done) => {
83
+ const isRootRouteEnabled = opts.isRootRouteEnabled ?? true;
84
+ if (isRootRouteEnabled) {
85
+ addRoute(app, opts, {
86
+ url: '/',
87
+ isPublicRoute: true,
88
+ });
89
+ }
92
90
  addRoute(app, opts, {
93
91
  url: '/health',
94
92
  isPublicRoute: false,
95
93
  });
96
94
  done();
97
- }
95
+ };
98
96
  exports.commonHealthcheckPlugin = (0, fastify_plugin_1.default)(plugin, {
99
97
  fastify: '5.x',
100
98
  name: 'common-healthcheck-plugin',
@@ -1 +1 @@
1
- {"version":3,"file":"commonHealthcheckPlugin.js","sourceRoot":"","sources":["../../../lib/plugins/healthcheck/commonHealthcheckPlugin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"commonHealthcheckPlugin.js","sourceRoot":"","sources":["../../../lib/plugins/healthcheck/commonHealthcheckPlugin.ts"],"names":[],"mappings":";;;;AAEA,4EAA+B;AAwC/B,SAAS,yBAAyB,CAChC,OAA4B,EAC5B,IAAoC;IAEpC,MAAM,YAAY,GAA2B,EAAE,CAAA;IAC/C,IAAI,cAAc,GAAG,IAAI,CAAA;IACzB,IAAI,kBAAkB,GAAG,KAAK,CAAA;IAE9B,sCAAsC;IACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;QACxB,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAA;QAClE,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;YAC3D,cAAc,GAAG,KAAK,CAAA;YACtB,kBAAkB,GAAG,KAAK,CAAA;QAC5B,CAAC;QAED,kFAAkF;QAClF,IAAI,cAAc,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;YAC9E,cAAc,GAAG,KAAK,CAAA;YACtB,kBAAkB,GAAG,IAAI,CAAA;QAC3B,CAAC;IACH,CAAC;IAED,OAAO;QACL,cAAc;QACd,kBAAkB;QAClB,YAAY;KACb,CAAA;AACH,CAAC;AAED,SAAS,QAAQ,CACf,GAAuB,EACvB,IAAoC,EACpC,SAAkC;IAElC,MAAM,eAAe,GAAG,IAAI,CAAC,eAAe,IAAI,EAAE,CAAA;IAElD,GAAG,CAAC,KAAK,CAAC;QACR,GAAG,EAAE,SAAS,CAAC,GAAG;QAClB,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,MAAM;QACjC,MAAM,EAAE;YACN,kCAAkC;YAClC,mBAAmB;YACnB,IAAI,EAAE,IAAI;SACX;QAED,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE;YAC1B,IAAI,cAAc,GAAG,IAAI,CAAA;YACzB,IAAI,kBAAkB,GAAG,KAAK,CAAA;YAC9B,IAAI,YAAY,GAA2B,EAAE,CAAA;YAE7C,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;gBAC7B,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE;oBAC1C,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;oBAC7C,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;wBACjB,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,WAAW,CAAC,IAAI,yBAAyB,CAAC,CAAA;oBAC3E,CAAC;oBACD,OAAO;wBACL,IAAI,EAAE,WAAW,CAAC,IAAI;wBACtB,MAAM;wBACN,WAAW,EAAE,WAAW,CAAC,WAAW;qBACrC,CAAA;gBACH,CAAC,CAAC,CACH,CAAA;gBAED,MAAM,2BAA2B,GAAG,yBAAyB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;gBAC5E,YAAY,GAAG,2BAA2B,CAAC,YAAY,CAAA;gBACvD,cAAc,GAAG,2BAA2B,CAAC,cAAc,CAAA;gBAC3D,kBAAkB,GAAG,2BAA2B,CAAC,kBAAkB,CAAA;YACrE,CAAC;YAED,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;gBAC3D,IAAI,EAAE,YAAY,CAAC,IAAI;gBACvB,KAAK,EAAE,YAAY,CAAC,YAAY,EAAE;aACnC,CAAC,CAAC,CAAA;YAEH,MAAM,SAAS,GAAG,cAAc;gBAC9B,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,kBAAkB;oBAClB,CAAC,CAAC,mBAAmB;oBACrB,CAAC,CAAC,MAAM,CAAA;YAEZ,MAAM,QAAQ,GAAG;gBACf,GAAG,eAAe;gBAClB,SAAS;gBACT,GAAG,CAAC,SAAS,CAAC,aAAa;oBACzB,CAAC,CAAC,EAAE;oBACJ,CAAC,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,CAAC,SAAS,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;aAC/D,CAAA;YAED,OAAO,KAAK,CAAC,MAAM,CAAC,cAAc,IAAI,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACtF,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,MAAM,GAA0D,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;IACxF,MAAM,kBAAkB,GAAG,IAAI,CAAC,kBAAkB,IAAI,IAAI,CAAA;IAE1D,IAAI,kBAAkB,EAAE,CAAC;QACvB,QAAQ,CAAC,GAAG,EAAE,IAAI,EAAE;YAClB,GAAG,EAAE,GAAG;YACR,aAAa,EAAE,IAAI;SACpB,CAAC,CAAA;IACJ,CAAC;IAED,QAAQ,CAAC,GAAG,EAAE,IAAI,EAAE;QAClB,GAAG,EAAE,SAAS;QACd,aAAa,EAAE,KAAK;KACrB,CAAC,CAAA;IAEF,IAAI,EAAE,CAAA;AACR,CAAC,CAAA;AAEY,QAAA,uBAAuB,GAAG,IAAA,wBAAE,EAAC,MAAM,EAAE;IAChD,OAAO,EAAE,KAAK;IACd,IAAI,EAAE,2BAA2B;CAClC,CAAC,CAAA"}
@@ -13,6 +13,9 @@ export declare class NewRelicTransactionManager implements TransactionObservabil
13
13
  private readonly transactionMap;
14
14
  constructor(isNewRelicEnabled: boolean);
15
15
  addCustomAttribute(attrName: string, attrValue: string | number | boolean): void;
16
+ addCustomAttributes(_uniqueTransactionKey: string, atts: {
17
+ [p: string]: string | number | boolean;
18
+ }): void;
16
19
  /**
17
20
  * @param transactionName - used for grouping similar transactions together
18
21
  * @param uniqueTransactionKey - used for identifying specific ongoing transaction. Must be reasonably unique to reduce possibility of collisions
@@ -22,6 +22,12 @@ class NewRelicTransactionManager {
22
22
  }
23
23
  newrelic.addCustomAttribute(attrName, attrValue);
24
24
  }
25
+ addCustomAttributes(_uniqueTransactionKey, atts) {
26
+ if (!this.isEnabled) {
27
+ return;
28
+ }
29
+ newrelic.addCustomAttributes(atts);
30
+ }
25
31
  /**
26
32
  * @param transactionName - used for grouping similar transactions together
27
33
  * @param uniqueTransactionKey - used for identifying specific ongoing transaction. Must be reasonably unique to reduce possibility of collisions
@@ -1 +1 @@
1
- {"version":3,"file":"newrelicTransactionManagerPlugin.js","sourceRoot":"","sources":["../../lib/plugins/newrelicTransactionManagerPlugin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"newrelicTransactionManagerPlugin.js","sourceRoot":"","sources":["../../lib/plugins/newrelicTransactionManagerPlugin.ts"],"names":[],"mappings":"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"}
@@ -4,14 +4,23 @@ import type { IFastifyMetrics } from 'fastify-metrics';
4
4
  * TransactionObservabilityManager implementation that uses Prometheus counter
5
5
  * to track the number of started, failed and success transactions.
6
6
  */
7
- export declare class PrometheusCounterTransactionManager implements TransactionObservabilityManager {
7
+ export declare class PrometheusCounterTransactionManager<CustomLabels extends string = never> implements TransactionObservabilityManager {
8
8
  private readonly metricName;
9
9
  private readonly metricDescription;
10
+ private readonly supportedCustomLabels;
10
11
  private readonly counter?;
11
12
  private readonly transactionNameByKey;
12
- constructor(metricName: string, metricDescription: string, appMetrics?: IFastifyMetrics);
13
+ private readonly customLabelsByKey;
14
+ constructor(metricName: string, metricDescription: string, appMetrics?: IFastifyMetrics, customLabels?: Array<CustomLabels>);
13
15
  start(transactionName: string, uniqueTransactionKey: string): void;
14
16
  startWithGroup(transactionName: string, uniqueTransactionKey: string, _transactionGroup: string): void;
15
17
  stop(uniqueTransactionKey: string, wasSuccessful?: boolean): void;
18
+ /**
19
+ * Prometheus labels are the way Prometheus handles custom attributes
20
+ * Note that it will skip any attributes that were not included in the constructor param "customLabels"
21
+ */
22
+ addCustomAttributes(uniqueTransactionKey: string, atts: {
23
+ [p: string]: string | number | boolean;
24
+ }): void;
16
25
  private registerMetric;
17
26
  }
@@ -8,12 +8,15 @@ exports.PrometheusCounterTransactionManager = void 0;
8
8
  class PrometheusCounterTransactionManager {
9
9
  metricName;
10
10
  metricDescription;
11
+ supportedCustomLabels;
11
12
  counter;
12
13
  transactionNameByKey = new Map();
13
- constructor(metricName, metricDescription, appMetrics) {
14
+ customLabelsByKey = new Map();
15
+ constructor(metricName, metricDescription, appMetrics, customLabels) {
14
16
  this.metricName = metricName;
15
17
  this.metricDescription = metricDescription;
16
- this.counter = this.registerMetric(appMetrics);
18
+ this.supportedCustomLabels = new Set(customLabels) ?? new Set();
19
+ this.counter = this.registerMetric(appMetrics, customLabels);
17
20
  }
18
21
  start(transactionName, uniqueTransactionKey) {
19
22
  this.transactionNameByKey.set(uniqueTransactionKey, transactionName);
@@ -27,10 +30,40 @@ class PrometheusCounterTransactionManager {
27
30
  const transactionName = this.transactionNameByKey.get(uniqueTransactionKey);
28
31
  if (!transactionName)
29
32
  return;
30
- this.counter?.inc({ status: wasSuccessful ? 'success' : 'failed', transactionName });
33
+ const labels = {
34
+ status: wasSuccessful ? 'success' : 'failed',
35
+ transactionName,
36
+ };
37
+ let labelsWithCustom;
38
+ if (this.customLabelsByKey.has(uniqueTransactionKey)) {
39
+ const customLabels = this.customLabelsByKey.get(uniqueTransactionKey);
40
+ labelsWithCustom = {
41
+ ...labels,
42
+ // biome-ignore lint/style/noNonNullAssertion: we already checked the presence
43
+ ...customLabels,
44
+ };
45
+ }
46
+ this.counter?.inc(labelsWithCustom ?? labels);
31
47
  this.transactionNameByKey.delete(uniqueTransactionKey);
48
+ this.customLabelsByKey.delete(uniqueTransactionKey);
32
49
  }
33
- registerMetric(appMetrics) {
50
+ /**
51
+ * Prometheus labels are the way Prometheus handles custom attributes
52
+ * Note that it will skip any attributes that were not included in the constructor param "customLabels"
53
+ */
54
+ addCustomAttributes(uniqueTransactionKey, atts) {
55
+ const transactionName = this.transactionNameByKey.get(uniqueTransactionKey);
56
+ if (!transactionName)
57
+ return;
58
+ const supportedLabels = Object.entries(atts).reduce((acc, [key, value]) => {
59
+ if (this.supportedCustomLabels.has(key)) {
60
+ acc[key] = value;
61
+ }
62
+ return acc;
63
+ }, {});
64
+ this.customLabelsByKey.set(uniqueTransactionKey, supportedLabels);
65
+ }
66
+ registerMetric(appMetrics, customLabels = []) {
34
67
  if (!appMetrics)
35
68
  return;
36
69
  const existingMetric = appMetrics.client.register.getSingleMetric(this.metricName);
@@ -39,7 +72,7 @@ class PrometheusCounterTransactionManager {
39
72
  return new appMetrics.client.Counter({
40
73
  name: this.metricName,
41
74
  help: this.metricDescription,
42
- labelNames: ['status', 'transactionName'],
75
+ labelNames: ['status', 'transactionName', ...customLabels],
43
76
  });
44
77
  }
45
78
  }
@@ -1 +1 @@
1
- {"version":3,"file":"PrometheusCounterTransactionManager.js","sourceRoot":"","sources":["../../../lib/plugins/prometheus/PrometheusCounterTransactionManager.ts"],"names":[],"mappings":";;;AAIA;;;GAGG;AACH,MAAa,mCAAmC;IAC7B,UAAU,CAAQ;IAClB,iBAAiB,CAAQ;IACzB,OAAO,CAAwC;IAE/C,oBAAoB,GAAwB,IAAI,GAAG,EAAE,CAAA;IAEtE,YAAY,UAAkB,EAAE,iBAAyB,EAAE,UAA4B;QACrF,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAC5B,IAAI,CAAC,iBAAiB,GAAG,iBAAiB,CAAA;QAC1C,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,CAAA;IAChD,CAAC;IAED,KAAK,CAAC,eAAuB,EAAE,oBAA4B;QACzD,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,oBAAoB,EAAE,eAAe,CAAC,CAAA;QACpE,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,eAAe,EAAE,eAAe,EAAE,CAAC,CAAA;IAC5E,CAAC;IAED,cAAc,CACZ,eAAuB,EACvB,oBAA4B,EAC5B,iBAAyB;QAEzB,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,oBAAoB,EAAE,eAAe,CAAC,CAAA;QACpE,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC,CAAA;IAC3D,CAAC;IAED,IAAI,CAAC,oBAA4B,EAAE,aAAa,GAAG,IAAI;QACrD,MAAM,eAAe,GAAG,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAA;QAC3E,IAAI,CAAC,eAAe;YAAE,OAAM;QAE5B,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,eAAe,EAAE,CAAC,CAAA;QACpF,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAA;IACxD,CAAC;IAEO,cAAc,CAAC,UAA4B;QACjD,IAAI,CAAC,UAAU;YAAE,OAAM;QAEvB,MAAM,cAAc,GAAwB,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CACpF,IAAI,CAAC,UAAU,CACO,CAAA;QAExB,IAAI,cAAc;YAAE,OAAO,cAAc,CAAA;QAEzC,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC;YACnC,IAAI,EAAE,IAAI,CAAC,UAAU;YACrB,IAAI,EAAE,IAAI,CAAC,iBAAiB;YAC5B,UAAU,EAAE,CAAC,QAAQ,EAAE,iBAAiB,CAAC;SAC1C,CAAC,CAAA;IACJ,CAAC;CACF;AAlDD,kFAkDC"}
1
+ {"version":3,"file":"PrometheusCounterTransactionManager.js","sourceRoot":"","sources":["../../../lib/plugins/prometheus/PrometheusCounterTransactionManager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { FastifyPluginCallback } from 'fastify';
2
+ export declare const stripTrailingSlashPlugin: FastifyPluginCallback;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stripTrailingSlashPlugin = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const fastify_plugin_1 = tslib_1.__importDefault(require("fastify-plugin"));
6
+ const pluginCallback = (fastify, _options, done) => {
7
+ fastify.addHook('onRequest', (request, reply, done) => {
8
+ const { pathname, search } = new URL(`${request.protocol}://${request.hostname}:${request.port}${request.url}`);
9
+ if (pathname.length > 1 && pathname.endsWith('/')) {
10
+ reply.redirect(`${pathname.slice(0, -1)}${search}`, 302);
11
+ }
12
+ else {
13
+ done();
14
+ }
15
+ });
16
+ done();
17
+ };
18
+ exports.stripTrailingSlashPlugin = (0, fastify_plugin_1.default)(pluginCallback, {
19
+ fastify: '5.x',
20
+ name: 'strip-trailing-slash-plugin',
21
+ });
22
+ //# sourceMappingURL=stripTrailingSlashPlugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stripTrailingSlashPlugin.js","sourceRoot":"","sources":["../../lib/plugins/stripTrailingSlashPlugin.ts"],"names":[],"mappings":";;;;AACA,4EAA+B;AAE/B,MAAM,cAAc,GAA0B,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE;IACxE,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACpD,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,GAAG,CAClC,GAAG,OAAO,CAAC,QAAQ,MAAM,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAC1E,CAAA;QAED,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAClD,KAAK,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM,EAAE,EAAE,GAAG,CAAC,CAAA;QAC1D,CAAC;aAAM,CAAC;YACN,IAAI,EAAE,CAAA;QACR,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,IAAI,EAAE,CAAA;AACR,CAAC,CAAA;AAEY,QAAA,wBAAwB,GAAG,IAAA,wBAAE,EAAC,cAAc,EAAE;IACzD,OAAO,EAAE,KAAK;IACd,IAAI,EAAE,6BAA6B;CACpC,CAAC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lokalise/fastify-extras",
3
- "version": "25.5.0",
3
+ "version": "26.1.0",
4
4
  "description": "Opinionated set of fastify plugins, commonly used in Lokalise",
5
5
  "author": {
6
6
  "name": "Lokalise",
@@ -35,7 +35,7 @@
35
35
  "@amplitude/analytics-node": "^1.3.6",
36
36
  "@bugsnag/js": "^8.1.2",
37
37
  "@lokalise/error-utils": "^2.2.0",
38
- "@splitsoftware/splitio": "^11.0.1",
38
+ "@splitsoftware/splitio": "^11.0.3",
39
39
  "@supercharge/promise-pool": "^3.2.0",
40
40
  "fastify-metrics": "^12.1.0",
41
41
  "fastify-plugin": "^5.0.1",
@@ -47,7 +47,7 @@
47
47
  "peerDependencies": {
48
48
  "@fastify/jwt": "^9.0.1",
49
49
  "@lokalise/background-jobs-common": ">=8.0.0",
50
- "@lokalise/node-core": ">=12.0.0",
50
+ "@lokalise/node-core": ">=13.3.0",
51
51
  "bullmq": "^5.19.0",
52
52
  "fastify": "^5.0.0",
53
53
  "ioredis": "^5.4.1",
@@ -58,25 +58,25 @@
58
58
  "devDependencies": {
59
59
  "@amplitude/analytics-types": "^2.8.4",
60
60
  "@biomejs/biome": "^1.9.4",
61
- "@lokalise/backend-http-client": "^2.4.0",
62
- "@lokalise/background-jobs-common": "^9.0.0",
61
+ "@lokalise/backend-http-client": "^3.0.0",
62
+ "@lokalise/background-jobs-common": "^10.0.1",
63
63
  "@lokalise/biome-config": "^1.5.0",
64
- "@lokalise/node-core": "^13.1.0",
65
- "@types/newrelic": "^9.14.5",
66
- "@types/node": "^22.9.0",
67
- "@vitest/coverage-v8": "^2.1.4",
64
+ "@lokalise/node-core": "^13.3.0",
65
+ "@types/newrelic": "^9.14.6",
66
+ "@types/node": "^22.10.2",
67
+ "@vitest/coverage-v8": "^2.1.8",
68
68
  "auto-changelog": "^2.4.0",
69
- "bullmq": "^5.21.1",
70
- "fastify": "^5.1.0",
69
+ "bullmq": "^5.34.2",
70
+ "fastify": "^5.2.0",
71
71
  "fastify-type-provider-zod": "^4.0.2",
72
72
  "ioredis": "^5.4.1",
73
- "newrelic": "12.8.0",
74
- "pino": "^9.4.0",
73
+ "newrelic": "12.13.0",
74
+ "pino": "^9.5.0",
75
75
  "pino-pretty": "^13.0.0",
76
76
  "shx": "^0.3.4",
77
- "typescript": "^5.6.3",
78
- "vitest": "^2.1.4",
79
- "zod": "^3.23.8"
77
+ "typescript": "^5.7.2",
78
+ "vitest": "^2.1.8",
79
+ "zod": "^3.24.1"
80
80
  },
81
81
  "engines": {
82
82
  "node": ">=20"