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.
- package/LICENSE +21 -0
- package/README.md +136 -0
- package/dist/common/client.d.ts +37 -0
- package/dist/common/client.d.ts.map +1 -0
- package/dist/common/client.js +243 -0
- package/dist/common/client.js.map +1 -0
- package/dist/common/index.d.ts +2 -0
- package/dist/common/index.d.ts.map +1 -0
- package/dist/common/index.js +6 -0
- package/dist/common/index.js.map +1 -0
- package/dist/common/keyRegistry.d.ts +29 -0
- package/dist/common/keyRegistry.d.ts.map +1 -0
- package/dist/common/keyRegistry.js +90 -0
- package/dist/common/keyRegistry.js.map +1 -0
- package/dist/common/logging.d.ts +8 -0
- package/dist/common/logging.d.ts.map +1 -0
- package/dist/common/logging.js +13 -0
- package/dist/common/logging.js.map +1 -0
- package/dist/common/requestLogger.d.ts +10 -0
- package/dist/common/requestLogger.d.ts.map +1 -0
- package/dist/common/requestLogger.js +49 -0
- package/dist/common/requestLogger.js.map +1 -0
- package/dist/common/types.d.ts +56 -0
- package/dist/common/types.d.ts.map +1 -0
- package/dist/common/types.js +3 -0
- package/dist/common/types.js.map +1 -0
- package/dist/common/utils.d.ts +4 -0
- package/dist/common/utils.d.ts.map +1 -0
- package/dist/common/utils.js +23 -0
- package/dist/common/utils.js.map +1 -0
- package/dist/common/validationErrorLogger.d.ts +9 -0
- package/dist/common/validationErrorLogger.d.ts.map +1 -0
- package/dist/common/validationErrorLogger.js +40 -0
- package/dist/common/validationErrorLogger.js.map +1 -0
- package/dist/express/auth.d.ts +6 -0
- package/dist/express/auth.d.ts.map +1 -0
- package/dist/express/auth.js +66 -0
- package/dist/express/auth.js.map +1 -0
- package/dist/express/index.d.ts +3 -0
- package/dist/express/index.d.ts.map +1 -0
- package/dist/express/index.js +8 -0
- package/dist/express/index.js.map +1 -0
- package/dist/express/listEndpoints.d.ts +3 -0
- package/dist/express/listEndpoints.d.ts.map +1 -0
- package/dist/express/listEndpoints.js +166 -0
- package/dist/express/listEndpoints.js.map +1 -0
- package/dist/express/middleware.d.ts +4 -0
- package/dist/express/middleware.d.ts.map +1 -0
- package/dist/express/middleware.js +164 -0
- package/dist/express/middleware.js.map +1 -0
- package/dist/fastify/auth.d.ts +6 -0
- package/dist/fastify/auth.d.ts.map +1 -0
- package/dist/fastify/auth.js +66 -0
- package/dist/fastify/auth.js.map +1 -0
- package/dist/fastify/index.d.ts +3 -0
- package/dist/fastify/index.d.ts.map +1 -0
- package/dist/fastify/index.js +11 -0
- package/dist/fastify/index.js.map +1 -0
- package/dist/fastify/plugin.d.ts +16 -0
- package/dist/fastify/plugin.d.ts.map +1 -0
- package/dist/fastify/plugin.js +122 -0
- package/dist/fastify/plugin.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/koa/auth.d.ts +6 -0
- package/dist/koa/auth.d.ts.map +1 -0
- package/dist/koa/auth.js +67 -0
- package/dist/koa/auth.js.map +1 -0
- package/dist/koa/index.d.ts +3 -0
- package/dist/koa/index.d.ts.map +1 -0
- package/dist/koa/index.js +8 -0
- package/dist/koa/index.js.map +1 -0
- package/dist/koa/middleware.d.ts +4 -0
- package/dist/koa/middleware.d.ts.map +1 -0
- package/dist/koa/middleware.js +108 -0
- package/dist/koa/middleware.js.map +1 -0
- package/dist/nestjs/auth.d.ts +10 -0
- package/dist/nestjs/auth.d.ts.map +1 -0
- package/dist/nestjs/auth.js +84 -0
- package/dist/nestjs/auth.js.map +1 -0
- package/dist/nestjs/index.d.ts +3 -0
- package/dist/nestjs/index.d.ts.map +1 -0
- package/dist/nestjs/index.js +9 -0
- package/dist/nestjs/index.js.map +1 -0
- 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
|
+

|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# Apitally client library for Node.js
|
|
20
|
+
|
|
21
|
+
[](https://github.com/apitally/nodejs-client/actions)
|
|
22
|
+
[](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 @@
|
|
|
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"}
|