apitally 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +136 -0
  3. package/dist/common/client.d.ts +37 -0
  4. package/dist/common/client.d.ts.map +1 -0
  5. package/dist/common/client.js +243 -0
  6. package/dist/common/client.js.map +1 -0
  7. package/dist/common/index.d.ts +2 -0
  8. package/dist/common/index.d.ts.map +1 -0
  9. package/dist/common/index.js +6 -0
  10. package/dist/common/index.js.map +1 -0
  11. package/dist/common/keyRegistry.d.ts +29 -0
  12. package/dist/common/keyRegistry.d.ts.map +1 -0
  13. package/dist/common/keyRegistry.js +90 -0
  14. package/dist/common/keyRegistry.js.map +1 -0
  15. package/dist/common/logging.d.ts +8 -0
  16. package/dist/common/logging.d.ts.map +1 -0
  17. package/dist/common/logging.js +13 -0
  18. package/dist/common/logging.js.map +1 -0
  19. package/dist/common/requestLogger.d.ts +10 -0
  20. package/dist/common/requestLogger.d.ts.map +1 -0
  21. package/dist/common/requestLogger.js +49 -0
  22. package/dist/common/requestLogger.js.map +1 -0
  23. package/dist/common/types.d.ts +56 -0
  24. package/dist/common/types.d.ts.map +1 -0
  25. package/dist/common/types.js +3 -0
  26. package/dist/common/types.js.map +1 -0
  27. package/dist/common/utils.d.ts +4 -0
  28. package/dist/common/utils.d.ts.map +1 -0
  29. package/dist/common/utils.js +23 -0
  30. package/dist/common/utils.js.map +1 -0
  31. package/dist/common/validationErrorLogger.d.ts +9 -0
  32. package/dist/common/validationErrorLogger.d.ts.map +1 -0
  33. package/dist/common/validationErrorLogger.js +40 -0
  34. package/dist/common/validationErrorLogger.js.map +1 -0
  35. package/dist/express/auth.d.ts +6 -0
  36. package/dist/express/auth.d.ts.map +1 -0
  37. package/dist/express/auth.js +66 -0
  38. package/dist/express/auth.js.map +1 -0
  39. package/dist/express/index.d.ts +3 -0
  40. package/dist/express/index.d.ts.map +1 -0
  41. package/dist/express/index.js +8 -0
  42. package/dist/express/index.js.map +1 -0
  43. package/dist/express/listEndpoints.d.ts +3 -0
  44. package/dist/express/listEndpoints.d.ts.map +1 -0
  45. package/dist/express/listEndpoints.js +166 -0
  46. package/dist/express/listEndpoints.js.map +1 -0
  47. package/dist/express/middleware.d.ts +4 -0
  48. package/dist/express/middleware.d.ts.map +1 -0
  49. package/dist/express/middleware.js +164 -0
  50. package/dist/express/middleware.js.map +1 -0
  51. package/dist/fastify/auth.d.ts +6 -0
  52. package/dist/fastify/auth.d.ts.map +1 -0
  53. package/dist/fastify/auth.js +66 -0
  54. package/dist/fastify/auth.js.map +1 -0
  55. package/dist/fastify/index.d.ts +3 -0
  56. package/dist/fastify/index.d.ts.map +1 -0
  57. package/dist/fastify/index.js +11 -0
  58. package/dist/fastify/index.js.map +1 -0
  59. package/dist/fastify/plugin.d.ts +16 -0
  60. package/dist/fastify/plugin.d.ts.map +1 -0
  61. package/dist/fastify/plugin.js +122 -0
  62. package/dist/fastify/plugin.js.map +1 -0
  63. package/dist/index.d.ts +2 -0
  64. package/dist/index.d.ts.map +1 -0
  65. package/dist/index.js +3 -0
  66. package/dist/index.js.map +1 -0
  67. package/dist/koa/auth.d.ts +6 -0
  68. package/dist/koa/auth.d.ts.map +1 -0
  69. package/dist/koa/auth.js +67 -0
  70. package/dist/koa/auth.js.map +1 -0
  71. package/dist/koa/index.d.ts +3 -0
  72. package/dist/koa/index.d.ts.map +1 -0
  73. package/dist/koa/index.js +8 -0
  74. package/dist/koa/index.js.map +1 -0
  75. package/dist/koa/middleware.d.ts +4 -0
  76. package/dist/koa/middleware.d.ts.map +1 -0
  77. package/dist/koa/middleware.js +108 -0
  78. package/dist/koa/middleware.js.map +1 -0
  79. package/dist/nestjs/auth.d.ts +10 -0
  80. package/dist/nestjs/auth.d.ts.map +1 -0
  81. package/dist/nestjs/auth.js +84 -0
  82. package/dist/nestjs/auth.js.map +1 -0
  83. package/dist/nestjs/index.d.ts +3 -0
  84. package/dist/nestjs/index.d.ts.map +1 -0
  85. package/dist/nestjs/index.js +9 -0
  86. package/dist/nestjs/index.js.map +1 -0
  87. package/package.json +128 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Apitally
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,136 @@
1
+ <p align="center">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://assets.apitally.io/logos/logo-vertical-dark.png">
4
+ <source media="(prefers-color-scheme: light)" srcset="https://assets.apitally.io/logos/logo-vertical-light.png">
5
+ <img alt="Apitally logo" src="https://assets.apitally.io/logos/logo-vertical-light.png">
6
+ </picture>
7
+ </p>
8
+
9
+ <p align="center"><b>Your refreshingly simple REST API companion.</b></p>
10
+
11
+ <p align="center"><i>Apitally gives busy engineering teams valuable insights into how their APIs are being used and allows them to secure their applications with API keys managed through a simple dashboard. It is easy to set up and use with new and existing API projects.</i></p>
12
+
13
+ <p align="center">🔗 <b><a href="https://apitally.io" target="_blank">apitally.io</a></b></p>
14
+
15
+ ![Apitally screenshots](https://assets.apitally.io/screenshots/overview.png)
16
+
17
+ ---
18
+
19
+ # Apitally client library for Node.js
20
+
21
+ [![Tests](https://github.com/apitally/nodejs-client/actions/workflows/tests.yaml/badge.svg?event=push)](https://github.com/apitally/nodejs-client/actions)
22
+ [![Codecov](https://codecov.io/gh/apitally/nodejs-client/graph/badge.svg?token=j5jqlrL7Pd)](https://codecov.io/gh/apitally/nodejs-client)
23
+
24
+ This client library for Apitally currently supports the following Node.js web frameworks:
25
+
26
+ - [Express](https://docs.apitally.io/frameworks/express)
27
+ - [NestJS](https://docs.apitally.io/frameworks/nestjs) (with Express)
28
+ - [Fastify](https://docs.apitally.io/frameworks/fastify)
29
+ - [Koa](https://docs.apitally.io/frameworks/koa)
30
+
31
+ Learn more about Apitally on our 🌎 [website](https://apitally.io) or check out the 📚 [documentation](https://docs.apitally.io).
32
+
33
+ ## Key features
34
+
35
+ - Middleware/plugins for different frameworks to capture metadata about API endpoints, requests and responses (no sensitive data is captured)
36
+ - Non-blocking client that aggregates and sends captured data to Apitally and optionally synchronizes API key hashes in 1 minute intervals
37
+ - Functions to easily secure endpoints with API key authentication and permission checks
38
+
39
+ ## Installation
40
+
41
+ You can install this library in your project using `npm` or `yarn`:
42
+
43
+ ```bash
44
+ npm install apitally
45
+ ```
46
+
47
+ or
48
+
49
+ ```bash
50
+ yarn add apitally
51
+ ```
52
+
53
+ ## Usage
54
+
55
+ Our comprehensive [setup guides](https://docs.apitally.io/quickstart) include all the details you need to get started.
56
+
57
+ ### Express
58
+
59
+ This is an example of how to use the Apitally middleware with an Express application. For further instructions, see our [setup guide for Express](https://docs.apitally.io/frameworks/express).
60
+
61
+ ```javascript
62
+ const express = require("express");
63
+ const { useApitally } = require("apitally/express");
64
+
65
+ const app = express();
66
+ app.use(express.json());
67
+
68
+ useApitally(app, {
69
+ clientId: "your-client-id",
70
+ env: "your-env-name",
71
+ });
72
+ ```
73
+
74
+ ### NestJS
75
+
76
+ This is an example of how to use the Apitally middleware with a NestJS application. For further instructions, see our [setup guide for NestJS](https://docs.apitally.io/frameworks/nestjs).
77
+
78
+ _Note_: Currently only NestJS applications that use Express as the underlying HTTP server are supported (the default).
79
+
80
+ ```javascript
81
+ const { NestFactory } = require("@nestjs/core");
82
+ const { useApitally } = require("apitally/nestjs");
83
+ const { AppModule } = require("./app.module");
84
+
85
+ const app = await NestFactory.create(AppModule);
86
+ const expressInstance = app.getHttpAdapter().getInstance();
87
+
88
+ useApitally(expressInstance, {
89
+ clientId: "your-client-id",
90
+ env: "your-env-name",
91
+ });
92
+ ```
93
+
94
+ ### Fastify
95
+
96
+ This is an example of how to register the Apitally plugin with a Fastify application. For further instructions, see our [setup guide for Fastify](https://docs.apitally.io/frameworks/fastify).
97
+
98
+ _Note:_ The Apitally plugin requires the [`fastify-plugin`](https://www.npmjs.com/package/fastify-plugin) package to be installed.
99
+
100
+ ```bash
101
+ npm install fastify-plugin
102
+ ```
103
+
104
+ ```javascript
105
+ const fastify = require("fastify")({ logger: true });
106
+ const { apitallyPlugin } = require("apitally/fastify");
107
+
108
+ await app.register(apitallyPlugin, {
109
+ clientId: "your-client-id",
110
+ env: "your-env-name",
111
+ });
112
+ ```
113
+
114
+ ### Koa
115
+
116
+ This is an example of how to use the Apitally middleware with a Koa application. For further instructions, see our [setup guide for Koa](https://docs.apitally.io/frameworks/koa).
117
+
118
+ ```javascript
119
+ const Koa = require("koa");
120
+ const { useApitally } = require("apitally/koa");
121
+
122
+ const app = new Koa();
123
+
124
+ useApitally(app, {
125
+ clientId: "your-client-id",
126
+ env: "your-env-name",
127
+ });
128
+ ```
129
+
130
+ ## Getting help
131
+
132
+ If you need help please [create a new discussion](https://github.com/orgs/apitally/discussions/categories/q-a) on GitHub.
133
+
134
+ ## License
135
+
136
+ This library is licensed under the terms of the MIT license.
@@ -0,0 +1,37 @@
1
+ import { KeyCacheBase, KeyRegistry } from "./keyRegistry";
2
+ import { Logger } from "./logging";
3
+ import RequestLogger from "./requestLogger";
4
+ import { ApitallyConfig, AppInfo } from "./types";
5
+ import ValidationErrorLogger from "./validationErrorLogger";
6
+ export declare class ApitallyClient {
7
+ private clientId;
8
+ private env;
9
+ private syncApiKeys;
10
+ private static instance?;
11
+ private instanceUuid;
12
+ private requestsDataQueue;
13
+ private axiosClient;
14
+ private syncIntervalId?;
15
+ appInfo?: AppInfo;
16
+ private appInfoSent;
17
+ private startedAt;
18
+ private keysUpdated?;
19
+ requestLogger: RequestLogger;
20
+ validationErrorLogger: ValidationErrorLogger;
21
+ keyRegistry: KeyRegistry;
22
+ keyCache?: KeyCacheBase;
23
+ logger: Logger;
24
+ constructor({ clientId, env, syncApiKeys, logger, keyCacheClass, }: ApitallyConfig);
25
+ static getInstance(): ApitallyClient;
26
+ private getHubUrl;
27
+ private startSync;
28
+ private sync;
29
+ private stopSync;
30
+ handleShutdown(): Promise<void>;
31
+ setAppInfo(appInfo: AppInfo): void;
32
+ private sendAppInfo;
33
+ private sendRequestsData;
34
+ private getKeys;
35
+ private updateKeyRegistry;
36
+ }
37
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/common/client.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAa,MAAM,WAAW,CAAC;AAC9C,OAAO,aAAa,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EACL,cAAc,EACd,OAAO,EAGR,MAAM,SAAS,CAAC;AAEjB,OAAO,qBAAqB,MAAM,yBAAyB,CAAC;AAM5D,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,WAAW,CAAU;IAE7B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAiB;IACzC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,iBAAiB,CAAuC;IAChE,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,cAAc,CAAC,CAAiB;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,WAAW,CAAC,CAAS;IAEtB,aAAa,EAAE,aAAa,CAAC;IAC7B,qBAAqB,EAAE,qBAAqB,CAAC;IAC7C,WAAW,EAAE,WAAW,CAAC;IACzB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;gBAEV,EACV,QAAQ,EACR,GAAe,EACf,WAAmB,EACnB,MAAM,EACN,aAAa,GACd,EAAE,cAAc;WAwDH,WAAW,IAAI,cAAc;IAO3C,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,SAAS;YAOH,IAAI;IAiBlB,OAAO,CAAC,QAAQ;IAMH,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAMrC,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;YAM3B,WAAW;YAkCX,gBAAgB;YAsChB,OAAO;IA6BrB,OAAO,CAAC,iBAAiB;CAQ1B"}
@@ -0,0 +1,243 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ var __importDefault = (this && this.__importDefault) || function (mod) {
35
+ return (mod && mod.__esModule) ? mod : { "default": mod };
36
+ };
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ exports.ApitallyClient = void 0;
39
+ const axios_1 = __importStar(require("axios"));
40
+ const axios_retry_1 = __importDefault(require("axios-retry"));
41
+ const crypto_1 = require("crypto");
42
+ const keyRegistry_1 = require("./keyRegistry");
43
+ const logging_1 = require("./logging");
44
+ const requestLogger_1 = __importDefault(require("./requestLogger"));
45
+ const utils_1 = require("./utils");
46
+ const validationErrorLogger_1 = __importDefault(require("./validationErrorLogger"));
47
+ const SYNC_INTERVAL = 60000; // 60 seconds
48
+ const REQUEST_TIMEOUT = 10000; // 10 seconds
49
+ const MAX_QUEUE_TIME = 3.6e6; // 1 hour
50
+ class ApitallyClient {
51
+ constructor({ clientId, env = "default", syncApiKeys = false, logger, keyCacheClass, }) {
52
+ this.appInfoSent = false;
53
+ if (ApitallyClient.instance) {
54
+ throw new Error("Apitally client is already initialized");
55
+ }
56
+ if (!(0, utils_1.isValidClientId)(clientId)) {
57
+ throw new Error(`Invalid client ID '${clientId}' (expecting hexadeciaml UUID format)`);
58
+ }
59
+ if (!(0, utils_1.isValidEnv)(env)) {
60
+ throw new Error(`Invalid env '${env}' (expecting 1-32 alphanumeric lowercase characters and hyphens only)`);
61
+ }
62
+ ApitallyClient.instance = this;
63
+ this.clientId = clientId;
64
+ this.env = env;
65
+ this.syncApiKeys = syncApiKeys;
66
+ this.instanceUuid = (0, crypto_1.randomUUID)();
67
+ this.requestsDataQueue = [];
68
+ this.startedAt = Date.now();
69
+ this.requestLogger = new requestLogger_1.default();
70
+ this.validationErrorLogger = new validationErrorLogger_1.default();
71
+ this.keyRegistry = new keyRegistry_1.KeyRegistry();
72
+ this.keyCache = keyCacheClass
73
+ ? new keyCacheClass(clientId, env)
74
+ : undefined;
75
+ this.logger = logger || (0, logging_1.getLogger)();
76
+ this.axiosClient = axios_1.default.create({
77
+ baseURL: this.getHubUrl(),
78
+ timeout: REQUEST_TIMEOUT,
79
+ });
80
+ (0, axios_retry_1.default)(this.axiosClient, {
81
+ retries: 3,
82
+ retryDelay: (retryCount, error) => axios_retry_1.default.exponentialDelay(retryCount, error, 1000),
83
+ });
84
+ if (this.keyCache) {
85
+ const keyDataString = this.keyCache.retrieve();
86
+ if (keyDataString) {
87
+ try {
88
+ const keyData = JSON.parse(keyDataString);
89
+ this.updateKeyRegistry(keyData, false);
90
+ }
91
+ catch (error) {
92
+ this.logger.error("Failed to load API keys from cache.", { error });
93
+ }
94
+ }
95
+ }
96
+ this.startSync();
97
+ this.handleShutdown = this.handleShutdown.bind(this);
98
+ }
99
+ static getInstance() {
100
+ if (!ApitallyClient.instance) {
101
+ throw new Error("Apitally client is not initialized");
102
+ }
103
+ return ApitallyClient.instance;
104
+ }
105
+ getHubUrl() {
106
+ const baseURL = process.env.APITALLY_HUB_BASE_URL || "https://hub.apitally.io";
107
+ const version = "v1";
108
+ return `${baseURL}/${version}/${this.clientId}/${this.env}`;
109
+ }
110
+ startSync() {
111
+ this.sync();
112
+ this.syncIntervalId = setInterval(() => {
113
+ this.sync();
114
+ }, SYNC_INTERVAL);
115
+ }
116
+ sync() {
117
+ return __awaiter(this, void 0, void 0, function* () {
118
+ try {
119
+ const promises = [this.sendRequestsData()];
120
+ if (this.syncApiKeys) {
121
+ promises.push(this.getKeys());
122
+ }
123
+ if (!this.appInfoSent) {
124
+ promises.push(this.sendAppInfo());
125
+ }
126
+ yield Promise.all(promises);
127
+ }
128
+ catch (error) {
129
+ this.logger.error("Error while syncing with Apitally Hub.", {
130
+ error,
131
+ });
132
+ }
133
+ });
134
+ }
135
+ stopSync() {
136
+ if (this.syncIntervalId) {
137
+ clearInterval(this.syncIntervalId);
138
+ }
139
+ }
140
+ handleShutdown() {
141
+ return __awaiter(this, void 0, void 0, function* () {
142
+ this.stopSync();
143
+ yield this.sendRequestsData();
144
+ ApitallyClient.instance = undefined;
145
+ });
146
+ }
147
+ setAppInfo(appInfo) {
148
+ this.appInfo = appInfo;
149
+ this.appInfoSent = false;
150
+ this.sendAppInfo();
151
+ }
152
+ sendAppInfo() {
153
+ return __awaiter(this, void 0, void 0, function* () {
154
+ if (this.appInfo) {
155
+ this.logger.debug("Sending app info to Apitally Hub.");
156
+ const payload = Object.assign({ instance_uuid: this.instanceUuid, message_uuid: (0, crypto_1.randomUUID)() }, this.appInfo);
157
+ try {
158
+ yield this.axiosClient.post("/info", payload);
159
+ this.appInfoSent = true;
160
+ }
161
+ catch (error) {
162
+ if (error instanceof axios_1.AxiosError &&
163
+ error.response &&
164
+ error.response.status === 404 &&
165
+ error.response.data &&
166
+ typeof error.response.data === "string" &&
167
+ error.response.data.includes("Client ID")) {
168
+ this.logger.error(`Invalid Apitally client ID '${this.clientId}'.`);
169
+ this.stopSync();
170
+ }
171
+ else {
172
+ this.logger.debug(`Error while sending app info to Apitally Hub (${error.code}). Will retry.`, { error });
173
+ }
174
+ }
175
+ }
176
+ });
177
+ }
178
+ sendRequestsData() {
179
+ return __awaiter(this, void 0, void 0, function* () {
180
+ this.logger.debug("Sending requests data to Apitally Hub.");
181
+ const newPayload = {
182
+ time_offset: 0,
183
+ instance_uuid: this.instanceUuid,
184
+ message_uuid: (0, crypto_1.randomUUID)(),
185
+ requests: this.requestLogger.getAndResetRequests(),
186
+ validation_errors: this.validationErrorLogger.getAndResetValidationErrors(),
187
+ api_key_usage: this.keyRegistry.getAndResetUsageCounts(),
188
+ };
189
+ this.requestsDataQueue.push([Date.now(), newPayload]);
190
+ const failedItems = [];
191
+ while (this.requestsDataQueue.length > 0) {
192
+ const queueItem = this.requestsDataQueue.shift();
193
+ if (queueItem) {
194
+ const [time, payload] = queueItem;
195
+ try {
196
+ const timeOffset = Date.now() - time;
197
+ if (timeOffset <= MAX_QUEUE_TIME) {
198
+ payload.time_offset = timeOffset / 1000.0; // In seconds
199
+ yield this.axiosClient.post("/requests", payload);
200
+ }
201
+ }
202
+ catch (error) {
203
+ this.logger.debug(`Error while sending requests data to Apitally Hub (${error.code}). Will retry.`, { error });
204
+ failedItems.push(queueItem);
205
+ }
206
+ }
207
+ }
208
+ this.requestsDataQueue = failedItems;
209
+ });
210
+ }
211
+ getKeys() {
212
+ return __awaiter(this, void 0, void 0, function* () {
213
+ try {
214
+ this.logger.debug("Getting API keys from Apitally Hub.");
215
+ const response = yield this.axiosClient.get("/keys");
216
+ this.updateKeyRegistry(response.data);
217
+ this.keysUpdated = Date.now();
218
+ }
219
+ catch (error) {
220
+ this.logger.debug(`Error while getting API keys from Apitally Hub (${error.code}). Will retry.`, { error });
221
+ const now = Date.now();
222
+ if (!this.keyRegistry.salt) {
223
+ // Exit because application won't be able to authenticate requests
224
+ this.logger.error("Initial Apitally API key sync failed.");
225
+ process.exit(1);
226
+ }
227
+ else if ((this.keysUpdated && now - this.keysUpdated > MAX_QUEUE_TIME) ||
228
+ (!this.keysUpdated && now - this.startedAt > MAX_QUEUE_TIME)) {
229
+ this.logger.warn("Apitally API key sync has been failing for more than 1 hour.");
230
+ }
231
+ }
232
+ });
233
+ }
234
+ updateKeyRegistry(data, cache = true) {
235
+ this.keyRegistry.salt = data.salt || null;
236
+ this.keyRegistry.update(data.keys || {});
237
+ if (cache && this.keyCache) {
238
+ this.keyCache.store(JSON.stringify(data));
239
+ }
240
+ }
241
+ }
242
+ exports.ApitallyClient = ApitallyClient;
243
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/common/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { KeyCacheBase } from "./keyRegistry";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/common/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KeyCacheBase = void 0;
4
+ var keyRegistry_1 = require("./keyRegistry");
5
+ Object.defineProperty(exports, "KeyCacheBase", { enumerable: true, get: function () { return keyRegistry_1.KeyCacheBase; } });
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/common/index.ts"],"names":[],"mappings":";;;AAAA,6CAA6C;AAApC,2GAAA,YAAY,OAAA"}
@@ -0,0 +1,29 @@
1
+ export declare class KeyInfo {
2
+ readonly keyId: number;
3
+ readonly apiKeyId: number;
4
+ readonly name: string;
5
+ readonly scopes: string[];
6
+ readonly expiresAt: Date | null;
7
+ constructor(keyId: number, apiKeyId: number, name?: string, scopes?: string[], expiresInSeconds?: number | null);
8
+ get isExpired(): boolean;
9
+ hasScopes(scopes: string | string[]): boolean;
10
+ }
11
+ export declare class KeyRegistry {
12
+ salt: string | null;
13
+ private keys;
14
+ private usageCounts;
15
+ constructor();
16
+ get(apiKey: string): Promise<KeyInfo | null>;
17
+ private hashApiKey;
18
+ update(keys: Record<string, any>): void;
19
+ getAndResetUsageCounts(): Record<number, number>;
20
+ }
21
+ export declare abstract class KeyCacheBase {
22
+ private clientId;
23
+ private env;
24
+ constructor(clientId: string, env: string);
25
+ get cacheKey(): string;
26
+ abstract store(data: string): void;
27
+ abstract retrieve(): string | null;
28
+ }
29
+ //# sourceMappingURL=keyRegistry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyRegistry.d.ts","sourceRoot":"","sources":["../../src/common/keyRegistry.ts"],"names":[],"mappings":"AAEA,qBAAa,OAAO;IAClB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,IAAI,GAAG,IAAI,CAAC;gBAG9B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,MAAW,EACjB,MAAM,GAAE,MAAM,EAAO,EACrB,gBAAgB,GAAE,MAAM,GAAG,IAAW;IAYxC,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO;CAM9C;AAED,qBAAa,WAAW;IACf,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,CAAC,IAAI,CAAuB;IACnC,OAAO,CAAC,WAAW,CAAsB;;IAQ5B,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;YAa3C,UAAU;IAkBjB,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAgBvC,sBAAsB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;CAKxD;AAED,8BAAsB,YAAY;IAChC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,GAAG,CAAS;gBAER,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;IAKzC,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAElC,QAAQ,CAAC,QAAQ,IAAI,MAAM,GAAG,IAAI;CACnC"}
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.KeyCacheBase = exports.KeyRegistry = exports.KeyInfo = void 0;
13
+ const crypto_1 = require("crypto");
14
+ class KeyInfo {
15
+ constructor(keyId, apiKeyId, name = "", scopes = [], expiresInSeconds = null) {
16
+ this.keyId = keyId;
17
+ this.apiKeyId = apiKeyId;
18
+ this.name = name;
19
+ this.scopes = scopes;
20
+ this.expiresAt =
21
+ expiresInSeconds !== null && expiresInSeconds !== undefined
22
+ ? new Date(Date.now() + expiresInSeconds * 1000)
23
+ : null;
24
+ }
25
+ get isExpired() {
26
+ return this.expiresAt !== null && this.expiresAt < new Date();
27
+ }
28
+ hasScopes(scopes) {
29
+ if (typeof scopes === "string") {
30
+ scopes = [scopes];
31
+ }
32
+ return scopes.every((scope) => this.scopes.includes(scope));
33
+ }
34
+ }
35
+ exports.KeyInfo = KeyInfo;
36
+ class KeyRegistry {
37
+ constructor() {
38
+ this.salt = null;
39
+ this.keys = new Map();
40
+ this.usageCounts = new Map();
41
+ }
42
+ get(apiKey) {
43
+ return __awaiter(this, void 0, void 0, function* () {
44
+ const hash = yield this.hashApiKey(apiKey.trim());
45
+ const key = this.keys.get(hash);
46
+ if (!key || key.isExpired) {
47
+ return null;
48
+ }
49
+ this.usageCounts.set(key.apiKeyId, (this.usageCounts.get(key.apiKeyId) || 0) + 1);
50
+ return key;
51
+ });
52
+ }
53
+ hashApiKey(apiKey) {
54
+ return __awaiter(this, void 0, void 0, function* () {
55
+ return new Promise((resolve, reject) => {
56
+ if (!this.salt) {
57
+ throw new Error("Apitally API keys not initialized");
58
+ }
59
+ (0, crypto_1.scrypt)(apiKey, Buffer.from(this.salt, "hex"), 32, { N: 256, r: 4, p: 1 }, (err, derivedKey) => {
60
+ if (err)
61
+ reject(err);
62
+ resolve(derivedKey.toString("hex"));
63
+ });
64
+ });
65
+ });
66
+ }
67
+ update(keys) {
68
+ this.keys.clear();
69
+ for (const [hash, data] of Object.entries(keys)) {
70
+ this.keys.set(hash, new KeyInfo(data["key_id"], data["api_key_id"], data["name"], data["scopes"], data["expires_in_seconds"]));
71
+ }
72
+ }
73
+ getAndResetUsageCounts() {
74
+ const data = Object.fromEntries(this.usageCounts);
75
+ this.usageCounts.clear();
76
+ return data;
77
+ }
78
+ }
79
+ exports.KeyRegistry = KeyRegistry;
80
+ class KeyCacheBase {
81
+ constructor(clientId, env) {
82
+ this.clientId = clientId;
83
+ this.env = env;
84
+ }
85
+ get cacheKey() {
86
+ return `apitally:keys:${this.clientId}:${this.env}`;
87
+ }
88
+ }
89
+ exports.KeyCacheBase = KeyCacheBase;
90
+ //# sourceMappingURL=keyRegistry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyRegistry.js","sourceRoot":"","sources":["../../src/common/keyRegistry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export interface Logger {
2
+ debug: (message: string, meta?: object) => void;
3
+ info: (message: string, meta?: object) => void;
4
+ warn: (message: string, meta?: object) => void;
5
+ error: (message: string, meta?: object) => void;
6
+ }
7
+ export declare const getLogger: () => import("winston").Logger;
8
+ //# sourceMappingURL=logging.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logging.d.ts","sourceRoot":"","sources":["../../src/common/logging.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACjD;AAED,eAAO,MAAM,SAAS,gCAYrB,CAAC"}
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getLogger = void 0;
4
+ const winston_1 = require("winston");
5
+ const getLogger = () => {
6
+ return (0, winston_1.createLogger)({
7
+ level: process.env.APITALLY_DEBUG ? "debug" : "warn",
8
+ format: winston_1.format.combine(winston_1.format.colorize(), winston_1.format.timestamp(), winston_1.format.printf((info) => `${info.timestamp} ${info.level}: ${info.message}`)),
9
+ transports: [new winston_1.transports.Console()],
10
+ });
11
+ };
12
+ exports.getLogger = getLogger;
13
+ //# sourceMappingURL=logging.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logging.js","sourceRoot":"","sources":["../../src/common/logging.ts"],"names":[],"mappings":";;;AAAA,qCAA2D;AASpD,MAAM,SAAS,GAAG,GAAG,EAAE;IAC5B,OAAO,IAAA,sBAAY,EAAC;QAClB,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM;QACpD,MAAM,EAAE,gBAAM,CAAC,OAAO,CACpB,gBAAM,CAAC,QAAQ,EAAE,EACjB,gBAAM,CAAC,SAAS,EAAE,EAClB,gBAAM,CAAC,MAAM,CACX,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,OAAO,EAAE,CAC7D,CACF;QACD,UAAU,EAAE,CAAC,IAAI,oBAAU,CAAC,OAAO,EAAE,CAAC;KACvC,CAAC,CAAC;AACL,CAAC,CAAC;AAZW,QAAA,SAAS,aAYpB"}
@@ -0,0 +1,10 @@
1
+ import { RequestInfo, RequestsItem } from "./types";
2
+ export default class RequestLogger {
3
+ private requestCounts;
4
+ private responseTimes;
5
+ constructor();
6
+ private getKey;
7
+ logRequest(requestInfo: RequestInfo): void;
8
+ getAndResetRequests(): Array<RequestsItem>;
9
+ }
10
+ //# sourceMappingURL=requestLogger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requestLogger.d.ts","sourceRoot":"","sources":["../../src/common/requestLogger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEpD,MAAM,CAAC,OAAO,OAAO,aAAa;IAChC,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,aAAa,CAAmC;;IAOxD,OAAO,CAAC,MAAM;IASd,UAAU,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI;IAkB1C,mBAAmB,IAAI,KAAK,CAAC,YAAY,CAAC;CAsB3C"}