├── .eslintignore ├── .eslintrc.json ├── .gitignore ├── LICENSE ├── README.md ├── examples └── index.ts ├── index.ts ├── jest.config.js ├── lib ├── access.ts ├── config.ts ├── configInterface.ts ├── config_change.ts ├── config_change_event.ts ├── config_manager.ts ├── config_service.ts ├── constants.ts ├── json_config.ts ├── plain_config.ts ├── properties_config.ts ├── request.ts └── types.ts ├── package.json ├── pnpm-lock.yaml ├── test ├── access.test.ts ├── config_change.test.ts ├── config_change_event.test.ts ├── config_manager.test.ts ├── json_config.test.ts ├── plain_config.test.ts ├── properties_config.test.ts └── request.test.ts └── tsconfig.json /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/* 2 | coverage/* 3 | node_modules/* -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "node": true, 4 | "es6": true 5 | }, 6 | "extends": [ 7 | "eslint:recommended", 8 | "plugin:@typescript-eslint/eslint-recommended", 9 | "plugin:@typescript-eslint/recommended" 10 | ], 11 | "globals": { 12 | "Atomics": "readonly", 13 | "SharedArrayBuffer": "readonly" 14 | }, 15 | "parser": "@typescript-eslint/parser", 16 | "parserOptions": { 17 | "ecmaVersion": 2018, 18 | "sourceType": "module" 19 | }, 20 | "plugins": [ 21 | "@typescript-eslint" 22 | ], 23 | "rules": { 24 | "indent": [ 25 | "error", 26 | 2 27 | ], 28 | "linebreak-style": [ 29 | "error", 30 | "unix" 31 | ], 32 | "quotes": [ 33 | "error", 34 | "single" 35 | ], 36 | "semi": [ 37 | "error", 38 | "always" 39 | ], 40 | "eol-last": [ 41 | "error", 42 | "always" 43 | ], 44 | "@typescript-eslint/no-explicit-any": 0 45 | } 46 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | .vscode/* 3 | coverage/* 4 | dist/* 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 zhangxh1023 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # apollo-node-client 2 | Node.js Client for [Apollo](https://github.com/ctripcorp/apollo) 3 | 4 | ## install 5 | ```bash 6 | $ npm install apollo-node-client --save 7 | ``` 8 | 9 | ## Examples 10 | [examples](https://github.com/zhangxh1023/apollo-node-client/tree/master/examples) 11 | 12 | ## Usage 13 | 14 | ### 实例化 `ConfigService` 15 | 16 | ```javascript 17 | const { ConfigService } = require('apollo-node-client'); 18 | 19 | const service = new ConfigService({ 20 | configServerUrl: 'http://localhost:8080/', 21 | appId: 'SampleApp', 22 | clusterName: 'default', 23 | secret: 'cf86d564d10a46d4a5989dfdeed3a3a2' 24 | }); 25 | ``` 26 | 27 | ### 获取默认 `namespace` 的配置(`application`) 28 | ```javascript 29 | const config = await service.getAppConfig(); 30 | config.getAllConfig(); // Map(1) { 'mysql.user' => 'root' } 31 | console.log(config.getProperty('mysql.user')); // root 32 | console.log(config.getProperty('mysql.missing', 'default')); // default 33 | ``` 34 | 35 | ### 获取 `properties` 格式 `namespace` 的配置 36 | ```javascript 37 | const config = await service.getConfig('application'); 38 | config.getAllConfig(); // Map(1) { 'mysql.user' => 'root' } 39 | console.log(config.getProperty('mysql.user')); // root 40 | console.log(config.getProperty('mysql.missing', 'default')); // default 41 | ``` 42 | 43 | ### 获取 `json` 格式 `namespace` 的配置 44 | ```javascript 45 | const config = await service.getConfig('config.json'); 46 | config.getAllConfig(); // { mysql: { user: 'root' } } 47 | console.log(config.getProperty('mysql.user')); // root 48 | console.log(config.getProperty('mysql.missing', 'default')); // default 49 | ``` 50 | 51 | ### 获取 `xml/yml/yaml/txt` 格式 `namespace` 的配置 52 | ```javascript 53 | const config = await service.getConfig('config.txt'); 54 | config.getAllConfig(); // txt config 55 | console.log(config.getProperty('', 'default')); // txt config 56 | console.log(config.getProperty()); // txt config 57 | ``` 58 | 59 | ### 指定灰度发布的服务 `ip` 60 | ```javascript 61 | const config = await service.getConfig('application', '192.168.3.4'); 62 | config.getAllConfig(); // Map(1) { 'mysql.user' => 'root' } 63 | console.log(config.getProperty('mysql.user')); // root 64 | console.log(config.getProperty('mysql.missing', 'default')); // default 65 | ``` 66 | 67 | ### 监听配置变化事件 68 | ```javascript 69 | config.addChangeListener((changeEvent) => { 70 | for (const key of changeEvent.changedKeys()) { 71 | const change = changeEvent.getChange(key); 72 | if (change) { 73 | console.log(`namespace: ${change.getNamespace()}, 74 | changeType: ${change.getChangeType()}, 75 | propertyName: ${change.getPropertyName()}, 76 | oldValue: ${change.getOldValue()}, 77 | newValue: ${change.getNewValue()}`); 78 | } 79 | } 80 | }); 81 | ``` 82 | 83 | ## API 84 | 85 | ### Class: ConfigService 86 | 87 | - new ConfigService( options ) 88 | - `options` _\_ 89 | - `configServerUrl` _\_ Apollo 配置服务的地址 90 | - `appId` _\_ 应用的 appId 91 | - `[clusterName]` _\_ 集群名 92 | - `[secret]` _\_ 服务端密钥 access key 93 | 94 | - Returns: _ConfigService_ 95 | 96 | - configService.getAppConfig( [ ip ] ) 97 | - `[ip]` _\_ 应用部署的机器ip 98 | 99 | - Returns: _Promise\_ 默认的 `namespace` 为 `application` 100 | 101 | - configService.getConfig( namespaceName, [ ip ] ) 102 | - `namespaceName` _\_ Namespace的名字,以后缀名判断是什么类型格式的 `Config`。如果没有后缀名,默认为 `properties`,目前支持 `.json`,`.properties`,`.xml`,`.yml`, `.yaml`,`.txt` 103 | - `[ip]` _\_ 应用部署的机器ip 104 | 105 | - Returns: _Promise\_ 106 | 107 | --- 108 | 109 | ### Class: PropertiesConfig 110 | 111 | - propertiesConfig.getAllConfig() 112 | 113 | - Returns: _Map\_ 114 | 115 | - propertiesConfig.getProperty( key, [ defaultValue ] ) 116 | - `key` _\_ 要获取的配置的 `key` 117 | - `[defaultValue]` _\_ 默认值,当传入的 `key` 不存在时,会返回 `defaultValue` 118 | 119 | - Returns: _undefined | string_ 120 | 121 | - propertiesConfig.addChangeListener( handle ) 122 | - `handle` _( changeEvent: ConfigChangeEvent\ ) => void_ 监听配置变化事件的回调函数 123 | 124 | - Returns: _void_ 125 | 126 | --- 127 | 128 | ### Class: JSONConfig 129 | 130 | - jsonConfig.getAllConfig() 131 | 132 | - Returns: _JSONValueType_ 133 | 134 | - jsonConfig.getProperty( key, [ defaultValue ] ) 135 | - `key` _\_ 要获取的配置的 `key` 136 | - `[defaultValue]` _\_ 默认值,当传入的 `key` 不存在时,会返回 `defaultValue` 137 | 138 | - Returns: _undefined | JSONValueType_ 139 | 140 | - jsonConfig.addChangeListener( handle ) 141 | - `handle` _( changeEvent: ConfigChangeEvent\ ) => void_ 监听配置变化事件的回调函数 142 | 143 | - Returns: _void_ 144 | 145 | --- 146 | 147 | ### Class: PlainConfig 148 | 149 | - plainConfig.getAllConfig() 150 | 151 | - Returns: _string_ 152 | 153 | - plainConfig.getProperty( key, [ defaultValue ] ) 154 | - `key` _\_ 兼容其他类型的 _Config_,不做校验,传入任意 `key` 都会返回整个配置文本内容 155 | - `[defaultValue]` _\_ 默认值,当配置不存在时,会返回 `defaultValue` 156 | 157 | - Returns: _undefined | string_ 158 | 159 | --- 160 | 161 | ### Class: ConfigChangeEvent 162 | 163 | - configChangeEvent.getNamespace() 164 | 165 | - Returns: _string_ 166 | 167 | - configChangeEvent.changedKeys() 168 | 169 | - Returns: _string[]_ 170 | 171 | - configChangeEvent.getChange() 172 | 173 | - Returns: _undefined | ConfigChange\_ 174 | 175 | --- 176 | 177 | ### Class: ConfigChange\ 178 | 179 | - configChange.getNamespace() 180 | 181 | - Returns: _string_ 182 | 183 | - configChange.getPropertyName() 184 | 185 | - Returns: _string_ 186 | 187 | - configChange.getOldValues() 188 | 189 | - Returns: _undefined | T_ 190 | 191 | - configChange.getNewValue() 192 | 193 | - Returns: _undefined | T_ 194 | 195 | - configChange.getChangeType() 196 | 197 | - Returns: _PropertyChangeType_ 198 | 199 | --- 200 | 201 | ### Enum: PropertyChangeType 202 | 203 | - propertyChangeType.ADDED 204 | 205 | - propertyChangeType.MODIFIED 206 | 207 | - propertyChangeType.DELETED 208 | 209 | --- 210 | 211 | ## Contributing 212 | Contributions are always welcome! 213 | 214 | ## License 215 | [MIT](https://github.com/zhangxh1023/apollo-node-client/blob/master/LICENSE) 216 | -------------------------------------------------------------------------------- /examples/index.ts: -------------------------------------------------------------------------------- 1 | import { ConfigService } from '..'; 2 | import { ConfigChangeEvent } from '..'; 3 | 4 | const service = new ConfigService({ 5 | configServerUrl: 'http://81.68.181.139:8080/', 6 | appId: 'apolloNodeClient', 7 | clusterName: 'default', 8 | secret: '16b63e04c38f4bd2b10dadb3ad39e356' 9 | }); 10 | 11 | async function main(): Promise { 12 | // const appConfig = await service.getAppConfig(); 13 | // const jsonConfig = await service.getConfig('first.json'); 14 | // const txtConfig = await service.getConfig('first.txt'); 15 | const [ 16 | appConfig, 17 | jsonConfig, 18 | txtConfig 19 | ] = await Promise.all([ 20 | service.getAppConfig(), 21 | service.getConfig('first.json'), 22 | service.getConfig('first.txt') 23 | ]); 24 | 25 | appConfig.addChangeListener((changeEvent: ConfigChangeEvent) => { 26 | for (const key of changeEvent.changedKeys()) { 27 | const change = changeEvent.getChange(key); 28 | if (change) { 29 | console.log(`namespace: ${change.getNamespace()}, 30 | changeType: ${change.getChangeType()}, 31 | propertyName: ${change.getPropertyName()}, 32 | oldValue: ${change.getOldValue()}, 33 | newValue: ${change.getNewValue()}`); 34 | } 35 | } 36 | }); 37 | 38 | jsonConfig.addChangeListener((changeEvent: ConfigChangeEvent) => { 39 | for (const key of changeEvent.changedKeys()) { 40 | const change = changeEvent.getChange(key); 41 | if (change) { 42 | console.log(`namespace: ${change.getNamespace()}, 43 | changeType: ${change.getChangeType()}, 44 | propertyName: ${change.getPropertyName()}, 45 | oldValue: ${JSON.stringify(change.getOldValue())}, 46 | newValue: ${JSON.stringify(change.getNewValue())}`); 47 | } 48 | } 49 | }); 50 | 51 | txtConfig.addChangeListener((changeEvent: ConfigChangeEvent) => { 52 | for (const key of changeEvent.changedKeys()) { 53 | const change = changeEvent.getChange(key); 54 | if (change) { 55 | console.log(`namespace: ${change.getNamespace()}, 56 | changeType: ${change.getChangeType()}, 57 | propertyName: ${change.getPropertyName()}, 58 | oldValue: ${change.getOldValue()}, 59 | newValue: ${change.getNewValue()}`); 60 | } 61 | } 62 | }); 63 | 64 | console.log(appConfig.getAllConfig()); 65 | console.log(appConfig.getProperty('mysql.user')); 66 | console.log(jsonConfig.getAllConfig()); 67 | console.log(jsonConfig.getProperty('mysql.user')); 68 | console.log(txtConfig.getAllConfig()); 69 | console.log(txtConfig.getProperty('mysql.user')); 70 | } 71 | 72 | main(); 73 | -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/access'; 2 | export * from './lib/config_change_event'; 3 | export * from './lib/config_change'; 4 | export * from './lib/config_manager'; 5 | export * from './lib/config_service'; 6 | export * from './lib/config'; 7 | export * from './lib/configInterface'; 8 | export * from './lib/constants'; 9 | export * from './lib/json_config'; 10 | export * from './lib/plain_config'; 11 | export * from './lib/properties_config'; 12 | export * from './lib/request'; 13 | export * from './lib/types'; 14 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'node', 4 | modulePathIgnorePatterns: [ 5 | 'node_modules', 6 | 'dist' 7 | ] 8 | }; 9 | -------------------------------------------------------------------------------- /lib/access.ts: -------------------------------------------------------------------------------- 1 | import * as crypto from 'crypto'; 2 | import { URL } from 'url'; 3 | 4 | export type AuthHeader = { 5 | Authorization: string; 6 | Timestamp: string; 7 | }; 8 | 9 | export class Access { 10 | 11 | public static DELIMITER = '\n'; 12 | 13 | public static createAccessHeader(appId: string, url: string, secret: string): AuthHeader { 14 | return this.createAccessHeaderByTimestamp(new Date().getTime(), appId, url, secret); 15 | } 16 | 17 | private static createAccessHeaderByTimestamp(timestamp: number, appId: string, url: string, secret: string): AuthHeader { 18 | const accessHeader = { 19 | Authorization: '', 20 | Timestamp: timestamp.toString(), 21 | }; 22 | const sign = this.signature(accessHeader.Timestamp, this.url2PathWithQuery(url), secret); 23 | accessHeader.Authorization = `Apollo ${appId}:${sign}`; 24 | return accessHeader; 25 | } 26 | 27 | private static signature(timestamp: string, pathWithQuery: string, secret: string): string { 28 | const hash = crypto.createHmac('sha1', secret); 29 | hash.update(timestamp + this.DELIMITER + pathWithQuery); 30 | return hash.digest('base64'); 31 | } 32 | 33 | private static url2PathWithQuery(urlString: string): string { 34 | const url = new URL(urlString); 35 | return url.pathname + url.search; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/config.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from 'stream'; 2 | import { Access, AuthHeader } from './access'; 3 | import { NOTIFICATION_ID_PLACEHOLDER } from './constants'; 4 | import { ConfigOptions } from './types'; 5 | import { Request } from './request'; 6 | 7 | export abstract class Config extends EventEmitter { 8 | 9 | private releaseKey = ''; 10 | 11 | private notificationId = NOTIFICATION_ID_PLACEHOLDER; 12 | 13 | constructor(private readonly options: ConfigOptions, private readonly ip?: string) { 14 | super(); 15 | this.options = options; 16 | } 17 | 18 | public getNamespaceName(): string { 19 | return this.options.namespaceName; 20 | } 21 | 22 | public getNotificationId(): number { 23 | return this.notificationId; 24 | } 25 | 26 | public setNotificationId(newNotificationId: number): void { 27 | this.notificationId = newNotificationId; 28 | } 29 | 30 | protected getConfigOptions(): ConfigOptions { 31 | return this.options; 32 | } 33 | 34 | protected getAppId(): string { 35 | return this.options.appId; 36 | } 37 | 38 | protected getSecret(): undefined | string { 39 | return this.options.secret; 40 | } 41 | 42 | protected getReleaseKey(): string { 43 | return this.releaseKey; 44 | } 45 | 46 | protected setReleaseKey(releaseKey: string): void { 47 | this.releaseKey = releaseKey; 48 | } 49 | 50 | protected getIp(): undefined | string { 51 | return this.ip; 52 | } 53 | 54 | public async loadAndUpdateConfig(): Promise { 55 | const url = Request.formatConfigUrl({ 56 | ...this.getConfigOptions(), 57 | releaseKey: this.getReleaseKey(), 58 | ip: this.getIp(), 59 | }); 60 | let headers: AuthHeader | undefined; 61 | const secret = this.getSecret(); 62 | if (secret) { 63 | headers = Access.createAccessHeader(this.getAppId(), url, secret); 64 | } 65 | return this._loadAndUpdateConfig(url, headers); 66 | } 67 | 68 | abstract _loadAndUpdateConfig(url: string, headers: AuthHeader | undefined): Promise 69 | } 70 | -------------------------------------------------------------------------------- /lib/configInterface.ts: -------------------------------------------------------------------------------- 1 | import { ConfigChangeEvent } from './config_change_event'; 2 | 3 | export interface ConfigInterface { 4 | 5 | getAllConfig(): unknown; 6 | 7 | getProperty(key: string, defaultValue?: unknown): unknown; 8 | 9 | getNamespaceName(): string; 10 | 11 | getNotificationId(): number; 12 | 13 | loadAndUpdateConfig(): Promise; 14 | 15 | addChangeListener(fn: (changeEvent: ConfigChangeEvent) => void): unknown; 16 | } 17 | -------------------------------------------------------------------------------- /lib/config_change.ts: -------------------------------------------------------------------------------- 1 | import { PropertyChangeType } from './constants'; 2 | 3 | 4 | export class ConfigChange { 5 | constructor( 6 | private readonly namespaceName: string, 7 | private readonly propertyName: string, 8 | private readonly oldValue: undefined | T, 9 | private readonly newValue: undefined | T, 10 | private readonly changeType: PropertyChangeType, 11 | ) { 12 | this.namespaceName = namespaceName; 13 | this.propertyName = propertyName; 14 | this.oldValue = oldValue; 15 | this.newValue = newValue; 16 | this.changeType = changeType; 17 | } 18 | 19 | public getNamespace(): string { 20 | return this.namespaceName; 21 | } 22 | 23 | public getPropertyName(): string { 24 | return this.propertyName; 25 | } 26 | 27 | public getOldValue(): undefined | T { 28 | return this.oldValue; 29 | } 30 | 31 | public getNewValue(): undefined | T { 32 | return this.newValue; 33 | } 34 | 35 | public getChangeType(): PropertyChangeType { 36 | return this.changeType; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /lib/config_change_event.ts: -------------------------------------------------------------------------------- 1 | import { ConfigChange } from './config_change'; 2 | 3 | export class ConfigChangeEvent { 4 | constructor( 5 | private readonly namespaceName: string, 6 | private readonly configChanges: Map>, 7 | ) { 8 | this.namespaceName = namespaceName; 9 | this.configChanges = configChanges; 10 | } 11 | 12 | public getNamespace(): string { 13 | return this.namespaceName; 14 | } 15 | 16 | public changedKeys(): string[] { 17 | return Array.from(this.configChanges.keys()); 18 | } 19 | 20 | public getChange(key: string): undefined | ConfigChange { 21 | return this.configChanges.get(key); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /lib/config_manager.ts: -------------------------------------------------------------------------------- 1 | import { PropertiesConfig } from './properties_config'; 2 | import { CLUSTER_NAMESPACE_SEPARATOR, ConfigTypes } from './constants'; 3 | import { JSONConfig } from './json_config'; 4 | import { Access, AuthHeader } from './access'; 5 | import { Request } from './request'; 6 | import { PlainConfig } from './plain_config'; 7 | 8 | export type ConfigManagerOptions = { 9 | configServerUrl: string; 10 | appId: string; 11 | clusterName: string; 12 | secret?: string; 13 | }; 14 | 15 | type NamespacePair = { 16 | namespaceName: string; 17 | type: ConfigTypes; 18 | }; 19 | 20 | export class ConfigManager { 21 | 22 | private LONG_POLL_RETRY_TIME = 1000; 23 | 24 | private MAX_LONG_POLL_RETRY_TIME = 16000; 25 | 26 | private MIN_LONG_POLL_RETRY_TIME = 1000; 27 | 28 | private configsMap: Map = new Map(); 29 | 30 | private configsMapVersion = 0; 31 | 32 | constructor(private readonly options: ConfigManagerOptions) { 33 | this.options = options; 34 | } 35 | 36 | private getTypeByNamespaceName(namespaceName: string): NamespacePair { 37 | for (const key in ConfigTypes) { 38 | if (namespaceName.endsWith(`.${ConfigTypes[key]}`)) { 39 | return { 40 | namespaceName: ConfigTypes[key] === ConfigTypes.PROPERTIES ? 41 | namespaceName.substring( 42 | 0, 43 | namespaceName.length - ConfigTypes[key].length - 1 44 | ) : namespaceName, 45 | type: ConfigTypes[key] 46 | }; 47 | } 48 | } 49 | return { namespaceName, type: ConfigTypes.PROPERTIES }; 50 | } 51 | 52 | public async getConfig(namespaceName: string, ip?: string): Promise { 53 | const type = this.getTypeByNamespaceName(namespaceName); 54 | if (!type.namespaceName) { 55 | throw new Error('namespaceName can not be empty!'); 56 | } 57 | const mpKey = this.formatConfigsMapKey(type.namespaceName); 58 | let config = this.configsMap.get(mpKey); 59 | if (!config) { 60 | if (type.type == ConfigTypes.PROPERTIES) { 61 | config = new PropertiesConfig({ 62 | ...this.options, 63 | namespaceName: type.namespaceName, 64 | }, ip); 65 | } else if (type.type == ConfigTypes.JSON) { 66 | config = new JSONConfig({ 67 | ...this.options, 68 | namespaceName: type.namespaceName, 69 | }, ip); 70 | } else { 71 | config = new PlainConfig({ 72 | ...this.options, 73 | namespaceName: type.namespaceName, 74 | }, ip); 75 | } 76 | 77 | this.configsMapVersion = this.configsMapVersion % Number.MAX_SAFE_INTEGER + 1; 78 | const configsMapVersion = this.configsMapVersion; 79 | const key = this.formatConfigsMapKey(config.getNamespaceName()); 80 | this.configsMap.set(key, config); 81 | const singleMap = new Map(); 82 | singleMap.set(key, config); 83 | try { 84 | await this.updateConfigs(singleMap); 85 | } catch (error) { 86 | console.log('[apollo-node-client] %s - load notifications failed. - %s', new Date(), error); 87 | } 88 | setImmediate(async () => { 89 | await this.startLongPoll(configsMapVersion); 90 | }); 91 | } 92 | return config; 93 | } 94 | 95 | public removeConfig(namespaceName: string): void { 96 | const type = this.getTypeByNamespaceName(namespaceName); 97 | const mpKey = this.formatConfigsMapKey(type.namespaceName); 98 | this.configsMap.delete(mpKey); 99 | } 100 | 101 | private async updateConfigs(configsMap: Map): Promise { 102 | const url = Request.formatNotificationsUrl({ 103 | ...this.options, 104 | }, configsMap); 105 | let headers: undefined | AuthHeader; 106 | if (this.options.secret) { 107 | headers = Access.createAccessHeader(this.options.appId, url, this.options.secret); 108 | } 109 | const notification = await Request.fetchNotifications(url, headers); 110 | 111 | if (notification) { 112 | for (const item of notification) { 113 | const key = this.formatConfigsMapKey(item.namespaceName); 114 | const config = this.configsMap.get(key); 115 | if (config) { 116 | await config.loadAndUpdateConfig(); 117 | config.setNotificationId(item.notificationId); 118 | } 119 | } 120 | } 121 | // ignore no update 122 | } 123 | 124 | private async startLongPoll(configsMapVersion: number): Promise { 125 | if (configsMapVersion !== this.configsMapVersion) { 126 | return; 127 | } 128 | try { 129 | await this.updateConfigs(this.configsMap); 130 | this.LONG_POLL_RETRY_TIME = this.MIN_LONG_POLL_RETRY_TIME; 131 | } catch (error) { 132 | console.log('[apollo-node-client] %s - update configs failed, will retry in %s seconds. - %s', 133 | new Date(), this.LONG_POLL_RETRY_TIME / 1000, error); 134 | await this.sleep(this.LONG_POLL_RETRY_TIME); 135 | if (this.LONG_POLL_RETRY_TIME < this.MAX_LONG_POLL_RETRY_TIME) { 136 | this.LONG_POLL_RETRY_TIME *= 2; 137 | } 138 | } 139 | 140 | if (this.configsMap.size > 0) { 141 | setImmediate(() => { 142 | this.startLongPoll(configsMapVersion); 143 | }); 144 | } 145 | } 146 | 147 | private formatConfigsMapKey(namespaceName: string): string { 148 | return this.options.clusterName + CLUSTER_NAMESPACE_SEPARATOR + namespaceName; 149 | } 150 | 151 | private sleep(time = 2000): Promise { 152 | return new Promise(resolve => setTimeout(resolve, time)); 153 | } 154 | 155 | } 156 | -------------------------------------------------------------------------------- /lib/config_service.ts: -------------------------------------------------------------------------------- 1 | import { NAMESPACE_APPLICATION, CLUSTER_NAME_DEFAULT } from './constants'; 2 | import { ConfigManager } from './config_manager'; 3 | import { PropertiesConfig } from './properties_config'; 4 | import { JSONConfig } from './json_config'; 5 | import { PlainConfig } from './plain_config'; 6 | 7 | export class ConfigService { 8 | 9 | private readonly configManager: ConfigManager; 10 | 11 | constructor(private readonly options: { 12 | configServerUrl: string; 13 | appId: string; 14 | clusterName?: string; 15 | secret?: string; 16 | }) { 17 | this.options = options; 18 | this.options.clusterName = this.options.clusterName ? this.options.clusterName : CLUSTER_NAME_DEFAULT; 19 | this.configManager = new ConfigManager({ 20 | ...this.options, 21 | clusterName: this.options.clusterName, 22 | }); 23 | } 24 | 25 | /** 26 | * getAppConfig, default namespace name: `application` 27 | */ 28 | public async getAppConfig(ip? : string): Promise { 29 | const config = await this.getConfig(NAMESPACE_APPLICATION, ip); 30 | return config as PropertiesConfig; 31 | } 32 | 33 | /** 34 | * get Config by namespaceName 35 | */ 36 | public getConfig(namespaceName: string, ip?: string): Promise { 37 | return this.configManager.getConfig(namespaceName, ip); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/constants.ts: -------------------------------------------------------------------------------- 1 | export const NAMESPACE_APPLICATION = 'application'; 2 | 3 | export const CLUSTER_NAME_DEFAULT = 'default'; 4 | 5 | export const CLUSTER_NAMESPACE_SEPARATOR = '+'; 6 | 7 | export const APOLLO_CLUSTER_KEY = 'apollo.cluster'; 8 | 9 | export const APOLLO_META_KEY = 'apollo.meta'; 10 | 11 | export const CONFIG_FILE_CONTENT_KEY = 'content'; 12 | 13 | export const NO_APPID_PLACEHOLDER = 'ApolloNoAppIdPlaceHolder'; 14 | 15 | export const NOTIFICATION_ID_PLACEHOLDER = -1; 16 | 17 | export const CHANGE_EVENT_NAME = 'change'; 18 | 19 | export enum ConfigTypes { 20 | PROPERTIES = 'properties', 21 | XML = 'xml', 22 | JSON = 'json', 23 | YML = 'yml', 24 | YAML = 'yaml', 25 | TXT = 'txt', 26 | } 27 | 28 | export enum PropertyChangeType { 29 | ADDED = 'ADDED', 30 | MODIFIED = 'MODIFIED', 31 | DELETED = 'DELETED', 32 | } 33 | -------------------------------------------------------------------------------- /lib/json_config.ts: -------------------------------------------------------------------------------- 1 | import { AuthHeader } from './access'; 2 | import { Config } from './config'; 3 | import { ConfigInterface } from './configInterface'; 4 | import { ConfigChange } from './config_change'; 5 | import { ConfigChangeEvent } from './config_change_event'; 6 | import { CHANGE_EVENT_NAME, PropertyChangeType } from './constants'; 7 | import { Request } from './request'; 8 | import { ConfigContentType, ConfigOptions } from './types'; 9 | 10 | export type JSONBaseType = string | number | boolean | null; 11 | 12 | export type JSONArrayType = JSONBaseType[]; 13 | 14 | export type JSONType = { 15 | [key: string]: JSONBaseType | JSONArrayType | JSONType; 16 | } 17 | 18 | export type JSONValueType = JSONBaseType | JSONArrayType | JSONType; 19 | 20 | export class JSONConfig extends Config implements ConfigInterface { 21 | 22 | private configs: JSONValueType = Object.create(null); 23 | 24 | constructor(options: ConfigOptions, ip?: string) { 25 | super(options, ip); 26 | } 27 | 28 | public getProperty(key: string, defaultValue?: JSONValueType): undefined | JSONValueType { 29 | return this.getPropertyByJSONAndKey(this.configs, key, defaultValue); 30 | } 31 | 32 | private getPropertyByJSONAndKey(configs: JSONValueType, 33 | key: string, defaultValue?: JSONValueType): undefined | JSONValueType { 34 | const keySlice = key ? key.split('.') : []; 35 | const value = this.getPropertyByJSONAndKeySlice(configs, keySlice); 36 | if (value !== undefined) { 37 | return value; 38 | } 39 | return defaultValue; 40 | } 41 | 42 | private getPropertyByJSONAndKeySlice(JSONValue: undefined | JSONValueType, keySlice: string[]): undefined | JSONValueType { 43 | if (keySlice.length == 0) { 44 | return JSONValue; 45 | } 46 | if (typeof JSONValue === 'string' 47 | || typeof JSONValue === 'number' 48 | || typeof JSONValue === 'boolean' 49 | || JSONValue === null 50 | || JSONValue === undefined) return; 51 | if (Array.isArray(JSONValue)) return; 52 | const key = keySlice.shift(); 53 | if (!key) return; 54 | return this.getPropertyByJSONAndKeySlice(JSONValue[key], keySlice); 55 | } 56 | 57 | public getAllConfig(): JSONValueType { 58 | return this.configs; 59 | } 60 | 61 | public addChangeListener(fn: (changeEvent: ConfigChangeEvent) => void): JSONConfig { 62 | this.addListener(CHANGE_EVENT_NAME, fn); 63 | return this; 64 | } 65 | 66 | public async _loadAndUpdateConfig(url: string, headers: AuthHeader | undefined): Promise { 67 | const loadConfigResp = await Request.fetchConfig(url, headers); 68 | if (loadConfigResp) { 69 | const content = loadConfigResp.configurations.content; 70 | if (content) { 71 | let newConfigs: JSONValueType; 72 | try { 73 | newConfigs = JSON.parse(content); 74 | } catch (error) { 75 | newConfigs = content; 76 | } 77 | const { added, deleted, changed } = this.diffJSON(this.configs, newConfigs); 78 | const configChangeEvent = this.updateConfigAndCreateChangeEvent(added, 79 | deleted, 80 | changed, 81 | newConfigs); 82 | if (configChangeEvent) { 83 | this.emit(CHANGE_EVENT_NAME, configChangeEvent); 84 | } 85 | } 86 | this.setReleaseKey(loadConfigResp.releaseKey); 87 | } 88 | } 89 | 90 | private diffJSON(oldJSONValue: JSONValueType, newJSONValue: JSONValueType, prefix = ''): { 91 | added: string[]; 92 | deleted: string[]; 93 | changed: string[]; 94 | } { 95 | const added: string[] = []; 96 | const deleted: string[] = []; 97 | const changed: string[] = []; 98 | 99 | if (typeof oldJSONValue === 'string' || 100 | typeof newJSONValue === 'string' || 101 | typeof oldJSONValue === 'number' || 102 | typeof newJSONValue === 'number' || 103 | typeof oldJSONValue === 'boolean' || 104 | typeof newJSONValue === 'boolean' || 105 | oldJSONValue === null || 106 | newJSONValue === null) { 107 | if (oldJSONValue !== newJSONValue) { 108 | changed.push(prefix); 109 | } 110 | return { 111 | added, 112 | deleted, 113 | changed, 114 | }; 115 | } 116 | 117 | if (Array.isArray(oldJSONValue) || Array.isArray(newJSONValue)) { 118 | if (JSON.stringify(oldJSONValue) !== JSON.stringify(newJSONValue)) { 119 | changed.push(prefix); 120 | } 121 | return { 122 | added, 123 | deleted, 124 | changed, 125 | }; 126 | } 127 | 128 | for (const key of Object.keys(oldJSONValue)) { 129 | if (!Object.prototype.hasOwnProperty.call(newJSONValue, key)) { 130 | const newKey = prefix ? prefix + '.' + key : key; 131 | deleted.push(newKey); 132 | } 133 | } 134 | 135 | for (const key of Object.keys(newJSONValue)) { 136 | const newKey = prefix ? prefix + '.' + key : key; 137 | if (!Object.prototype.hasOwnProperty.call(oldJSONValue, key)) { 138 | added.push(newKey); 139 | } else { 140 | // merge returned value 141 | const { 142 | added: _added, 143 | deleted: _deleted, 144 | changed: _changed 145 | } = this.diffJSON(oldJSONValue[key], newJSONValue[key], newKey); 146 | added.push(..._added); 147 | deleted.push(..._deleted); 148 | changed.push(..._changed); 149 | } 150 | } 151 | 152 | return { 153 | added, 154 | deleted, 155 | changed, 156 | }; 157 | } 158 | 159 | private updateConfigAndCreateChangeEvent(added: string[], deleted: string[], changed: string[], newConfigs: JSONValueType): undefined | ConfigChangeEvent { 160 | let configChangeEvent: undefined | ConfigChangeEvent; 161 | const configChanges: Map> = new Map(); 162 | for (const key of added) { 163 | const configChange = new ConfigChange(this.getNamespaceName(), 164 | key, 165 | undefined, 166 | this.getPropertyByJSONAndKey(newConfigs, key), 167 | PropertyChangeType.ADDED); 168 | configChanges.set(key, configChange); 169 | } 170 | for (const key of deleted) { 171 | const configChange = new ConfigChange(this.getNamespaceName(), 172 | key, 173 | this.getProperty(key), 174 | undefined, 175 | PropertyChangeType.DELETED); 176 | configChanges.set(key, configChange); 177 | } 178 | for (const key of changed) { 179 | const configChange = new ConfigChange(this.getNamespaceName(), 180 | key, 181 | this.getProperty(key), 182 | this.getPropertyByJSONAndKey(newConfigs, key), 183 | PropertyChangeType.MODIFIED); 184 | configChanges.set(key, configChange); 185 | } 186 | if (configChanges.size > 0) { 187 | configChangeEvent = new ConfigChangeEvent(this.getNamespaceName(), configChanges); 188 | } 189 | 190 | this.configs = newConfigs; 191 | return configChangeEvent; 192 | } 193 | 194 | } 195 | -------------------------------------------------------------------------------- /lib/plain_config.ts: -------------------------------------------------------------------------------- 1 | import { AuthHeader } from './access'; 2 | import { Config } from './config'; 3 | import { ConfigInterface } from './configInterface'; 4 | import { ConfigChangeEvent } from './config_change_event'; 5 | import { ConfigContentType, ConfigOptions } from './types'; 6 | import { Request } from './request'; 7 | import { CHANGE_EVENT_NAME, PropertyChangeType } from './constants'; 8 | import { ConfigChange } from './config_change'; 9 | 10 | export class PlainConfig extends Config implements ConfigInterface { 11 | 12 | private configs: undefined | string; 13 | 14 | constructor(options: ConfigOptions, ip?: string) { 15 | super(options, ip); 16 | } 17 | 18 | getAllConfig(): undefined | string { 19 | return this.configs; 20 | } 21 | 22 | public getProperty(_?: string, defaultValue?: string): undefined | string { 23 | if (this.configs !== undefined) { 24 | return this.configs; 25 | } 26 | return defaultValue; 27 | } 28 | 29 | public async _loadAndUpdateConfig(url: string, headers: AuthHeader | undefined): Promise { 30 | const loadConfigResp = await Request.fetchConfig(url, headers); 31 | if (loadConfigResp) { 32 | const configChangeEvent = this.updateConfigAndCreateChangeEvent(this.configs, loadConfigResp.configurations.content); 33 | if (configChangeEvent) { 34 | this.emit(CHANGE_EVENT_NAME, configChangeEvent); 35 | } 36 | this.setReleaseKey(loadConfigResp.releaseKey); 37 | } 38 | } 39 | 40 | public addChangeListener(fn: (changeEvent: ConfigChangeEvent) => void): PlainConfig { 41 | this.addListener(CHANGE_EVENT_NAME, fn); 42 | return this; 43 | } 44 | 45 | private updateConfigAndCreateChangeEvent(oldText: undefined | string, newText: string): undefined | ConfigChangeEvent { 46 | let changeType: PropertyChangeType; 47 | if (oldText === undefined) { 48 | changeType = PropertyChangeType.ADDED; 49 | } else if (newText === undefined) { 50 | changeType = PropertyChangeType.DELETED; 51 | } else { 52 | changeType = PropertyChangeType.MODIFIED; 53 | } 54 | const configChanges: Map> = new Map(); 55 | const configChange = new ConfigChange(this.getNamespaceName(), 56 | '', 57 | oldText, 58 | newText, 59 | changeType); 60 | configChanges.set('', configChange); 61 | this.configs = newText; 62 | return new ConfigChangeEvent(this.getNamespaceName(), configChanges); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /lib/properties_config.ts: -------------------------------------------------------------------------------- 1 | import { AuthHeader } from './access'; 2 | import { Config } from './config'; 3 | import { ConfigInterface } from './configInterface'; 4 | import { ConfigChange } from './config_change'; 5 | import { ConfigChangeEvent } from './config_change_event'; 6 | import { CHANGE_EVENT_NAME, PropertyChangeType } from './constants'; 7 | import { Request } from './request'; 8 | import { ConfigOptions } from './types'; 9 | 10 | export type KVConfigContentType = { 11 | [key: string]: string; 12 | }; 13 | 14 | export class PropertiesConfig extends Config implements ConfigInterface { 15 | 16 | private configs: Map = new Map(); 17 | 18 | constructor(options: ConfigOptions, ip?: string) { 19 | super(options, ip); 20 | } 21 | 22 | public getProperty(key: string, defaultValue?: string): undefined | string { 23 | const value = this.configs.get(key); 24 | if (value !== undefined) { 25 | return value; 26 | } 27 | return defaultValue; 28 | } 29 | 30 | public getAllConfig(): Map { 31 | return this.configs; 32 | } 33 | 34 | private setProperty(key: string, value: string): void { 35 | this.configs.set(key, value); 36 | } 37 | 38 | private deleteProperty(key: string): boolean { 39 | return this.configs.delete(key); 40 | } 41 | 42 | public addChangeListener(fn: (changeEvent: ConfigChangeEvent) => void): PropertiesConfig { 43 | this.addListener(CHANGE_EVENT_NAME, fn); 44 | return this; 45 | } 46 | 47 | public async _loadAndUpdateConfig(url: string, headers: AuthHeader | undefined): Promise { 48 | const loadConfigResp = await Request.fetchConfig(url, headers); 49 | if (loadConfigResp) { 50 | // diff change 51 | const { added, deleted, changed } = this.diffMap(this.configs, loadConfigResp.configurations); 52 | // update change and emit changeEvent 53 | const configChangeEvent = this.updateConfigAndCreateChangeEvent(added, 54 | deleted, 55 | changed, 56 | loadConfigResp.configurations); 57 | if (configChangeEvent) { 58 | this.emit(CHANGE_EVENT_NAME, configChangeEvent); 59 | } 60 | // update releaseKey 61 | this.setReleaseKey(loadConfigResp.releaseKey); 62 | } 63 | } 64 | 65 | private diffMap(oldConfigs: Map, newConfigs: { [key: string]: string }): { 66 | added: string[]; 67 | deleted: string[]; 68 | changed: string[]; 69 | } { 70 | const added: string[] = []; 71 | const deleted: string[] = []; 72 | const changed: string[] = []; 73 | for (const key in newConfigs) { 74 | if (oldConfigs.has(key)) { 75 | if (oldConfigs.get(key) !== newConfigs[key]) { 76 | changed.push(key); 77 | } 78 | } else { 79 | added.push(key); 80 | } 81 | } 82 | for (const key of oldConfigs.keys()) { 83 | if (!Object.prototype.hasOwnProperty.call(newConfigs, key)) { 84 | deleted.push(key); 85 | } 86 | } 87 | return { 88 | added, 89 | deleted, 90 | changed, 91 | }; 92 | } 93 | 94 | private updateConfigAndCreateChangeEvent(added: string[], deleted: string[], changed: string[], newConfigs: { 95 | [key: string]: string; 96 | }): undefined | ConfigChangeEvent { 97 | const configChanges: Map> = new Map(); 98 | 99 | for (const addedKey of added) { 100 | const newConfigValue = newConfigs[addedKey]; 101 | configChanges.set(addedKey, new ConfigChange(this.getNamespaceName(), addedKey, undefined, newConfigValue, PropertyChangeType.ADDED)); 102 | this.setProperty(addedKey, newConfigValue); 103 | } 104 | 105 | for (const deletedKey of deleted) { 106 | configChanges.set(deletedKey, new ConfigChange(this.getNamespaceName(), deletedKey, this.configs.get(deletedKey), undefined, PropertyChangeType.DELETED)); 107 | this.deleteProperty(deletedKey); 108 | } 109 | 110 | for (const changedKey of changed) { 111 | const newConfigsValue = newConfigs[changedKey]; 112 | configChanges.set(changedKey, new ConfigChange(this.getNamespaceName(), changedKey, this.configs.get(changedKey), newConfigs[changedKey], PropertyChangeType.MODIFIED)); 113 | this.setProperty(changedKey, newConfigsValue); 114 | } 115 | 116 | let configChangeEvent: undefined | ConfigChangeEvent; 117 | 118 | if (configChanges.size > 0) { 119 | configChangeEvent = new ConfigChangeEvent(this.getNamespaceName(), configChanges); 120 | } 121 | 122 | return configChangeEvent; 123 | } 124 | 125 | } 126 | -------------------------------------------------------------------------------- /lib/request.ts: -------------------------------------------------------------------------------- 1 | import fetch, { HeadersInit } from 'node-fetch'; 2 | import { stringify } from 'query-string'; 3 | import { ConfigInterface } from './configInterface'; 4 | 5 | export type ConfigUrlOptions = { 6 | configServerUrl: string; 7 | appId: string; 8 | clusterName: string; 9 | namespaceName: string; 10 | releaseKey?: string; 11 | ip?: string; 12 | }; 13 | 14 | export type NotificationsUrlOptions = { 15 | configServerUrl: string; 16 | appId: string; 17 | clusterName: string; 18 | }; 19 | 20 | export type ConfigQueryParam = { 21 | releaseKey: string; 22 | ip: string; 23 | }; 24 | 25 | export type Notification = { 26 | namespaceName: string; 27 | notificationId: number; 28 | }; 29 | 30 | export type LoadConfigResp = { 31 | appId: string; 32 | cluster: string; 33 | namespaceName: string; 34 | configurations: T; 35 | releaseKey: string; 36 | } 37 | 38 | export class Request { 39 | public static formatConfigUrl(urlOptions: ConfigUrlOptions): string { 40 | const { appId, clusterName, namespaceName, configServerUrl, releaseKey, ip } = urlOptions; 41 | const url = configServerUrl.endsWith('/') ? configServerUrl.substring(0, configServerUrl.length - 1) : configServerUrl; 42 | const params: ConfigQueryParam = Object.create(null); 43 | if (releaseKey) { 44 | params.releaseKey = releaseKey; 45 | } 46 | if (ip) { 47 | params.ip = ip; 48 | } 49 | return `${url}/configs/${appId}/${clusterName}/${namespaceName}?${stringify(params)}`; 50 | } 51 | 52 | public static async fetchConfig(url: string, headers?: HeadersInit): Promise | null> { 53 | const response = await fetch(url, { headers }); 54 | const status = response.status; 55 | const text = await response.text(); 56 | if (status === 304) return null; 57 | if (status != 200) throw new Error(`Http request error: ${status}, ${response.statusText}`); 58 | if (!text) return null; 59 | return JSON.parse(text); 60 | } 61 | 62 | public static formatNotificationsUrl(options: NotificationsUrlOptions, 63 | configsMap: Map): string { 64 | const { configServerUrl, appId, clusterName } = options; 65 | const url = configServerUrl.endsWith('/') ? configServerUrl.substring(0, configServerUrl.length - 1) : configServerUrl; 66 | const notifications: Notification[] = []; 67 | for (const config of configsMap.values()) { 68 | const temp = { 69 | namespaceName: config.getNamespaceName(), 70 | notificationId: config.getNotificationId(), 71 | }; 72 | notifications.push(temp); 73 | } 74 | const strParams = stringify({ 75 | appId: appId, 76 | cluster: clusterName, 77 | notifications: JSON.stringify(notifications), 78 | }); 79 | return `${url}/notifications/v2?${strParams}`; 80 | } 81 | 82 | public static async fetchNotifications(url: string, headers?: HeadersInit): Promise { 83 | const response = await fetch(url, { headers, timeout: 70000 }); 84 | const status = response.status; 85 | const text = await response.text(); 86 | if (status === 304) return null; 87 | if (status != 200) throw new Error(`Http request error: ${status}, ${response.statusText}`); 88 | if (!text) return null; 89 | return JSON.parse(text); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /lib/types.ts: -------------------------------------------------------------------------------- 1 | export type ConfigOptions = { 2 | configServerUrl: string; 3 | appId: string; 4 | clusterName: string; 5 | namespaceName: string; 6 | secret?: string; 7 | } 8 | 9 | export type ConfigContentType = { 10 | content: string; 11 | } 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apollo-node-client", 3 | "version": "1.4.3", 4 | "description": "Node.js Client for Apollo", 5 | "author": "zhangxh1023", 6 | "email": "zhangxh1023@gmail.com", 7 | "url": "https://github.com/zhangxh1023/apollo-node-client", 8 | "main": "dist/index.js", 9 | "typings": "dist/index.d.ts", 10 | "repository": { 11 | "type": "git", 12 | "url": "git@github.com:zhangxh1023/apollo-node-client.git" 13 | }, 14 | "files": [ 15 | "dist" 16 | ], 17 | "keywords": [ 18 | "apollo", 19 | "apollo client", 20 | "ctrip apollo", 21 | "ctrip apollo client" 22 | ], 23 | "scripts": { 24 | "build": "tsc --sourceMap false -p tsconfig.json", 25 | "clean": "rm -rf dist coverage", 26 | "lint": "eslint --ext .ts .", 27 | "fix": "eslint --fix --ext .ts .", 28 | "prepublishOnly": "npm run clean && npm run build && npm run lint && npm run test", 29 | "test": "jest", 30 | "test:coverage": "jest --coverage" 31 | }, 32 | "license": "MIT", 33 | "devDependencies": { 34 | "@types/jest": "^29.0.3", 35 | "@types/node": "^18.7.18", 36 | "@types/node-fetch": "^2.6.2", 37 | "@typescript-eslint/eslint-plugin": "^2.19.0", 38 | "@typescript-eslint/parser": "^2.19.0", 39 | "eslint": "^6.8.0", 40 | "i": "^0.3.7", 41 | "jest": "^29.4.1", 42 | "npm": "^8.19.2", 43 | "ts-jest": "^29.0.5", 44 | "typescript": "^4.8.3" 45 | }, 46 | "dependencies": { 47 | "node-fetch": "^2.6.9", 48 | "query-string": "^7.1.3" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | dependencies: 8 | node-fetch: 9 | specifier: ^2.6.9 10 | version: 2.7.0 11 | query-string: 12 | specifier: ^7.1.3 13 | version: 7.1.3 14 | 15 | devDependencies: 16 | '@types/jest': 17 | specifier: ^29.0.3 18 | version: 29.5.13 19 | '@types/node': 20 | specifier: ^18.7.18 21 | version: 18.19.50 22 | '@types/node-fetch': 23 | specifier: ^2.6.2 24 | version: 2.6.11 25 | '@typescript-eslint/eslint-plugin': 26 | specifier: ^2.19.0 27 | version: 2.34.0(@typescript-eslint/parser@2.34.0)(eslint@6.8.0)(typescript@4.9.5) 28 | '@typescript-eslint/parser': 29 | specifier: ^2.19.0 30 | version: 2.34.0(eslint@6.8.0)(typescript@4.9.5) 31 | eslint: 32 | specifier: ^6.8.0 33 | version: 6.8.0 34 | i: 35 | specifier: ^0.3.7 36 | version: 0.3.7 37 | jest: 38 | specifier: ^29.4.1 39 | version: 29.7.0(@types/node@18.19.50) 40 | npm: 41 | specifier: ^8.19.2 42 | version: 8.19.4 43 | ts-jest: 44 | specifier: ^29.0.5 45 | version: 29.2.5(@babel/core@7.25.2)(jest@29.7.0)(typescript@4.9.5) 46 | typescript: 47 | specifier: ^4.8.3 48 | version: 4.9.5 49 | 50 | packages: 51 | 52 | /@ampproject/remapping@2.3.0: 53 | resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} 54 | engines: {node: '>=6.0.0'} 55 | dependencies: 56 | '@jridgewell/gen-mapping': 0.3.5 57 | '@jridgewell/trace-mapping': 0.3.25 58 | dev: true 59 | 60 | /@babel/code-frame@7.24.7: 61 | resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} 62 | engines: {node: '>=6.9.0'} 63 | dependencies: 64 | '@babel/highlight': 7.24.7 65 | picocolors: 1.1.0 66 | dev: true 67 | 68 | /@babel/compat-data@7.25.4: 69 | resolution: {integrity: sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==} 70 | engines: {node: '>=6.9.0'} 71 | dev: true 72 | 73 | /@babel/core@7.25.2: 74 | resolution: {integrity: sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==} 75 | engines: {node: '>=6.9.0'} 76 | dependencies: 77 | '@ampproject/remapping': 2.3.0 78 | '@babel/code-frame': 7.24.7 79 | '@babel/generator': 7.25.6 80 | '@babel/helper-compilation-targets': 7.25.2 81 | '@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2) 82 | '@babel/helpers': 7.25.6 83 | '@babel/parser': 7.25.6 84 | '@babel/template': 7.25.0 85 | '@babel/traverse': 7.25.6 86 | '@babel/types': 7.25.6 87 | convert-source-map: 2.0.0 88 | debug: 4.3.7 89 | gensync: 1.0.0-beta.2 90 | json5: 2.2.3 91 | semver: 6.3.1 92 | transitivePeerDependencies: 93 | - supports-color 94 | dev: true 95 | 96 | /@babel/generator@7.25.6: 97 | resolution: {integrity: sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==} 98 | engines: {node: '>=6.9.0'} 99 | dependencies: 100 | '@babel/types': 7.25.6 101 | '@jridgewell/gen-mapping': 0.3.5 102 | '@jridgewell/trace-mapping': 0.3.25 103 | jsesc: 2.5.2 104 | dev: true 105 | 106 | /@babel/helper-compilation-targets@7.25.2: 107 | resolution: {integrity: sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==} 108 | engines: {node: '>=6.9.0'} 109 | dependencies: 110 | '@babel/compat-data': 7.25.4 111 | '@babel/helper-validator-option': 7.24.8 112 | browserslist: 4.23.3 113 | lru-cache: 5.1.1 114 | semver: 6.3.1 115 | dev: true 116 | 117 | /@babel/helper-module-imports@7.24.7: 118 | resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==} 119 | engines: {node: '>=6.9.0'} 120 | dependencies: 121 | '@babel/traverse': 7.25.6 122 | '@babel/types': 7.25.6 123 | transitivePeerDependencies: 124 | - supports-color 125 | dev: true 126 | 127 | /@babel/helper-module-transforms@7.25.2(@babel/core@7.25.2): 128 | resolution: {integrity: sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==} 129 | engines: {node: '>=6.9.0'} 130 | peerDependencies: 131 | '@babel/core': ^7.0.0 132 | dependencies: 133 | '@babel/core': 7.25.2 134 | '@babel/helper-module-imports': 7.24.7 135 | '@babel/helper-simple-access': 7.24.7 136 | '@babel/helper-validator-identifier': 7.24.7 137 | '@babel/traverse': 7.25.6 138 | transitivePeerDependencies: 139 | - supports-color 140 | dev: true 141 | 142 | /@babel/helper-plugin-utils@7.24.8: 143 | resolution: {integrity: sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==} 144 | engines: {node: '>=6.9.0'} 145 | dev: true 146 | 147 | /@babel/helper-simple-access@7.24.7: 148 | resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==} 149 | engines: {node: '>=6.9.0'} 150 | dependencies: 151 | '@babel/traverse': 7.25.6 152 | '@babel/types': 7.25.6 153 | transitivePeerDependencies: 154 | - supports-color 155 | dev: true 156 | 157 | /@babel/helper-string-parser@7.24.8: 158 | resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==} 159 | engines: {node: '>=6.9.0'} 160 | dev: true 161 | 162 | /@babel/helper-validator-identifier@7.24.7: 163 | resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} 164 | engines: {node: '>=6.9.0'} 165 | dev: true 166 | 167 | /@babel/helper-validator-option@7.24.8: 168 | resolution: {integrity: sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==} 169 | engines: {node: '>=6.9.0'} 170 | dev: true 171 | 172 | /@babel/helpers@7.25.6: 173 | resolution: {integrity: sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==} 174 | engines: {node: '>=6.9.0'} 175 | dependencies: 176 | '@babel/template': 7.25.0 177 | '@babel/types': 7.25.6 178 | dev: true 179 | 180 | /@babel/highlight@7.24.7: 181 | resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} 182 | engines: {node: '>=6.9.0'} 183 | dependencies: 184 | '@babel/helper-validator-identifier': 7.24.7 185 | chalk: 2.4.2 186 | js-tokens: 4.0.0 187 | picocolors: 1.1.0 188 | dev: true 189 | 190 | /@babel/parser@7.25.6: 191 | resolution: {integrity: sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==} 192 | engines: {node: '>=6.0.0'} 193 | hasBin: true 194 | dependencies: 195 | '@babel/types': 7.25.6 196 | dev: true 197 | 198 | /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.25.2): 199 | resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} 200 | peerDependencies: 201 | '@babel/core': ^7.0.0-0 202 | dependencies: 203 | '@babel/core': 7.25.2 204 | '@babel/helper-plugin-utils': 7.24.8 205 | dev: true 206 | 207 | /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.25.2): 208 | resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} 209 | peerDependencies: 210 | '@babel/core': ^7.0.0-0 211 | dependencies: 212 | '@babel/core': 7.25.2 213 | '@babel/helper-plugin-utils': 7.24.8 214 | dev: true 215 | 216 | /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.25.2): 217 | resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} 218 | peerDependencies: 219 | '@babel/core': ^7.0.0-0 220 | dependencies: 221 | '@babel/core': 7.25.2 222 | '@babel/helper-plugin-utils': 7.24.8 223 | dev: true 224 | 225 | /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.25.2): 226 | resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} 227 | engines: {node: '>=6.9.0'} 228 | peerDependencies: 229 | '@babel/core': ^7.0.0-0 230 | dependencies: 231 | '@babel/core': 7.25.2 232 | '@babel/helper-plugin-utils': 7.24.8 233 | dev: true 234 | 235 | /@babel/plugin-syntax-import-attributes@7.25.6(@babel/core@7.25.2): 236 | resolution: {integrity: sha512-sXaDXaJN9SNLymBdlWFA+bjzBhFD617ZaFiY13dGt7TVslVvVgA6fkZOP7Ki3IGElC45lwHdOTrCtKZGVAWeLQ==} 237 | engines: {node: '>=6.9.0'} 238 | peerDependencies: 239 | '@babel/core': ^7.0.0-0 240 | dependencies: 241 | '@babel/core': 7.25.2 242 | '@babel/helper-plugin-utils': 7.24.8 243 | dev: true 244 | 245 | /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.25.2): 246 | resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} 247 | peerDependencies: 248 | '@babel/core': ^7.0.0-0 249 | dependencies: 250 | '@babel/core': 7.25.2 251 | '@babel/helper-plugin-utils': 7.24.8 252 | dev: true 253 | 254 | /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.25.2): 255 | resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} 256 | peerDependencies: 257 | '@babel/core': ^7.0.0-0 258 | dependencies: 259 | '@babel/core': 7.25.2 260 | '@babel/helper-plugin-utils': 7.24.8 261 | dev: true 262 | 263 | /@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.25.2): 264 | resolution: {integrity: sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==} 265 | engines: {node: '>=6.9.0'} 266 | peerDependencies: 267 | '@babel/core': ^7.0.0-0 268 | dependencies: 269 | '@babel/core': 7.25.2 270 | '@babel/helper-plugin-utils': 7.24.8 271 | dev: true 272 | 273 | /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.25.2): 274 | resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} 275 | peerDependencies: 276 | '@babel/core': ^7.0.0-0 277 | dependencies: 278 | '@babel/core': 7.25.2 279 | '@babel/helper-plugin-utils': 7.24.8 280 | dev: true 281 | 282 | /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.25.2): 283 | resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} 284 | peerDependencies: 285 | '@babel/core': ^7.0.0-0 286 | dependencies: 287 | '@babel/core': 7.25.2 288 | '@babel/helper-plugin-utils': 7.24.8 289 | dev: true 290 | 291 | /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.25.2): 292 | resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} 293 | peerDependencies: 294 | '@babel/core': ^7.0.0-0 295 | dependencies: 296 | '@babel/core': 7.25.2 297 | '@babel/helper-plugin-utils': 7.24.8 298 | dev: true 299 | 300 | /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.25.2): 301 | resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} 302 | peerDependencies: 303 | '@babel/core': ^7.0.0-0 304 | dependencies: 305 | '@babel/core': 7.25.2 306 | '@babel/helper-plugin-utils': 7.24.8 307 | dev: true 308 | 309 | /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.25.2): 310 | resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} 311 | peerDependencies: 312 | '@babel/core': ^7.0.0-0 313 | dependencies: 314 | '@babel/core': 7.25.2 315 | '@babel/helper-plugin-utils': 7.24.8 316 | dev: true 317 | 318 | /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.25.2): 319 | resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} 320 | peerDependencies: 321 | '@babel/core': ^7.0.0-0 322 | dependencies: 323 | '@babel/core': 7.25.2 324 | '@babel/helper-plugin-utils': 7.24.8 325 | dev: true 326 | 327 | /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.25.2): 328 | resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} 329 | engines: {node: '>=6.9.0'} 330 | peerDependencies: 331 | '@babel/core': ^7.0.0-0 332 | dependencies: 333 | '@babel/core': 7.25.2 334 | '@babel/helper-plugin-utils': 7.24.8 335 | dev: true 336 | 337 | /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.25.2): 338 | resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} 339 | engines: {node: '>=6.9.0'} 340 | peerDependencies: 341 | '@babel/core': ^7.0.0-0 342 | dependencies: 343 | '@babel/core': 7.25.2 344 | '@babel/helper-plugin-utils': 7.24.8 345 | dev: true 346 | 347 | /@babel/plugin-syntax-typescript@7.25.4(@babel/core@7.25.2): 348 | resolution: {integrity: sha512-uMOCoHVU52BsSWxPOMVv5qKRdeSlPuImUCB2dlPuBSU+W2/ROE7/Zg8F2Kepbk+8yBa68LlRKxO+xgEVWorsDg==} 349 | engines: {node: '>=6.9.0'} 350 | peerDependencies: 351 | '@babel/core': ^7.0.0-0 352 | dependencies: 353 | '@babel/core': 7.25.2 354 | '@babel/helper-plugin-utils': 7.24.8 355 | dev: true 356 | 357 | /@babel/template@7.25.0: 358 | resolution: {integrity: sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==} 359 | engines: {node: '>=6.9.0'} 360 | dependencies: 361 | '@babel/code-frame': 7.24.7 362 | '@babel/parser': 7.25.6 363 | '@babel/types': 7.25.6 364 | dev: true 365 | 366 | /@babel/traverse@7.25.6: 367 | resolution: {integrity: sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==} 368 | engines: {node: '>=6.9.0'} 369 | dependencies: 370 | '@babel/code-frame': 7.24.7 371 | '@babel/generator': 7.25.6 372 | '@babel/parser': 7.25.6 373 | '@babel/template': 7.25.0 374 | '@babel/types': 7.25.6 375 | debug: 4.3.7 376 | globals: 11.12.0 377 | transitivePeerDependencies: 378 | - supports-color 379 | dev: true 380 | 381 | /@babel/types@7.25.6: 382 | resolution: {integrity: sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==} 383 | engines: {node: '>=6.9.0'} 384 | dependencies: 385 | '@babel/helper-string-parser': 7.24.8 386 | '@babel/helper-validator-identifier': 7.24.7 387 | to-fast-properties: 2.0.0 388 | dev: true 389 | 390 | /@bcoe/v8-coverage@0.2.3: 391 | resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} 392 | dev: true 393 | 394 | /@istanbuljs/load-nyc-config@1.1.0: 395 | resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} 396 | engines: {node: '>=8'} 397 | dependencies: 398 | camelcase: 5.3.1 399 | find-up: 4.1.0 400 | get-package-type: 0.1.0 401 | js-yaml: 3.14.1 402 | resolve-from: 5.0.0 403 | dev: true 404 | 405 | /@istanbuljs/schema@0.1.3: 406 | resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} 407 | engines: {node: '>=8'} 408 | dev: true 409 | 410 | /@jest/console@29.7.0: 411 | resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} 412 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 413 | dependencies: 414 | '@jest/types': 29.6.3 415 | '@types/node': 18.19.50 416 | chalk: 4.1.2 417 | jest-message-util: 29.7.0 418 | jest-util: 29.7.0 419 | slash: 3.0.0 420 | dev: true 421 | 422 | /@jest/core@29.7.0: 423 | resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} 424 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 425 | peerDependencies: 426 | node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 427 | peerDependenciesMeta: 428 | node-notifier: 429 | optional: true 430 | dependencies: 431 | '@jest/console': 29.7.0 432 | '@jest/reporters': 29.7.0 433 | '@jest/test-result': 29.7.0 434 | '@jest/transform': 29.7.0 435 | '@jest/types': 29.6.3 436 | '@types/node': 18.19.50 437 | ansi-escapes: 4.3.2 438 | chalk: 4.1.2 439 | ci-info: 3.9.0 440 | exit: 0.1.2 441 | graceful-fs: 4.2.11 442 | jest-changed-files: 29.7.0 443 | jest-config: 29.7.0(@types/node@18.19.50) 444 | jest-haste-map: 29.7.0 445 | jest-message-util: 29.7.0 446 | jest-regex-util: 29.6.3 447 | jest-resolve: 29.7.0 448 | jest-resolve-dependencies: 29.7.0 449 | jest-runner: 29.7.0 450 | jest-runtime: 29.7.0 451 | jest-snapshot: 29.7.0 452 | jest-util: 29.7.0 453 | jest-validate: 29.7.0 454 | jest-watcher: 29.7.0 455 | micromatch: 4.0.8 456 | pretty-format: 29.7.0 457 | slash: 3.0.0 458 | strip-ansi: 6.0.1 459 | transitivePeerDependencies: 460 | - babel-plugin-macros 461 | - supports-color 462 | - ts-node 463 | dev: true 464 | 465 | /@jest/environment@29.7.0: 466 | resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} 467 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 468 | dependencies: 469 | '@jest/fake-timers': 29.7.0 470 | '@jest/types': 29.6.3 471 | '@types/node': 18.19.50 472 | jest-mock: 29.7.0 473 | dev: true 474 | 475 | /@jest/expect-utils@29.7.0: 476 | resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} 477 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 478 | dependencies: 479 | jest-get-type: 29.6.3 480 | dev: true 481 | 482 | /@jest/expect@29.7.0: 483 | resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} 484 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 485 | dependencies: 486 | expect: 29.7.0 487 | jest-snapshot: 29.7.0 488 | transitivePeerDependencies: 489 | - supports-color 490 | dev: true 491 | 492 | /@jest/fake-timers@29.7.0: 493 | resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} 494 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 495 | dependencies: 496 | '@jest/types': 29.6.3 497 | '@sinonjs/fake-timers': 10.3.0 498 | '@types/node': 18.19.50 499 | jest-message-util: 29.7.0 500 | jest-mock: 29.7.0 501 | jest-util: 29.7.0 502 | dev: true 503 | 504 | /@jest/globals@29.7.0: 505 | resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} 506 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 507 | dependencies: 508 | '@jest/environment': 29.7.0 509 | '@jest/expect': 29.7.0 510 | '@jest/types': 29.6.3 511 | jest-mock: 29.7.0 512 | transitivePeerDependencies: 513 | - supports-color 514 | dev: true 515 | 516 | /@jest/reporters@29.7.0: 517 | resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} 518 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 519 | peerDependencies: 520 | node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 521 | peerDependenciesMeta: 522 | node-notifier: 523 | optional: true 524 | dependencies: 525 | '@bcoe/v8-coverage': 0.2.3 526 | '@jest/console': 29.7.0 527 | '@jest/test-result': 29.7.0 528 | '@jest/transform': 29.7.0 529 | '@jest/types': 29.6.3 530 | '@jridgewell/trace-mapping': 0.3.25 531 | '@types/node': 18.19.50 532 | chalk: 4.1.2 533 | collect-v8-coverage: 1.0.2 534 | exit: 0.1.2 535 | glob: 7.2.3 536 | graceful-fs: 4.2.11 537 | istanbul-lib-coverage: 3.2.2 538 | istanbul-lib-instrument: 6.0.3 539 | istanbul-lib-report: 3.0.1 540 | istanbul-lib-source-maps: 4.0.1 541 | istanbul-reports: 3.1.7 542 | jest-message-util: 29.7.0 543 | jest-util: 29.7.0 544 | jest-worker: 29.7.0 545 | slash: 3.0.0 546 | string-length: 4.0.2 547 | strip-ansi: 6.0.1 548 | v8-to-istanbul: 9.3.0 549 | transitivePeerDependencies: 550 | - supports-color 551 | dev: true 552 | 553 | /@jest/schemas@29.6.3: 554 | resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} 555 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 556 | dependencies: 557 | '@sinclair/typebox': 0.27.8 558 | dev: true 559 | 560 | /@jest/source-map@29.6.3: 561 | resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} 562 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 563 | dependencies: 564 | '@jridgewell/trace-mapping': 0.3.25 565 | callsites: 3.1.0 566 | graceful-fs: 4.2.11 567 | dev: true 568 | 569 | /@jest/test-result@29.7.0: 570 | resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} 571 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 572 | dependencies: 573 | '@jest/console': 29.7.0 574 | '@jest/types': 29.6.3 575 | '@types/istanbul-lib-coverage': 2.0.6 576 | collect-v8-coverage: 1.0.2 577 | dev: true 578 | 579 | /@jest/test-sequencer@29.7.0: 580 | resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} 581 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 582 | dependencies: 583 | '@jest/test-result': 29.7.0 584 | graceful-fs: 4.2.11 585 | jest-haste-map: 29.7.0 586 | slash: 3.0.0 587 | dev: true 588 | 589 | /@jest/transform@29.7.0: 590 | resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} 591 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 592 | dependencies: 593 | '@babel/core': 7.25.2 594 | '@jest/types': 29.6.3 595 | '@jridgewell/trace-mapping': 0.3.25 596 | babel-plugin-istanbul: 6.1.1 597 | chalk: 4.1.2 598 | convert-source-map: 2.0.0 599 | fast-json-stable-stringify: 2.1.0 600 | graceful-fs: 4.2.11 601 | jest-haste-map: 29.7.0 602 | jest-regex-util: 29.6.3 603 | jest-util: 29.7.0 604 | micromatch: 4.0.8 605 | pirates: 4.0.6 606 | slash: 3.0.0 607 | write-file-atomic: 4.0.2 608 | transitivePeerDependencies: 609 | - supports-color 610 | dev: true 611 | 612 | /@jest/types@29.6.3: 613 | resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} 614 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 615 | dependencies: 616 | '@jest/schemas': 29.6.3 617 | '@types/istanbul-lib-coverage': 2.0.6 618 | '@types/istanbul-reports': 3.0.4 619 | '@types/node': 18.19.50 620 | '@types/yargs': 17.0.33 621 | chalk: 4.1.2 622 | dev: true 623 | 624 | /@jridgewell/gen-mapping@0.3.5: 625 | resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} 626 | engines: {node: '>=6.0.0'} 627 | dependencies: 628 | '@jridgewell/set-array': 1.2.1 629 | '@jridgewell/sourcemap-codec': 1.5.0 630 | '@jridgewell/trace-mapping': 0.3.25 631 | dev: true 632 | 633 | /@jridgewell/resolve-uri@3.1.2: 634 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 635 | engines: {node: '>=6.0.0'} 636 | dev: true 637 | 638 | /@jridgewell/set-array@1.2.1: 639 | resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} 640 | engines: {node: '>=6.0.0'} 641 | dev: true 642 | 643 | /@jridgewell/sourcemap-codec@1.5.0: 644 | resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} 645 | dev: true 646 | 647 | /@jridgewell/trace-mapping@0.3.25: 648 | resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} 649 | dependencies: 650 | '@jridgewell/resolve-uri': 3.1.2 651 | '@jridgewell/sourcemap-codec': 1.5.0 652 | dev: true 653 | 654 | /@sinclair/typebox@0.27.8: 655 | resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} 656 | dev: true 657 | 658 | /@sinonjs/commons@3.0.1: 659 | resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} 660 | dependencies: 661 | type-detect: 4.0.8 662 | dev: true 663 | 664 | /@sinonjs/fake-timers@10.3.0: 665 | resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} 666 | dependencies: 667 | '@sinonjs/commons': 3.0.1 668 | dev: true 669 | 670 | /@types/babel__core@7.20.5: 671 | resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} 672 | dependencies: 673 | '@babel/parser': 7.25.6 674 | '@babel/types': 7.25.6 675 | '@types/babel__generator': 7.6.8 676 | '@types/babel__template': 7.4.4 677 | '@types/babel__traverse': 7.20.6 678 | dev: true 679 | 680 | /@types/babel__generator@7.6.8: 681 | resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} 682 | dependencies: 683 | '@babel/types': 7.25.6 684 | dev: true 685 | 686 | /@types/babel__template@7.4.4: 687 | resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} 688 | dependencies: 689 | '@babel/parser': 7.25.6 690 | '@babel/types': 7.25.6 691 | dev: true 692 | 693 | /@types/babel__traverse@7.20.6: 694 | resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} 695 | dependencies: 696 | '@babel/types': 7.25.6 697 | dev: true 698 | 699 | /@types/eslint-visitor-keys@1.0.0: 700 | resolution: {integrity: sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==} 701 | dev: true 702 | 703 | /@types/graceful-fs@4.1.9: 704 | resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} 705 | dependencies: 706 | '@types/node': 18.19.50 707 | dev: true 708 | 709 | /@types/istanbul-lib-coverage@2.0.6: 710 | resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} 711 | dev: true 712 | 713 | /@types/istanbul-lib-report@3.0.3: 714 | resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} 715 | dependencies: 716 | '@types/istanbul-lib-coverage': 2.0.6 717 | dev: true 718 | 719 | /@types/istanbul-reports@3.0.4: 720 | resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} 721 | dependencies: 722 | '@types/istanbul-lib-report': 3.0.3 723 | dev: true 724 | 725 | /@types/jest@29.5.13: 726 | resolution: {integrity: sha512-wd+MVEZCHt23V0/L642O5APvspWply/rGY5BcW4SUETo2UzPU3Z26qr8jC2qxpimI2jjx9h7+2cj2FwIr01bXg==} 727 | dependencies: 728 | expect: 29.7.0 729 | pretty-format: 29.7.0 730 | dev: true 731 | 732 | /@types/json-schema@7.0.15: 733 | resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} 734 | dev: true 735 | 736 | /@types/node-fetch@2.6.11: 737 | resolution: {integrity: sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==} 738 | dependencies: 739 | '@types/node': 18.19.50 740 | form-data: 4.0.0 741 | dev: true 742 | 743 | /@types/node@18.19.50: 744 | resolution: {integrity: sha512-xonK+NRrMBRtkL1hVCc3G+uXtjh1Al4opBLjqVmipe5ZAaBYWW6cNAiBVZ1BvmkBhep698rP3UM3aRAdSALuhg==} 745 | dependencies: 746 | undici-types: 5.26.5 747 | dev: true 748 | 749 | /@types/stack-utils@2.0.3: 750 | resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} 751 | dev: true 752 | 753 | /@types/yargs-parser@21.0.3: 754 | resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} 755 | dev: true 756 | 757 | /@types/yargs@17.0.33: 758 | resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} 759 | dependencies: 760 | '@types/yargs-parser': 21.0.3 761 | dev: true 762 | 763 | /@typescript-eslint/eslint-plugin@2.34.0(@typescript-eslint/parser@2.34.0)(eslint@6.8.0)(typescript@4.9.5): 764 | resolution: {integrity: sha512-4zY3Z88rEE99+CNvTbXSyovv2z9PNOVffTWD2W8QF5s2prBQtwN2zadqERcrHpcR7O/+KMI3fcTAmUUhK/iQcQ==} 765 | engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} 766 | peerDependencies: 767 | '@typescript-eslint/parser': ^2.0.0 768 | eslint: ^5.0.0 || ^6.0.0 769 | typescript: '*' 770 | peerDependenciesMeta: 771 | typescript: 772 | optional: true 773 | dependencies: 774 | '@typescript-eslint/experimental-utils': 2.34.0(eslint@6.8.0)(typescript@4.9.5) 775 | '@typescript-eslint/parser': 2.34.0(eslint@6.8.0)(typescript@4.9.5) 776 | eslint: 6.8.0 777 | functional-red-black-tree: 1.0.1 778 | regexpp: 3.2.0 779 | tsutils: 3.21.0(typescript@4.9.5) 780 | typescript: 4.9.5 781 | transitivePeerDependencies: 782 | - supports-color 783 | dev: true 784 | 785 | /@typescript-eslint/experimental-utils@2.34.0(eslint@6.8.0)(typescript@4.9.5): 786 | resolution: {integrity: sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA==} 787 | engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} 788 | peerDependencies: 789 | eslint: '*' 790 | dependencies: 791 | '@types/json-schema': 7.0.15 792 | '@typescript-eslint/typescript-estree': 2.34.0(typescript@4.9.5) 793 | eslint: 6.8.0 794 | eslint-scope: 5.1.1 795 | eslint-utils: 2.1.0 796 | transitivePeerDependencies: 797 | - supports-color 798 | - typescript 799 | dev: true 800 | 801 | /@typescript-eslint/parser@2.34.0(eslint@6.8.0)(typescript@4.9.5): 802 | resolution: {integrity: sha512-03ilO0ucSD0EPTw2X4PntSIRFtDPWjrVq7C3/Z3VQHRC7+13YB55rcJI3Jt+YgeHbjUdJPcPa7b23rXCBokuyA==} 803 | engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} 804 | peerDependencies: 805 | eslint: ^5.0.0 || ^6.0.0 806 | typescript: '*' 807 | peerDependenciesMeta: 808 | typescript: 809 | optional: true 810 | dependencies: 811 | '@types/eslint-visitor-keys': 1.0.0 812 | '@typescript-eslint/experimental-utils': 2.34.0(eslint@6.8.0)(typescript@4.9.5) 813 | '@typescript-eslint/typescript-estree': 2.34.0(typescript@4.9.5) 814 | eslint: 6.8.0 815 | eslint-visitor-keys: 1.3.0 816 | typescript: 4.9.5 817 | transitivePeerDependencies: 818 | - supports-color 819 | dev: true 820 | 821 | /@typescript-eslint/typescript-estree@2.34.0(typescript@4.9.5): 822 | resolution: {integrity: sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg==} 823 | engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} 824 | peerDependencies: 825 | typescript: '*' 826 | peerDependenciesMeta: 827 | typescript: 828 | optional: true 829 | dependencies: 830 | debug: 4.3.7 831 | eslint-visitor-keys: 1.3.0 832 | glob: 7.2.3 833 | is-glob: 4.0.3 834 | lodash: 4.17.21 835 | semver: 7.6.3 836 | tsutils: 3.21.0(typescript@4.9.5) 837 | typescript: 4.9.5 838 | transitivePeerDependencies: 839 | - supports-color 840 | dev: true 841 | 842 | /acorn-jsx@5.3.2(acorn@7.4.1): 843 | resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} 844 | peerDependencies: 845 | acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 846 | dependencies: 847 | acorn: 7.4.1 848 | dev: true 849 | 850 | /acorn@7.4.1: 851 | resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} 852 | engines: {node: '>=0.4.0'} 853 | hasBin: true 854 | dev: true 855 | 856 | /ajv@6.12.6: 857 | resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} 858 | dependencies: 859 | fast-deep-equal: 3.1.3 860 | fast-json-stable-stringify: 2.1.0 861 | json-schema-traverse: 0.4.1 862 | uri-js: 4.4.1 863 | dev: true 864 | 865 | /ansi-escapes@4.3.2: 866 | resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} 867 | engines: {node: '>=8'} 868 | dependencies: 869 | type-fest: 0.21.3 870 | dev: true 871 | 872 | /ansi-regex@4.1.1: 873 | resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==} 874 | engines: {node: '>=6'} 875 | dev: true 876 | 877 | /ansi-regex@5.0.1: 878 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 879 | engines: {node: '>=8'} 880 | dev: true 881 | 882 | /ansi-styles@3.2.1: 883 | resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} 884 | engines: {node: '>=4'} 885 | dependencies: 886 | color-convert: 1.9.3 887 | dev: true 888 | 889 | /ansi-styles@4.3.0: 890 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 891 | engines: {node: '>=8'} 892 | dependencies: 893 | color-convert: 2.0.1 894 | dev: true 895 | 896 | /ansi-styles@5.2.0: 897 | resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} 898 | engines: {node: '>=10'} 899 | dev: true 900 | 901 | /anymatch@3.1.3: 902 | resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} 903 | engines: {node: '>= 8'} 904 | dependencies: 905 | normalize-path: 3.0.0 906 | picomatch: 2.3.1 907 | dev: true 908 | 909 | /argparse@1.0.10: 910 | resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} 911 | dependencies: 912 | sprintf-js: 1.0.3 913 | dev: true 914 | 915 | /astral-regex@1.0.0: 916 | resolution: {integrity: sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==} 917 | engines: {node: '>=4'} 918 | dev: true 919 | 920 | /async@3.2.6: 921 | resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} 922 | dev: true 923 | 924 | /asynckit@0.4.0: 925 | resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} 926 | dev: true 927 | 928 | /babel-jest@29.7.0(@babel/core@7.25.2): 929 | resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} 930 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 931 | peerDependencies: 932 | '@babel/core': ^7.8.0 933 | dependencies: 934 | '@babel/core': 7.25.2 935 | '@jest/transform': 29.7.0 936 | '@types/babel__core': 7.20.5 937 | babel-plugin-istanbul: 6.1.1 938 | babel-preset-jest: 29.6.3(@babel/core@7.25.2) 939 | chalk: 4.1.2 940 | graceful-fs: 4.2.11 941 | slash: 3.0.0 942 | transitivePeerDependencies: 943 | - supports-color 944 | dev: true 945 | 946 | /babel-plugin-istanbul@6.1.1: 947 | resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} 948 | engines: {node: '>=8'} 949 | dependencies: 950 | '@babel/helper-plugin-utils': 7.24.8 951 | '@istanbuljs/load-nyc-config': 1.1.0 952 | '@istanbuljs/schema': 0.1.3 953 | istanbul-lib-instrument: 5.2.1 954 | test-exclude: 6.0.0 955 | transitivePeerDependencies: 956 | - supports-color 957 | dev: true 958 | 959 | /babel-plugin-jest-hoist@29.6.3: 960 | resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} 961 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 962 | dependencies: 963 | '@babel/template': 7.25.0 964 | '@babel/types': 7.25.6 965 | '@types/babel__core': 7.20.5 966 | '@types/babel__traverse': 7.20.6 967 | dev: true 968 | 969 | /babel-preset-current-node-syntax@1.1.0(@babel/core@7.25.2): 970 | resolution: {integrity: sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==} 971 | peerDependencies: 972 | '@babel/core': ^7.0.0 973 | dependencies: 974 | '@babel/core': 7.25.2 975 | '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.25.2) 976 | '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.25.2) 977 | '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.25.2) 978 | '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.25.2) 979 | '@babel/plugin-syntax-import-attributes': 7.25.6(@babel/core@7.25.2) 980 | '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.25.2) 981 | '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.25.2) 982 | '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.25.2) 983 | '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.25.2) 984 | '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.25.2) 985 | '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.25.2) 986 | '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.25.2) 987 | '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.25.2) 988 | '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.25.2) 989 | '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.25.2) 990 | dev: true 991 | 992 | /babel-preset-jest@29.6.3(@babel/core@7.25.2): 993 | resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} 994 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 995 | peerDependencies: 996 | '@babel/core': ^7.0.0 997 | dependencies: 998 | '@babel/core': 7.25.2 999 | babel-plugin-jest-hoist: 29.6.3 1000 | babel-preset-current-node-syntax: 1.1.0(@babel/core@7.25.2) 1001 | dev: true 1002 | 1003 | /balanced-match@1.0.2: 1004 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 1005 | dev: true 1006 | 1007 | /brace-expansion@1.1.11: 1008 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 1009 | dependencies: 1010 | balanced-match: 1.0.2 1011 | concat-map: 0.0.1 1012 | dev: true 1013 | 1014 | /brace-expansion@2.0.1: 1015 | resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} 1016 | dependencies: 1017 | balanced-match: 1.0.2 1018 | dev: true 1019 | 1020 | /braces@3.0.3: 1021 | resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} 1022 | engines: {node: '>=8'} 1023 | dependencies: 1024 | fill-range: 7.1.1 1025 | dev: true 1026 | 1027 | /browserslist@4.23.3: 1028 | resolution: {integrity: sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==} 1029 | engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} 1030 | hasBin: true 1031 | dependencies: 1032 | caniuse-lite: 1.0.30001660 1033 | electron-to-chromium: 1.5.22 1034 | node-releases: 2.0.18 1035 | update-browserslist-db: 1.1.0(browserslist@4.23.3) 1036 | dev: true 1037 | 1038 | /bs-logger@0.2.6: 1039 | resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} 1040 | engines: {node: '>= 6'} 1041 | dependencies: 1042 | fast-json-stable-stringify: 2.1.0 1043 | dev: true 1044 | 1045 | /bser@2.1.1: 1046 | resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} 1047 | dependencies: 1048 | node-int64: 0.4.0 1049 | dev: true 1050 | 1051 | /buffer-from@1.1.2: 1052 | resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} 1053 | dev: true 1054 | 1055 | /callsites@3.1.0: 1056 | resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} 1057 | engines: {node: '>=6'} 1058 | dev: true 1059 | 1060 | /camelcase@5.3.1: 1061 | resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} 1062 | engines: {node: '>=6'} 1063 | dev: true 1064 | 1065 | /camelcase@6.3.0: 1066 | resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} 1067 | engines: {node: '>=10'} 1068 | dev: true 1069 | 1070 | /caniuse-lite@1.0.30001660: 1071 | resolution: {integrity: sha512-GacvNTTuATm26qC74pt+ad1fW15mlQ/zuTzzY1ZoIzECTP8HURDfF43kNxPgf7H1jmelCBQTTbBNxdSXOA7Bqg==} 1072 | dev: true 1073 | 1074 | /chalk@2.4.2: 1075 | resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} 1076 | engines: {node: '>=4'} 1077 | dependencies: 1078 | ansi-styles: 3.2.1 1079 | escape-string-regexp: 1.0.5 1080 | supports-color: 5.5.0 1081 | dev: true 1082 | 1083 | /chalk@4.1.2: 1084 | resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 1085 | engines: {node: '>=10'} 1086 | dependencies: 1087 | ansi-styles: 4.3.0 1088 | supports-color: 7.2.0 1089 | dev: true 1090 | 1091 | /char-regex@1.0.2: 1092 | resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} 1093 | engines: {node: '>=10'} 1094 | dev: true 1095 | 1096 | /chardet@0.7.0: 1097 | resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} 1098 | dev: true 1099 | 1100 | /ci-info@3.9.0: 1101 | resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} 1102 | engines: {node: '>=8'} 1103 | dev: true 1104 | 1105 | /cjs-module-lexer@1.4.1: 1106 | resolution: {integrity: sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==} 1107 | dev: true 1108 | 1109 | /cli-cursor@3.1.0: 1110 | resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} 1111 | engines: {node: '>=8'} 1112 | dependencies: 1113 | restore-cursor: 3.1.0 1114 | dev: true 1115 | 1116 | /cli-width@3.0.0: 1117 | resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} 1118 | engines: {node: '>= 10'} 1119 | dev: true 1120 | 1121 | /cliui@8.0.1: 1122 | resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} 1123 | engines: {node: '>=12'} 1124 | dependencies: 1125 | string-width: 4.2.3 1126 | strip-ansi: 6.0.1 1127 | wrap-ansi: 7.0.0 1128 | dev: true 1129 | 1130 | /co@4.6.0: 1131 | resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} 1132 | engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} 1133 | dev: true 1134 | 1135 | /collect-v8-coverage@1.0.2: 1136 | resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} 1137 | dev: true 1138 | 1139 | /color-convert@1.9.3: 1140 | resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} 1141 | dependencies: 1142 | color-name: 1.1.3 1143 | dev: true 1144 | 1145 | /color-convert@2.0.1: 1146 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 1147 | engines: {node: '>=7.0.0'} 1148 | dependencies: 1149 | color-name: 1.1.4 1150 | dev: true 1151 | 1152 | /color-name@1.1.3: 1153 | resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} 1154 | dev: true 1155 | 1156 | /color-name@1.1.4: 1157 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 1158 | dev: true 1159 | 1160 | /combined-stream@1.0.8: 1161 | resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} 1162 | engines: {node: '>= 0.8'} 1163 | dependencies: 1164 | delayed-stream: 1.0.0 1165 | dev: true 1166 | 1167 | /concat-map@0.0.1: 1168 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} 1169 | dev: true 1170 | 1171 | /convert-source-map@2.0.0: 1172 | resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} 1173 | dev: true 1174 | 1175 | /create-jest@29.7.0(@types/node@18.19.50): 1176 | resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} 1177 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1178 | hasBin: true 1179 | dependencies: 1180 | '@jest/types': 29.6.3 1181 | chalk: 4.1.2 1182 | exit: 0.1.2 1183 | graceful-fs: 4.2.11 1184 | jest-config: 29.7.0(@types/node@18.19.50) 1185 | jest-util: 29.7.0 1186 | prompts: 2.4.2 1187 | transitivePeerDependencies: 1188 | - '@types/node' 1189 | - babel-plugin-macros 1190 | - supports-color 1191 | - ts-node 1192 | dev: true 1193 | 1194 | /cross-spawn@6.0.5: 1195 | resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==} 1196 | engines: {node: '>=4.8'} 1197 | dependencies: 1198 | nice-try: 1.0.5 1199 | path-key: 2.0.1 1200 | semver: 5.7.2 1201 | shebang-command: 1.2.0 1202 | which: 1.3.1 1203 | dev: true 1204 | 1205 | /cross-spawn@7.0.3: 1206 | resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} 1207 | engines: {node: '>= 8'} 1208 | dependencies: 1209 | path-key: 3.1.1 1210 | shebang-command: 2.0.0 1211 | which: 2.0.2 1212 | dev: true 1213 | 1214 | /debug@4.3.7: 1215 | resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} 1216 | engines: {node: '>=6.0'} 1217 | peerDependencies: 1218 | supports-color: '*' 1219 | peerDependenciesMeta: 1220 | supports-color: 1221 | optional: true 1222 | dependencies: 1223 | ms: 2.1.3 1224 | dev: true 1225 | 1226 | /decode-uri-component@0.2.2: 1227 | resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} 1228 | engines: {node: '>=0.10'} 1229 | dev: false 1230 | 1231 | /dedent@1.5.3: 1232 | resolution: {integrity: sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==} 1233 | peerDependencies: 1234 | babel-plugin-macros: ^3.1.0 1235 | peerDependenciesMeta: 1236 | babel-plugin-macros: 1237 | optional: true 1238 | dev: true 1239 | 1240 | /deep-is@0.1.4: 1241 | resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} 1242 | dev: true 1243 | 1244 | /deepmerge@4.3.1: 1245 | resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} 1246 | engines: {node: '>=0.10.0'} 1247 | dev: true 1248 | 1249 | /delayed-stream@1.0.0: 1250 | resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} 1251 | engines: {node: '>=0.4.0'} 1252 | dev: true 1253 | 1254 | /detect-newline@3.1.0: 1255 | resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} 1256 | engines: {node: '>=8'} 1257 | dev: true 1258 | 1259 | /diff-sequences@29.6.3: 1260 | resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} 1261 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1262 | dev: true 1263 | 1264 | /doctrine@3.0.0: 1265 | resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} 1266 | engines: {node: '>=6.0.0'} 1267 | dependencies: 1268 | esutils: 2.0.3 1269 | dev: true 1270 | 1271 | /ejs@3.1.10: 1272 | resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} 1273 | engines: {node: '>=0.10.0'} 1274 | hasBin: true 1275 | dependencies: 1276 | jake: 10.9.2 1277 | dev: true 1278 | 1279 | /electron-to-chromium@1.5.22: 1280 | resolution: {integrity: sha512-tKYm5YHPU1djz0O+CGJ+oJIvimtsCcwR2Z9w7Skh08lUdyzXY5djods3q+z2JkWdb7tCcmM//eVavSRAiaPRNg==} 1281 | dev: true 1282 | 1283 | /emittery@0.13.1: 1284 | resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} 1285 | engines: {node: '>=12'} 1286 | dev: true 1287 | 1288 | /emoji-regex@7.0.3: 1289 | resolution: {integrity: sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==} 1290 | dev: true 1291 | 1292 | /emoji-regex@8.0.0: 1293 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 1294 | dev: true 1295 | 1296 | /error-ex@1.3.2: 1297 | resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} 1298 | dependencies: 1299 | is-arrayish: 0.2.1 1300 | dev: true 1301 | 1302 | /escalade@3.2.0: 1303 | resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} 1304 | engines: {node: '>=6'} 1305 | dev: true 1306 | 1307 | /escape-string-regexp@1.0.5: 1308 | resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} 1309 | engines: {node: '>=0.8.0'} 1310 | dev: true 1311 | 1312 | /escape-string-regexp@2.0.0: 1313 | resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} 1314 | engines: {node: '>=8'} 1315 | dev: true 1316 | 1317 | /eslint-scope@5.1.1: 1318 | resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} 1319 | engines: {node: '>=8.0.0'} 1320 | dependencies: 1321 | esrecurse: 4.3.0 1322 | estraverse: 4.3.0 1323 | dev: true 1324 | 1325 | /eslint-utils@1.4.3: 1326 | resolution: {integrity: sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==} 1327 | engines: {node: '>=6'} 1328 | dependencies: 1329 | eslint-visitor-keys: 1.3.0 1330 | dev: true 1331 | 1332 | /eslint-utils@2.1.0: 1333 | resolution: {integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==} 1334 | engines: {node: '>=6'} 1335 | dependencies: 1336 | eslint-visitor-keys: 1.3.0 1337 | dev: true 1338 | 1339 | /eslint-visitor-keys@1.3.0: 1340 | resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==} 1341 | engines: {node: '>=4'} 1342 | dev: true 1343 | 1344 | /eslint@6.8.0: 1345 | resolution: {integrity: sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==} 1346 | engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} 1347 | hasBin: true 1348 | dependencies: 1349 | '@babel/code-frame': 7.24.7 1350 | ajv: 6.12.6 1351 | chalk: 2.4.2 1352 | cross-spawn: 6.0.5 1353 | debug: 4.3.7 1354 | doctrine: 3.0.0 1355 | eslint-scope: 5.1.1 1356 | eslint-utils: 1.4.3 1357 | eslint-visitor-keys: 1.3.0 1358 | espree: 6.2.1 1359 | esquery: 1.6.0 1360 | esutils: 2.0.3 1361 | file-entry-cache: 5.0.1 1362 | functional-red-black-tree: 1.0.1 1363 | glob-parent: 5.1.2 1364 | globals: 12.4.0 1365 | ignore: 4.0.6 1366 | import-fresh: 3.3.0 1367 | imurmurhash: 0.1.4 1368 | inquirer: 7.3.3 1369 | is-glob: 4.0.3 1370 | js-yaml: 3.14.1 1371 | json-stable-stringify-without-jsonify: 1.0.1 1372 | levn: 0.3.0 1373 | lodash: 4.17.21 1374 | minimatch: 3.1.2 1375 | mkdirp: 0.5.6 1376 | natural-compare: 1.4.0 1377 | optionator: 0.8.3 1378 | progress: 2.0.3 1379 | regexpp: 2.0.1 1380 | semver: 6.3.1 1381 | strip-ansi: 5.2.0 1382 | strip-json-comments: 3.1.1 1383 | table: 5.4.6 1384 | text-table: 0.2.0 1385 | v8-compile-cache: 2.4.0 1386 | transitivePeerDependencies: 1387 | - supports-color 1388 | dev: true 1389 | 1390 | /espree@6.2.1: 1391 | resolution: {integrity: sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==} 1392 | engines: {node: '>=6.0.0'} 1393 | dependencies: 1394 | acorn: 7.4.1 1395 | acorn-jsx: 5.3.2(acorn@7.4.1) 1396 | eslint-visitor-keys: 1.3.0 1397 | dev: true 1398 | 1399 | /esprima@4.0.1: 1400 | resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} 1401 | engines: {node: '>=4'} 1402 | hasBin: true 1403 | dev: true 1404 | 1405 | /esquery@1.6.0: 1406 | resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} 1407 | engines: {node: '>=0.10'} 1408 | dependencies: 1409 | estraverse: 5.3.0 1410 | dev: true 1411 | 1412 | /esrecurse@4.3.0: 1413 | resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} 1414 | engines: {node: '>=4.0'} 1415 | dependencies: 1416 | estraverse: 5.3.0 1417 | dev: true 1418 | 1419 | /estraverse@4.3.0: 1420 | resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} 1421 | engines: {node: '>=4.0'} 1422 | dev: true 1423 | 1424 | /estraverse@5.3.0: 1425 | resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} 1426 | engines: {node: '>=4.0'} 1427 | dev: true 1428 | 1429 | /esutils@2.0.3: 1430 | resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} 1431 | engines: {node: '>=0.10.0'} 1432 | dev: true 1433 | 1434 | /execa@5.1.1: 1435 | resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} 1436 | engines: {node: '>=10'} 1437 | dependencies: 1438 | cross-spawn: 7.0.3 1439 | get-stream: 6.0.1 1440 | human-signals: 2.1.0 1441 | is-stream: 2.0.1 1442 | merge-stream: 2.0.0 1443 | npm-run-path: 4.0.1 1444 | onetime: 5.1.2 1445 | signal-exit: 3.0.7 1446 | strip-final-newline: 2.0.0 1447 | dev: true 1448 | 1449 | /exit@0.1.2: 1450 | resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} 1451 | engines: {node: '>= 0.8.0'} 1452 | dev: true 1453 | 1454 | /expect@29.7.0: 1455 | resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} 1456 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1457 | dependencies: 1458 | '@jest/expect-utils': 29.7.0 1459 | jest-get-type: 29.6.3 1460 | jest-matcher-utils: 29.7.0 1461 | jest-message-util: 29.7.0 1462 | jest-util: 29.7.0 1463 | dev: true 1464 | 1465 | /external-editor@3.1.0: 1466 | resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} 1467 | engines: {node: '>=4'} 1468 | dependencies: 1469 | chardet: 0.7.0 1470 | iconv-lite: 0.4.24 1471 | tmp: 0.0.33 1472 | dev: true 1473 | 1474 | /fast-deep-equal@3.1.3: 1475 | resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 1476 | dev: true 1477 | 1478 | /fast-json-stable-stringify@2.1.0: 1479 | resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} 1480 | dev: true 1481 | 1482 | /fast-levenshtein@2.0.6: 1483 | resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} 1484 | dev: true 1485 | 1486 | /fb-watchman@2.0.2: 1487 | resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} 1488 | dependencies: 1489 | bser: 2.1.1 1490 | dev: true 1491 | 1492 | /figures@3.2.0: 1493 | resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} 1494 | engines: {node: '>=8'} 1495 | dependencies: 1496 | escape-string-regexp: 1.0.5 1497 | dev: true 1498 | 1499 | /file-entry-cache@5.0.1: 1500 | resolution: {integrity: sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==} 1501 | engines: {node: '>=4'} 1502 | dependencies: 1503 | flat-cache: 2.0.1 1504 | dev: true 1505 | 1506 | /filelist@1.0.4: 1507 | resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} 1508 | dependencies: 1509 | minimatch: 5.1.6 1510 | dev: true 1511 | 1512 | /fill-range@7.1.1: 1513 | resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} 1514 | engines: {node: '>=8'} 1515 | dependencies: 1516 | to-regex-range: 5.0.1 1517 | dev: true 1518 | 1519 | /filter-obj@1.1.0: 1520 | resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==} 1521 | engines: {node: '>=0.10.0'} 1522 | dev: false 1523 | 1524 | /find-up@4.1.0: 1525 | resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} 1526 | engines: {node: '>=8'} 1527 | dependencies: 1528 | locate-path: 5.0.0 1529 | path-exists: 4.0.0 1530 | dev: true 1531 | 1532 | /flat-cache@2.0.1: 1533 | resolution: {integrity: sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==} 1534 | engines: {node: '>=4'} 1535 | dependencies: 1536 | flatted: 2.0.2 1537 | rimraf: 2.6.3 1538 | write: 1.0.3 1539 | dev: true 1540 | 1541 | /flatted@2.0.2: 1542 | resolution: {integrity: sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==} 1543 | dev: true 1544 | 1545 | /form-data@4.0.0: 1546 | resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} 1547 | engines: {node: '>= 6'} 1548 | dependencies: 1549 | asynckit: 0.4.0 1550 | combined-stream: 1.0.8 1551 | mime-types: 2.1.35 1552 | dev: true 1553 | 1554 | /fs.realpath@1.0.0: 1555 | resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} 1556 | dev: true 1557 | 1558 | /fsevents@2.3.3: 1559 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 1560 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 1561 | os: [darwin] 1562 | requiresBuild: true 1563 | dev: true 1564 | optional: true 1565 | 1566 | /function-bind@1.1.2: 1567 | resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 1568 | dev: true 1569 | 1570 | /functional-red-black-tree@1.0.1: 1571 | resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} 1572 | dev: true 1573 | 1574 | /gensync@1.0.0-beta.2: 1575 | resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} 1576 | engines: {node: '>=6.9.0'} 1577 | dev: true 1578 | 1579 | /get-caller-file@2.0.5: 1580 | resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} 1581 | engines: {node: 6.* || 8.* || >= 10.*} 1582 | dev: true 1583 | 1584 | /get-package-type@0.1.0: 1585 | resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} 1586 | engines: {node: '>=8.0.0'} 1587 | dev: true 1588 | 1589 | /get-stream@6.0.1: 1590 | resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} 1591 | engines: {node: '>=10'} 1592 | dev: true 1593 | 1594 | /glob-parent@5.1.2: 1595 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 1596 | engines: {node: '>= 6'} 1597 | dependencies: 1598 | is-glob: 4.0.3 1599 | dev: true 1600 | 1601 | /glob@7.2.3: 1602 | resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} 1603 | deprecated: Glob versions prior to v9 are no longer supported 1604 | dependencies: 1605 | fs.realpath: 1.0.0 1606 | inflight: 1.0.6 1607 | inherits: 2.0.4 1608 | minimatch: 3.1.2 1609 | once: 1.4.0 1610 | path-is-absolute: 1.0.1 1611 | dev: true 1612 | 1613 | /globals@11.12.0: 1614 | resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} 1615 | engines: {node: '>=4'} 1616 | dev: true 1617 | 1618 | /globals@12.4.0: 1619 | resolution: {integrity: sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==} 1620 | engines: {node: '>=8'} 1621 | dependencies: 1622 | type-fest: 0.8.1 1623 | dev: true 1624 | 1625 | /graceful-fs@4.2.11: 1626 | resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} 1627 | dev: true 1628 | 1629 | /has-flag@3.0.0: 1630 | resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} 1631 | engines: {node: '>=4'} 1632 | dev: true 1633 | 1634 | /has-flag@4.0.0: 1635 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 1636 | engines: {node: '>=8'} 1637 | dev: true 1638 | 1639 | /hasown@2.0.2: 1640 | resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} 1641 | engines: {node: '>= 0.4'} 1642 | dependencies: 1643 | function-bind: 1.1.2 1644 | dev: true 1645 | 1646 | /html-escaper@2.0.2: 1647 | resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} 1648 | dev: true 1649 | 1650 | /human-signals@2.1.0: 1651 | resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} 1652 | engines: {node: '>=10.17.0'} 1653 | dev: true 1654 | 1655 | /i@0.3.7: 1656 | resolution: {integrity: sha512-FYz4wlXgkQwIPqhzC5TdNMLSE5+GS1IIDJZY/1ZiEPCT2S3COUVZeT5OW4BmW4r5LHLQuOosSwsvnroG9GR59Q==} 1657 | engines: {node: '>=0.4'} 1658 | dev: true 1659 | 1660 | /iconv-lite@0.4.24: 1661 | resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} 1662 | engines: {node: '>=0.10.0'} 1663 | dependencies: 1664 | safer-buffer: 2.1.2 1665 | dev: true 1666 | 1667 | /ignore@4.0.6: 1668 | resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} 1669 | engines: {node: '>= 4'} 1670 | dev: true 1671 | 1672 | /import-fresh@3.3.0: 1673 | resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} 1674 | engines: {node: '>=6'} 1675 | dependencies: 1676 | parent-module: 1.0.1 1677 | resolve-from: 4.0.0 1678 | dev: true 1679 | 1680 | /import-local@3.2.0: 1681 | resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} 1682 | engines: {node: '>=8'} 1683 | hasBin: true 1684 | dependencies: 1685 | pkg-dir: 4.2.0 1686 | resolve-cwd: 3.0.0 1687 | dev: true 1688 | 1689 | /imurmurhash@0.1.4: 1690 | resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} 1691 | engines: {node: '>=0.8.19'} 1692 | dev: true 1693 | 1694 | /inflight@1.0.6: 1695 | resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} 1696 | deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. 1697 | dependencies: 1698 | once: 1.4.0 1699 | wrappy: 1.0.2 1700 | dev: true 1701 | 1702 | /inherits@2.0.4: 1703 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 1704 | dev: true 1705 | 1706 | /inquirer@7.3.3: 1707 | resolution: {integrity: sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==} 1708 | engines: {node: '>=8.0.0'} 1709 | dependencies: 1710 | ansi-escapes: 4.3.2 1711 | chalk: 4.1.2 1712 | cli-cursor: 3.1.0 1713 | cli-width: 3.0.0 1714 | external-editor: 3.1.0 1715 | figures: 3.2.0 1716 | lodash: 4.17.21 1717 | mute-stream: 0.0.8 1718 | run-async: 2.4.1 1719 | rxjs: 6.6.7 1720 | string-width: 4.2.3 1721 | strip-ansi: 6.0.1 1722 | through: 2.3.8 1723 | dev: true 1724 | 1725 | /is-arrayish@0.2.1: 1726 | resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} 1727 | dev: true 1728 | 1729 | /is-core-module@2.15.1: 1730 | resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} 1731 | engines: {node: '>= 0.4'} 1732 | dependencies: 1733 | hasown: 2.0.2 1734 | dev: true 1735 | 1736 | /is-extglob@2.1.1: 1737 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 1738 | engines: {node: '>=0.10.0'} 1739 | dev: true 1740 | 1741 | /is-fullwidth-code-point@2.0.0: 1742 | resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==} 1743 | engines: {node: '>=4'} 1744 | dev: true 1745 | 1746 | /is-fullwidth-code-point@3.0.0: 1747 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 1748 | engines: {node: '>=8'} 1749 | dev: true 1750 | 1751 | /is-generator-fn@2.1.0: 1752 | resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} 1753 | engines: {node: '>=6'} 1754 | dev: true 1755 | 1756 | /is-glob@4.0.3: 1757 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 1758 | engines: {node: '>=0.10.0'} 1759 | dependencies: 1760 | is-extglob: 2.1.1 1761 | dev: true 1762 | 1763 | /is-number@7.0.0: 1764 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 1765 | engines: {node: '>=0.12.0'} 1766 | dev: true 1767 | 1768 | /is-stream@2.0.1: 1769 | resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} 1770 | engines: {node: '>=8'} 1771 | dev: true 1772 | 1773 | /isexe@2.0.0: 1774 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 1775 | dev: true 1776 | 1777 | /istanbul-lib-coverage@3.2.2: 1778 | resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} 1779 | engines: {node: '>=8'} 1780 | dev: true 1781 | 1782 | /istanbul-lib-instrument@5.2.1: 1783 | resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} 1784 | engines: {node: '>=8'} 1785 | dependencies: 1786 | '@babel/core': 7.25.2 1787 | '@babel/parser': 7.25.6 1788 | '@istanbuljs/schema': 0.1.3 1789 | istanbul-lib-coverage: 3.2.2 1790 | semver: 6.3.1 1791 | transitivePeerDependencies: 1792 | - supports-color 1793 | dev: true 1794 | 1795 | /istanbul-lib-instrument@6.0.3: 1796 | resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} 1797 | engines: {node: '>=10'} 1798 | dependencies: 1799 | '@babel/core': 7.25.2 1800 | '@babel/parser': 7.25.6 1801 | '@istanbuljs/schema': 0.1.3 1802 | istanbul-lib-coverage: 3.2.2 1803 | semver: 7.6.3 1804 | transitivePeerDependencies: 1805 | - supports-color 1806 | dev: true 1807 | 1808 | /istanbul-lib-report@3.0.1: 1809 | resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} 1810 | engines: {node: '>=10'} 1811 | dependencies: 1812 | istanbul-lib-coverage: 3.2.2 1813 | make-dir: 4.0.0 1814 | supports-color: 7.2.0 1815 | dev: true 1816 | 1817 | /istanbul-lib-source-maps@4.0.1: 1818 | resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} 1819 | engines: {node: '>=10'} 1820 | dependencies: 1821 | debug: 4.3.7 1822 | istanbul-lib-coverage: 3.2.2 1823 | source-map: 0.6.1 1824 | transitivePeerDependencies: 1825 | - supports-color 1826 | dev: true 1827 | 1828 | /istanbul-reports@3.1.7: 1829 | resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} 1830 | engines: {node: '>=8'} 1831 | dependencies: 1832 | html-escaper: 2.0.2 1833 | istanbul-lib-report: 3.0.1 1834 | dev: true 1835 | 1836 | /jake@10.9.2: 1837 | resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==} 1838 | engines: {node: '>=10'} 1839 | hasBin: true 1840 | dependencies: 1841 | async: 3.2.6 1842 | chalk: 4.1.2 1843 | filelist: 1.0.4 1844 | minimatch: 3.1.2 1845 | dev: true 1846 | 1847 | /jest-changed-files@29.7.0: 1848 | resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} 1849 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1850 | dependencies: 1851 | execa: 5.1.1 1852 | jest-util: 29.7.0 1853 | p-limit: 3.1.0 1854 | dev: true 1855 | 1856 | /jest-circus@29.7.0: 1857 | resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} 1858 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1859 | dependencies: 1860 | '@jest/environment': 29.7.0 1861 | '@jest/expect': 29.7.0 1862 | '@jest/test-result': 29.7.0 1863 | '@jest/types': 29.6.3 1864 | '@types/node': 18.19.50 1865 | chalk: 4.1.2 1866 | co: 4.6.0 1867 | dedent: 1.5.3 1868 | is-generator-fn: 2.1.0 1869 | jest-each: 29.7.0 1870 | jest-matcher-utils: 29.7.0 1871 | jest-message-util: 29.7.0 1872 | jest-runtime: 29.7.0 1873 | jest-snapshot: 29.7.0 1874 | jest-util: 29.7.0 1875 | p-limit: 3.1.0 1876 | pretty-format: 29.7.0 1877 | pure-rand: 6.1.0 1878 | slash: 3.0.0 1879 | stack-utils: 2.0.6 1880 | transitivePeerDependencies: 1881 | - babel-plugin-macros 1882 | - supports-color 1883 | dev: true 1884 | 1885 | /jest-cli@29.7.0(@types/node@18.19.50): 1886 | resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} 1887 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1888 | hasBin: true 1889 | peerDependencies: 1890 | node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 1891 | peerDependenciesMeta: 1892 | node-notifier: 1893 | optional: true 1894 | dependencies: 1895 | '@jest/core': 29.7.0 1896 | '@jest/test-result': 29.7.0 1897 | '@jest/types': 29.6.3 1898 | chalk: 4.1.2 1899 | create-jest: 29.7.0(@types/node@18.19.50) 1900 | exit: 0.1.2 1901 | import-local: 3.2.0 1902 | jest-config: 29.7.0(@types/node@18.19.50) 1903 | jest-util: 29.7.0 1904 | jest-validate: 29.7.0 1905 | yargs: 17.7.2 1906 | transitivePeerDependencies: 1907 | - '@types/node' 1908 | - babel-plugin-macros 1909 | - supports-color 1910 | - ts-node 1911 | dev: true 1912 | 1913 | /jest-config@29.7.0(@types/node@18.19.50): 1914 | resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} 1915 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1916 | peerDependencies: 1917 | '@types/node': '*' 1918 | ts-node: '>=9.0.0' 1919 | peerDependenciesMeta: 1920 | '@types/node': 1921 | optional: true 1922 | ts-node: 1923 | optional: true 1924 | dependencies: 1925 | '@babel/core': 7.25.2 1926 | '@jest/test-sequencer': 29.7.0 1927 | '@jest/types': 29.6.3 1928 | '@types/node': 18.19.50 1929 | babel-jest: 29.7.0(@babel/core@7.25.2) 1930 | chalk: 4.1.2 1931 | ci-info: 3.9.0 1932 | deepmerge: 4.3.1 1933 | glob: 7.2.3 1934 | graceful-fs: 4.2.11 1935 | jest-circus: 29.7.0 1936 | jest-environment-node: 29.7.0 1937 | jest-get-type: 29.6.3 1938 | jest-regex-util: 29.6.3 1939 | jest-resolve: 29.7.0 1940 | jest-runner: 29.7.0 1941 | jest-util: 29.7.0 1942 | jest-validate: 29.7.0 1943 | micromatch: 4.0.8 1944 | parse-json: 5.2.0 1945 | pretty-format: 29.7.0 1946 | slash: 3.0.0 1947 | strip-json-comments: 3.1.1 1948 | transitivePeerDependencies: 1949 | - babel-plugin-macros 1950 | - supports-color 1951 | dev: true 1952 | 1953 | /jest-diff@29.7.0: 1954 | resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} 1955 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1956 | dependencies: 1957 | chalk: 4.1.2 1958 | diff-sequences: 29.6.3 1959 | jest-get-type: 29.6.3 1960 | pretty-format: 29.7.0 1961 | dev: true 1962 | 1963 | /jest-docblock@29.7.0: 1964 | resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} 1965 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1966 | dependencies: 1967 | detect-newline: 3.1.0 1968 | dev: true 1969 | 1970 | /jest-each@29.7.0: 1971 | resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} 1972 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1973 | dependencies: 1974 | '@jest/types': 29.6.3 1975 | chalk: 4.1.2 1976 | jest-get-type: 29.6.3 1977 | jest-util: 29.7.0 1978 | pretty-format: 29.7.0 1979 | dev: true 1980 | 1981 | /jest-environment-node@29.7.0: 1982 | resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} 1983 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1984 | dependencies: 1985 | '@jest/environment': 29.7.0 1986 | '@jest/fake-timers': 29.7.0 1987 | '@jest/types': 29.6.3 1988 | '@types/node': 18.19.50 1989 | jest-mock: 29.7.0 1990 | jest-util: 29.7.0 1991 | dev: true 1992 | 1993 | /jest-get-type@29.6.3: 1994 | resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} 1995 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 1996 | dev: true 1997 | 1998 | /jest-haste-map@29.7.0: 1999 | resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} 2000 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 2001 | dependencies: 2002 | '@jest/types': 29.6.3 2003 | '@types/graceful-fs': 4.1.9 2004 | '@types/node': 18.19.50 2005 | anymatch: 3.1.3 2006 | fb-watchman: 2.0.2 2007 | graceful-fs: 4.2.11 2008 | jest-regex-util: 29.6.3 2009 | jest-util: 29.7.0 2010 | jest-worker: 29.7.0 2011 | micromatch: 4.0.8 2012 | walker: 1.0.8 2013 | optionalDependencies: 2014 | fsevents: 2.3.3 2015 | dev: true 2016 | 2017 | /jest-leak-detector@29.7.0: 2018 | resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} 2019 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 2020 | dependencies: 2021 | jest-get-type: 29.6.3 2022 | pretty-format: 29.7.0 2023 | dev: true 2024 | 2025 | /jest-matcher-utils@29.7.0: 2026 | resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} 2027 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 2028 | dependencies: 2029 | chalk: 4.1.2 2030 | jest-diff: 29.7.0 2031 | jest-get-type: 29.6.3 2032 | pretty-format: 29.7.0 2033 | dev: true 2034 | 2035 | /jest-message-util@29.7.0: 2036 | resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} 2037 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 2038 | dependencies: 2039 | '@babel/code-frame': 7.24.7 2040 | '@jest/types': 29.6.3 2041 | '@types/stack-utils': 2.0.3 2042 | chalk: 4.1.2 2043 | graceful-fs: 4.2.11 2044 | micromatch: 4.0.8 2045 | pretty-format: 29.7.0 2046 | slash: 3.0.0 2047 | stack-utils: 2.0.6 2048 | dev: true 2049 | 2050 | /jest-mock@29.7.0: 2051 | resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} 2052 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 2053 | dependencies: 2054 | '@jest/types': 29.6.3 2055 | '@types/node': 18.19.50 2056 | jest-util: 29.7.0 2057 | dev: true 2058 | 2059 | /jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): 2060 | resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} 2061 | engines: {node: '>=6'} 2062 | peerDependencies: 2063 | jest-resolve: '*' 2064 | peerDependenciesMeta: 2065 | jest-resolve: 2066 | optional: true 2067 | dependencies: 2068 | jest-resolve: 29.7.0 2069 | dev: true 2070 | 2071 | /jest-regex-util@29.6.3: 2072 | resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} 2073 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 2074 | dev: true 2075 | 2076 | /jest-resolve-dependencies@29.7.0: 2077 | resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} 2078 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 2079 | dependencies: 2080 | jest-regex-util: 29.6.3 2081 | jest-snapshot: 29.7.0 2082 | transitivePeerDependencies: 2083 | - supports-color 2084 | dev: true 2085 | 2086 | /jest-resolve@29.7.0: 2087 | resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} 2088 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 2089 | dependencies: 2090 | chalk: 4.1.2 2091 | graceful-fs: 4.2.11 2092 | jest-haste-map: 29.7.0 2093 | jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) 2094 | jest-util: 29.7.0 2095 | jest-validate: 29.7.0 2096 | resolve: 1.22.8 2097 | resolve.exports: 2.0.2 2098 | slash: 3.0.0 2099 | dev: true 2100 | 2101 | /jest-runner@29.7.0: 2102 | resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} 2103 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 2104 | dependencies: 2105 | '@jest/console': 29.7.0 2106 | '@jest/environment': 29.7.0 2107 | '@jest/test-result': 29.7.0 2108 | '@jest/transform': 29.7.0 2109 | '@jest/types': 29.6.3 2110 | '@types/node': 18.19.50 2111 | chalk: 4.1.2 2112 | emittery: 0.13.1 2113 | graceful-fs: 4.2.11 2114 | jest-docblock: 29.7.0 2115 | jest-environment-node: 29.7.0 2116 | jest-haste-map: 29.7.0 2117 | jest-leak-detector: 29.7.0 2118 | jest-message-util: 29.7.0 2119 | jest-resolve: 29.7.0 2120 | jest-runtime: 29.7.0 2121 | jest-util: 29.7.0 2122 | jest-watcher: 29.7.0 2123 | jest-worker: 29.7.0 2124 | p-limit: 3.1.0 2125 | source-map-support: 0.5.13 2126 | transitivePeerDependencies: 2127 | - supports-color 2128 | dev: true 2129 | 2130 | /jest-runtime@29.7.0: 2131 | resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} 2132 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 2133 | dependencies: 2134 | '@jest/environment': 29.7.0 2135 | '@jest/fake-timers': 29.7.0 2136 | '@jest/globals': 29.7.0 2137 | '@jest/source-map': 29.6.3 2138 | '@jest/test-result': 29.7.0 2139 | '@jest/transform': 29.7.0 2140 | '@jest/types': 29.6.3 2141 | '@types/node': 18.19.50 2142 | chalk: 4.1.2 2143 | cjs-module-lexer: 1.4.1 2144 | collect-v8-coverage: 1.0.2 2145 | glob: 7.2.3 2146 | graceful-fs: 4.2.11 2147 | jest-haste-map: 29.7.0 2148 | jest-message-util: 29.7.0 2149 | jest-mock: 29.7.0 2150 | jest-regex-util: 29.6.3 2151 | jest-resolve: 29.7.0 2152 | jest-snapshot: 29.7.0 2153 | jest-util: 29.7.0 2154 | slash: 3.0.0 2155 | strip-bom: 4.0.0 2156 | transitivePeerDependencies: 2157 | - supports-color 2158 | dev: true 2159 | 2160 | /jest-snapshot@29.7.0: 2161 | resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} 2162 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 2163 | dependencies: 2164 | '@babel/core': 7.25.2 2165 | '@babel/generator': 7.25.6 2166 | '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.25.2) 2167 | '@babel/plugin-syntax-typescript': 7.25.4(@babel/core@7.25.2) 2168 | '@babel/types': 7.25.6 2169 | '@jest/expect-utils': 29.7.0 2170 | '@jest/transform': 29.7.0 2171 | '@jest/types': 29.6.3 2172 | babel-preset-current-node-syntax: 1.1.0(@babel/core@7.25.2) 2173 | chalk: 4.1.2 2174 | expect: 29.7.0 2175 | graceful-fs: 4.2.11 2176 | jest-diff: 29.7.0 2177 | jest-get-type: 29.6.3 2178 | jest-matcher-utils: 29.7.0 2179 | jest-message-util: 29.7.0 2180 | jest-util: 29.7.0 2181 | natural-compare: 1.4.0 2182 | pretty-format: 29.7.0 2183 | semver: 7.6.3 2184 | transitivePeerDependencies: 2185 | - supports-color 2186 | dev: true 2187 | 2188 | /jest-util@29.7.0: 2189 | resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} 2190 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 2191 | dependencies: 2192 | '@jest/types': 29.6.3 2193 | '@types/node': 18.19.50 2194 | chalk: 4.1.2 2195 | ci-info: 3.9.0 2196 | graceful-fs: 4.2.11 2197 | picomatch: 2.3.1 2198 | dev: true 2199 | 2200 | /jest-validate@29.7.0: 2201 | resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} 2202 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 2203 | dependencies: 2204 | '@jest/types': 29.6.3 2205 | camelcase: 6.3.0 2206 | chalk: 4.1.2 2207 | jest-get-type: 29.6.3 2208 | leven: 3.1.0 2209 | pretty-format: 29.7.0 2210 | dev: true 2211 | 2212 | /jest-watcher@29.7.0: 2213 | resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} 2214 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 2215 | dependencies: 2216 | '@jest/test-result': 29.7.0 2217 | '@jest/types': 29.6.3 2218 | '@types/node': 18.19.50 2219 | ansi-escapes: 4.3.2 2220 | chalk: 4.1.2 2221 | emittery: 0.13.1 2222 | jest-util: 29.7.0 2223 | string-length: 4.0.2 2224 | dev: true 2225 | 2226 | /jest-worker@29.7.0: 2227 | resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} 2228 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 2229 | dependencies: 2230 | '@types/node': 18.19.50 2231 | jest-util: 29.7.0 2232 | merge-stream: 2.0.0 2233 | supports-color: 8.1.1 2234 | dev: true 2235 | 2236 | /jest@29.7.0(@types/node@18.19.50): 2237 | resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} 2238 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 2239 | hasBin: true 2240 | peerDependencies: 2241 | node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 2242 | peerDependenciesMeta: 2243 | node-notifier: 2244 | optional: true 2245 | dependencies: 2246 | '@jest/core': 29.7.0 2247 | '@jest/types': 29.6.3 2248 | import-local: 3.2.0 2249 | jest-cli: 29.7.0(@types/node@18.19.50) 2250 | transitivePeerDependencies: 2251 | - '@types/node' 2252 | - babel-plugin-macros 2253 | - supports-color 2254 | - ts-node 2255 | dev: true 2256 | 2257 | /js-tokens@4.0.0: 2258 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} 2259 | dev: true 2260 | 2261 | /js-yaml@3.14.1: 2262 | resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} 2263 | hasBin: true 2264 | dependencies: 2265 | argparse: 1.0.10 2266 | esprima: 4.0.1 2267 | dev: true 2268 | 2269 | /jsesc@2.5.2: 2270 | resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} 2271 | engines: {node: '>=4'} 2272 | hasBin: true 2273 | dev: true 2274 | 2275 | /json-parse-even-better-errors@2.3.1: 2276 | resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} 2277 | dev: true 2278 | 2279 | /json-schema-traverse@0.4.1: 2280 | resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} 2281 | dev: true 2282 | 2283 | /json-stable-stringify-without-jsonify@1.0.1: 2284 | resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} 2285 | dev: true 2286 | 2287 | /json5@2.2.3: 2288 | resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} 2289 | engines: {node: '>=6'} 2290 | hasBin: true 2291 | dev: true 2292 | 2293 | /kleur@3.0.3: 2294 | resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} 2295 | engines: {node: '>=6'} 2296 | dev: true 2297 | 2298 | /leven@3.1.0: 2299 | resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} 2300 | engines: {node: '>=6'} 2301 | dev: true 2302 | 2303 | /levn@0.3.0: 2304 | resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==} 2305 | engines: {node: '>= 0.8.0'} 2306 | dependencies: 2307 | prelude-ls: 1.1.2 2308 | type-check: 0.3.2 2309 | dev: true 2310 | 2311 | /lines-and-columns@1.2.4: 2312 | resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} 2313 | dev: true 2314 | 2315 | /locate-path@5.0.0: 2316 | resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} 2317 | engines: {node: '>=8'} 2318 | dependencies: 2319 | p-locate: 4.1.0 2320 | dev: true 2321 | 2322 | /lodash.memoize@4.1.2: 2323 | resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} 2324 | dev: true 2325 | 2326 | /lodash@4.17.21: 2327 | resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} 2328 | dev: true 2329 | 2330 | /lru-cache@5.1.1: 2331 | resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} 2332 | dependencies: 2333 | yallist: 3.1.1 2334 | dev: true 2335 | 2336 | /make-dir@4.0.0: 2337 | resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} 2338 | engines: {node: '>=10'} 2339 | dependencies: 2340 | semver: 7.6.3 2341 | dev: true 2342 | 2343 | /make-error@1.3.6: 2344 | resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} 2345 | dev: true 2346 | 2347 | /makeerror@1.0.12: 2348 | resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} 2349 | dependencies: 2350 | tmpl: 1.0.5 2351 | dev: true 2352 | 2353 | /merge-stream@2.0.0: 2354 | resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} 2355 | dev: true 2356 | 2357 | /micromatch@4.0.8: 2358 | resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} 2359 | engines: {node: '>=8.6'} 2360 | dependencies: 2361 | braces: 3.0.3 2362 | picomatch: 2.3.1 2363 | dev: true 2364 | 2365 | /mime-db@1.52.0: 2366 | resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} 2367 | engines: {node: '>= 0.6'} 2368 | dev: true 2369 | 2370 | /mime-types@2.1.35: 2371 | resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} 2372 | engines: {node: '>= 0.6'} 2373 | dependencies: 2374 | mime-db: 1.52.0 2375 | dev: true 2376 | 2377 | /mimic-fn@2.1.0: 2378 | resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} 2379 | engines: {node: '>=6'} 2380 | dev: true 2381 | 2382 | /minimatch@3.1.2: 2383 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} 2384 | dependencies: 2385 | brace-expansion: 1.1.11 2386 | dev: true 2387 | 2388 | /minimatch@5.1.6: 2389 | resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} 2390 | engines: {node: '>=10'} 2391 | dependencies: 2392 | brace-expansion: 2.0.1 2393 | dev: true 2394 | 2395 | /minimist@1.2.8: 2396 | resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} 2397 | dev: true 2398 | 2399 | /mkdirp@0.5.6: 2400 | resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} 2401 | hasBin: true 2402 | dependencies: 2403 | minimist: 1.2.8 2404 | dev: true 2405 | 2406 | /ms@2.1.3: 2407 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 2408 | dev: true 2409 | 2410 | /mute-stream@0.0.8: 2411 | resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} 2412 | dev: true 2413 | 2414 | /natural-compare@1.4.0: 2415 | resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} 2416 | dev: true 2417 | 2418 | /nice-try@1.0.5: 2419 | resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} 2420 | dev: true 2421 | 2422 | /node-fetch@2.7.0: 2423 | resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} 2424 | engines: {node: 4.x || >=6.0.0} 2425 | peerDependencies: 2426 | encoding: ^0.1.0 2427 | peerDependenciesMeta: 2428 | encoding: 2429 | optional: true 2430 | dependencies: 2431 | whatwg-url: 5.0.0 2432 | dev: false 2433 | 2434 | /node-int64@0.4.0: 2435 | resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} 2436 | dev: true 2437 | 2438 | /node-releases@2.0.18: 2439 | resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} 2440 | dev: true 2441 | 2442 | /normalize-path@3.0.0: 2443 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} 2444 | engines: {node: '>=0.10.0'} 2445 | dev: true 2446 | 2447 | /npm-run-path@4.0.1: 2448 | resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} 2449 | engines: {node: '>=8'} 2450 | dependencies: 2451 | path-key: 3.1.1 2452 | dev: true 2453 | 2454 | /npm@8.19.4: 2455 | resolution: {integrity: sha512-3HANl8i9DKnUA89P4KEgVNN28EjSeDCmvEqbzOAuxCFDzdBZzjUl99zgnGpOUumvW5lvJo2HKcjrsc+tfyv1Hw==} 2456 | engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} 2457 | hasBin: true 2458 | dev: true 2459 | bundledDependencies: 2460 | - '@isaacs/string-locale-compare' 2461 | - '@npmcli/arborist' 2462 | - '@npmcli/ci-detect' 2463 | - '@npmcli/config' 2464 | - '@npmcli/fs' 2465 | - '@npmcli/map-workspaces' 2466 | - '@npmcli/package-json' 2467 | - '@npmcli/run-script' 2468 | - abbrev 2469 | - archy 2470 | - cacache 2471 | - chalk 2472 | - chownr 2473 | - cli-columns 2474 | - cli-table3 2475 | - columnify 2476 | - fastest-levenshtein 2477 | - fs-minipass 2478 | - glob 2479 | - graceful-fs 2480 | - hosted-git-info 2481 | - ini 2482 | - init-package-json 2483 | - is-cidr 2484 | - json-parse-even-better-errors 2485 | - libnpmaccess 2486 | - libnpmdiff 2487 | - libnpmexec 2488 | - libnpmfund 2489 | - libnpmhook 2490 | - libnpmorg 2491 | - libnpmpack 2492 | - libnpmpublish 2493 | - libnpmsearch 2494 | - libnpmteam 2495 | - libnpmversion 2496 | - make-fetch-happen 2497 | - minimatch 2498 | - minipass 2499 | - minipass-pipeline 2500 | - mkdirp 2501 | - mkdirp-infer-owner 2502 | - ms 2503 | - node-gyp 2504 | - nopt 2505 | - npm-audit-report 2506 | - npm-install-checks 2507 | - npm-package-arg 2508 | - npm-pick-manifest 2509 | - npm-profile 2510 | - npm-registry-fetch 2511 | - npm-user-validate 2512 | - npmlog 2513 | - opener 2514 | - p-map 2515 | - pacote 2516 | - parse-conflict-json 2517 | - proc-log 2518 | - qrcode-terminal 2519 | - read 2520 | - read-package-json 2521 | - read-package-json-fast 2522 | - readdir-scoped-modules 2523 | - rimraf 2524 | - semver 2525 | - ssri 2526 | - tar 2527 | - text-table 2528 | - tiny-relative-date 2529 | - treeverse 2530 | - validate-npm-package-name 2531 | - which 2532 | - write-file-atomic 2533 | 2534 | /once@1.4.0: 2535 | resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} 2536 | dependencies: 2537 | wrappy: 1.0.2 2538 | dev: true 2539 | 2540 | /onetime@5.1.2: 2541 | resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} 2542 | engines: {node: '>=6'} 2543 | dependencies: 2544 | mimic-fn: 2.1.0 2545 | dev: true 2546 | 2547 | /optionator@0.8.3: 2548 | resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==} 2549 | engines: {node: '>= 0.8.0'} 2550 | dependencies: 2551 | deep-is: 0.1.4 2552 | fast-levenshtein: 2.0.6 2553 | levn: 0.3.0 2554 | prelude-ls: 1.1.2 2555 | type-check: 0.3.2 2556 | word-wrap: 1.2.5 2557 | dev: true 2558 | 2559 | /os-tmpdir@1.0.2: 2560 | resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} 2561 | engines: {node: '>=0.10.0'} 2562 | dev: true 2563 | 2564 | /p-limit@2.3.0: 2565 | resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} 2566 | engines: {node: '>=6'} 2567 | dependencies: 2568 | p-try: 2.2.0 2569 | dev: true 2570 | 2571 | /p-limit@3.1.0: 2572 | resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} 2573 | engines: {node: '>=10'} 2574 | dependencies: 2575 | yocto-queue: 0.1.0 2576 | dev: true 2577 | 2578 | /p-locate@4.1.0: 2579 | resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} 2580 | engines: {node: '>=8'} 2581 | dependencies: 2582 | p-limit: 2.3.0 2583 | dev: true 2584 | 2585 | /p-try@2.2.0: 2586 | resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} 2587 | engines: {node: '>=6'} 2588 | dev: true 2589 | 2590 | /parent-module@1.0.1: 2591 | resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} 2592 | engines: {node: '>=6'} 2593 | dependencies: 2594 | callsites: 3.1.0 2595 | dev: true 2596 | 2597 | /parse-json@5.2.0: 2598 | resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} 2599 | engines: {node: '>=8'} 2600 | dependencies: 2601 | '@babel/code-frame': 7.24.7 2602 | error-ex: 1.3.2 2603 | json-parse-even-better-errors: 2.3.1 2604 | lines-and-columns: 1.2.4 2605 | dev: true 2606 | 2607 | /path-exists@4.0.0: 2608 | resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} 2609 | engines: {node: '>=8'} 2610 | dev: true 2611 | 2612 | /path-is-absolute@1.0.1: 2613 | resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} 2614 | engines: {node: '>=0.10.0'} 2615 | dev: true 2616 | 2617 | /path-key@2.0.1: 2618 | resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==} 2619 | engines: {node: '>=4'} 2620 | dev: true 2621 | 2622 | /path-key@3.1.1: 2623 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 2624 | engines: {node: '>=8'} 2625 | dev: true 2626 | 2627 | /path-parse@1.0.7: 2628 | resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} 2629 | dev: true 2630 | 2631 | /picocolors@1.1.0: 2632 | resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} 2633 | dev: true 2634 | 2635 | /picomatch@2.3.1: 2636 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 2637 | engines: {node: '>=8.6'} 2638 | dev: true 2639 | 2640 | /pirates@4.0.6: 2641 | resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} 2642 | engines: {node: '>= 6'} 2643 | dev: true 2644 | 2645 | /pkg-dir@4.2.0: 2646 | resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} 2647 | engines: {node: '>=8'} 2648 | dependencies: 2649 | find-up: 4.1.0 2650 | dev: true 2651 | 2652 | /prelude-ls@1.1.2: 2653 | resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} 2654 | engines: {node: '>= 0.8.0'} 2655 | dev: true 2656 | 2657 | /pretty-format@29.7.0: 2658 | resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} 2659 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} 2660 | dependencies: 2661 | '@jest/schemas': 29.6.3 2662 | ansi-styles: 5.2.0 2663 | react-is: 18.3.1 2664 | dev: true 2665 | 2666 | /progress@2.0.3: 2667 | resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} 2668 | engines: {node: '>=0.4.0'} 2669 | dev: true 2670 | 2671 | /prompts@2.4.2: 2672 | resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} 2673 | engines: {node: '>= 6'} 2674 | dependencies: 2675 | kleur: 3.0.3 2676 | sisteransi: 1.0.5 2677 | dev: true 2678 | 2679 | /punycode@2.3.1: 2680 | resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} 2681 | engines: {node: '>=6'} 2682 | dev: true 2683 | 2684 | /pure-rand@6.1.0: 2685 | resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} 2686 | dev: true 2687 | 2688 | /query-string@7.1.3: 2689 | resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==} 2690 | engines: {node: '>=6'} 2691 | dependencies: 2692 | decode-uri-component: 0.2.2 2693 | filter-obj: 1.1.0 2694 | split-on-first: 1.1.0 2695 | strict-uri-encode: 2.0.0 2696 | dev: false 2697 | 2698 | /react-is@18.3.1: 2699 | resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} 2700 | dev: true 2701 | 2702 | /regexpp@2.0.1: 2703 | resolution: {integrity: sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==} 2704 | engines: {node: '>=6.5.0'} 2705 | dev: true 2706 | 2707 | /regexpp@3.2.0: 2708 | resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} 2709 | engines: {node: '>=8'} 2710 | dev: true 2711 | 2712 | /require-directory@2.1.1: 2713 | resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} 2714 | engines: {node: '>=0.10.0'} 2715 | dev: true 2716 | 2717 | /resolve-cwd@3.0.0: 2718 | resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} 2719 | engines: {node: '>=8'} 2720 | dependencies: 2721 | resolve-from: 5.0.0 2722 | dev: true 2723 | 2724 | /resolve-from@4.0.0: 2725 | resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} 2726 | engines: {node: '>=4'} 2727 | dev: true 2728 | 2729 | /resolve-from@5.0.0: 2730 | resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} 2731 | engines: {node: '>=8'} 2732 | dev: true 2733 | 2734 | /resolve.exports@2.0.2: 2735 | resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} 2736 | engines: {node: '>=10'} 2737 | dev: true 2738 | 2739 | /resolve@1.22.8: 2740 | resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} 2741 | hasBin: true 2742 | dependencies: 2743 | is-core-module: 2.15.1 2744 | path-parse: 1.0.7 2745 | supports-preserve-symlinks-flag: 1.0.0 2746 | dev: true 2747 | 2748 | /restore-cursor@3.1.0: 2749 | resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} 2750 | engines: {node: '>=8'} 2751 | dependencies: 2752 | onetime: 5.1.2 2753 | signal-exit: 3.0.7 2754 | dev: true 2755 | 2756 | /rimraf@2.6.3: 2757 | resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} 2758 | deprecated: Rimraf versions prior to v4 are no longer supported 2759 | hasBin: true 2760 | dependencies: 2761 | glob: 7.2.3 2762 | dev: true 2763 | 2764 | /run-async@2.4.1: 2765 | resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} 2766 | engines: {node: '>=0.12.0'} 2767 | dev: true 2768 | 2769 | /rxjs@6.6.7: 2770 | resolution: {integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==} 2771 | engines: {npm: '>=2.0.0'} 2772 | dependencies: 2773 | tslib: 1.14.1 2774 | dev: true 2775 | 2776 | /safer-buffer@2.1.2: 2777 | resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} 2778 | dev: true 2779 | 2780 | /semver@5.7.2: 2781 | resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} 2782 | hasBin: true 2783 | dev: true 2784 | 2785 | /semver@6.3.1: 2786 | resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} 2787 | hasBin: true 2788 | dev: true 2789 | 2790 | /semver@7.6.3: 2791 | resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} 2792 | engines: {node: '>=10'} 2793 | hasBin: true 2794 | dev: true 2795 | 2796 | /shebang-command@1.2.0: 2797 | resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} 2798 | engines: {node: '>=0.10.0'} 2799 | dependencies: 2800 | shebang-regex: 1.0.0 2801 | dev: true 2802 | 2803 | /shebang-command@2.0.0: 2804 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 2805 | engines: {node: '>=8'} 2806 | dependencies: 2807 | shebang-regex: 3.0.0 2808 | dev: true 2809 | 2810 | /shebang-regex@1.0.0: 2811 | resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} 2812 | engines: {node: '>=0.10.0'} 2813 | dev: true 2814 | 2815 | /shebang-regex@3.0.0: 2816 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 2817 | engines: {node: '>=8'} 2818 | dev: true 2819 | 2820 | /signal-exit@3.0.7: 2821 | resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} 2822 | dev: true 2823 | 2824 | /sisteransi@1.0.5: 2825 | resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} 2826 | dev: true 2827 | 2828 | /slash@3.0.0: 2829 | resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} 2830 | engines: {node: '>=8'} 2831 | dev: true 2832 | 2833 | /slice-ansi@2.1.0: 2834 | resolution: {integrity: sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==} 2835 | engines: {node: '>=6'} 2836 | dependencies: 2837 | ansi-styles: 3.2.1 2838 | astral-regex: 1.0.0 2839 | is-fullwidth-code-point: 2.0.0 2840 | dev: true 2841 | 2842 | /source-map-support@0.5.13: 2843 | resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} 2844 | dependencies: 2845 | buffer-from: 1.1.2 2846 | source-map: 0.6.1 2847 | dev: true 2848 | 2849 | /source-map@0.6.1: 2850 | resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} 2851 | engines: {node: '>=0.10.0'} 2852 | dev: true 2853 | 2854 | /split-on-first@1.1.0: 2855 | resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==} 2856 | engines: {node: '>=6'} 2857 | dev: false 2858 | 2859 | /sprintf-js@1.0.3: 2860 | resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} 2861 | dev: true 2862 | 2863 | /stack-utils@2.0.6: 2864 | resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} 2865 | engines: {node: '>=10'} 2866 | dependencies: 2867 | escape-string-regexp: 2.0.0 2868 | dev: true 2869 | 2870 | /strict-uri-encode@2.0.0: 2871 | resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} 2872 | engines: {node: '>=4'} 2873 | dev: false 2874 | 2875 | /string-length@4.0.2: 2876 | resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} 2877 | engines: {node: '>=10'} 2878 | dependencies: 2879 | char-regex: 1.0.2 2880 | strip-ansi: 6.0.1 2881 | dev: true 2882 | 2883 | /string-width@3.1.0: 2884 | resolution: {integrity: sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==} 2885 | engines: {node: '>=6'} 2886 | dependencies: 2887 | emoji-regex: 7.0.3 2888 | is-fullwidth-code-point: 2.0.0 2889 | strip-ansi: 5.2.0 2890 | dev: true 2891 | 2892 | /string-width@4.2.3: 2893 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 2894 | engines: {node: '>=8'} 2895 | dependencies: 2896 | emoji-regex: 8.0.0 2897 | is-fullwidth-code-point: 3.0.0 2898 | strip-ansi: 6.0.1 2899 | dev: true 2900 | 2901 | /strip-ansi@5.2.0: 2902 | resolution: {integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==} 2903 | engines: {node: '>=6'} 2904 | dependencies: 2905 | ansi-regex: 4.1.1 2906 | dev: true 2907 | 2908 | /strip-ansi@6.0.1: 2909 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 2910 | engines: {node: '>=8'} 2911 | dependencies: 2912 | ansi-regex: 5.0.1 2913 | dev: true 2914 | 2915 | /strip-bom@4.0.0: 2916 | resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} 2917 | engines: {node: '>=8'} 2918 | dev: true 2919 | 2920 | /strip-final-newline@2.0.0: 2921 | resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} 2922 | engines: {node: '>=6'} 2923 | dev: true 2924 | 2925 | /strip-json-comments@3.1.1: 2926 | resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} 2927 | engines: {node: '>=8'} 2928 | dev: true 2929 | 2930 | /supports-color@5.5.0: 2931 | resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} 2932 | engines: {node: '>=4'} 2933 | dependencies: 2934 | has-flag: 3.0.0 2935 | dev: true 2936 | 2937 | /supports-color@7.2.0: 2938 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 2939 | engines: {node: '>=8'} 2940 | dependencies: 2941 | has-flag: 4.0.0 2942 | dev: true 2943 | 2944 | /supports-color@8.1.1: 2945 | resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} 2946 | engines: {node: '>=10'} 2947 | dependencies: 2948 | has-flag: 4.0.0 2949 | dev: true 2950 | 2951 | /supports-preserve-symlinks-flag@1.0.0: 2952 | resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} 2953 | engines: {node: '>= 0.4'} 2954 | dev: true 2955 | 2956 | /table@5.4.6: 2957 | resolution: {integrity: sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==} 2958 | engines: {node: '>=6.0.0'} 2959 | dependencies: 2960 | ajv: 6.12.6 2961 | lodash: 4.17.21 2962 | slice-ansi: 2.1.0 2963 | string-width: 3.1.0 2964 | dev: true 2965 | 2966 | /test-exclude@6.0.0: 2967 | resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} 2968 | engines: {node: '>=8'} 2969 | dependencies: 2970 | '@istanbuljs/schema': 0.1.3 2971 | glob: 7.2.3 2972 | minimatch: 3.1.2 2973 | dev: true 2974 | 2975 | /text-table@0.2.0: 2976 | resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} 2977 | dev: true 2978 | 2979 | /through@2.3.8: 2980 | resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} 2981 | dev: true 2982 | 2983 | /tmp@0.0.33: 2984 | resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} 2985 | engines: {node: '>=0.6.0'} 2986 | dependencies: 2987 | os-tmpdir: 1.0.2 2988 | dev: true 2989 | 2990 | /tmpl@1.0.5: 2991 | resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} 2992 | dev: true 2993 | 2994 | /to-fast-properties@2.0.0: 2995 | resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} 2996 | engines: {node: '>=4'} 2997 | dev: true 2998 | 2999 | /to-regex-range@5.0.1: 3000 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 3001 | engines: {node: '>=8.0'} 3002 | dependencies: 3003 | is-number: 7.0.0 3004 | dev: true 3005 | 3006 | /tr46@0.0.3: 3007 | resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} 3008 | dev: false 3009 | 3010 | /ts-jest@29.2.5(@babel/core@7.25.2)(jest@29.7.0)(typescript@4.9.5): 3011 | resolution: {integrity: sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==} 3012 | engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} 3013 | hasBin: true 3014 | peerDependencies: 3015 | '@babel/core': '>=7.0.0-beta.0 <8' 3016 | '@jest/transform': ^29.0.0 3017 | '@jest/types': ^29.0.0 3018 | babel-jest: ^29.0.0 3019 | esbuild: '*' 3020 | jest: ^29.0.0 3021 | typescript: '>=4.3 <6' 3022 | peerDependenciesMeta: 3023 | '@babel/core': 3024 | optional: true 3025 | '@jest/transform': 3026 | optional: true 3027 | '@jest/types': 3028 | optional: true 3029 | babel-jest: 3030 | optional: true 3031 | esbuild: 3032 | optional: true 3033 | dependencies: 3034 | '@babel/core': 7.25.2 3035 | bs-logger: 0.2.6 3036 | ejs: 3.1.10 3037 | fast-json-stable-stringify: 2.1.0 3038 | jest: 29.7.0(@types/node@18.19.50) 3039 | jest-util: 29.7.0 3040 | json5: 2.2.3 3041 | lodash.memoize: 4.1.2 3042 | make-error: 1.3.6 3043 | semver: 7.6.3 3044 | typescript: 4.9.5 3045 | yargs-parser: 21.1.1 3046 | dev: true 3047 | 3048 | /tslib@1.14.1: 3049 | resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} 3050 | dev: true 3051 | 3052 | /tsutils@3.21.0(typescript@4.9.5): 3053 | resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} 3054 | engines: {node: '>= 6'} 3055 | peerDependencies: 3056 | typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' 3057 | dependencies: 3058 | tslib: 1.14.1 3059 | typescript: 4.9.5 3060 | dev: true 3061 | 3062 | /type-check@0.3.2: 3063 | resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==} 3064 | engines: {node: '>= 0.8.0'} 3065 | dependencies: 3066 | prelude-ls: 1.1.2 3067 | dev: true 3068 | 3069 | /type-detect@4.0.8: 3070 | resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} 3071 | engines: {node: '>=4'} 3072 | dev: true 3073 | 3074 | /type-fest@0.21.3: 3075 | resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} 3076 | engines: {node: '>=10'} 3077 | dev: true 3078 | 3079 | /type-fest@0.8.1: 3080 | resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} 3081 | engines: {node: '>=8'} 3082 | dev: true 3083 | 3084 | /typescript@4.9.5: 3085 | resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} 3086 | engines: {node: '>=4.2.0'} 3087 | hasBin: true 3088 | dev: true 3089 | 3090 | /undici-types@5.26.5: 3091 | resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} 3092 | dev: true 3093 | 3094 | /update-browserslist-db@1.1.0(browserslist@4.23.3): 3095 | resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==} 3096 | hasBin: true 3097 | peerDependencies: 3098 | browserslist: '>= 4.21.0' 3099 | dependencies: 3100 | browserslist: 4.23.3 3101 | escalade: 3.2.0 3102 | picocolors: 1.1.0 3103 | dev: true 3104 | 3105 | /uri-js@4.4.1: 3106 | resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} 3107 | dependencies: 3108 | punycode: 2.3.1 3109 | dev: true 3110 | 3111 | /v8-compile-cache@2.4.0: 3112 | resolution: {integrity: sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==} 3113 | dev: true 3114 | 3115 | /v8-to-istanbul@9.3.0: 3116 | resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} 3117 | engines: {node: '>=10.12.0'} 3118 | dependencies: 3119 | '@jridgewell/trace-mapping': 0.3.25 3120 | '@types/istanbul-lib-coverage': 2.0.6 3121 | convert-source-map: 2.0.0 3122 | dev: true 3123 | 3124 | /walker@1.0.8: 3125 | resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} 3126 | dependencies: 3127 | makeerror: 1.0.12 3128 | dev: true 3129 | 3130 | /webidl-conversions@3.0.1: 3131 | resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} 3132 | dev: false 3133 | 3134 | /whatwg-url@5.0.0: 3135 | resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} 3136 | dependencies: 3137 | tr46: 0.0.3 3138 | webidl-conversions: 3.0.1 3139 | dev: false 3140 | 3141 | /which@1.3.1: 3142 | resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} 3143 | hasBin: true 3144 | dependencies: 3145 | isexe: 2.0.0 3146 | dev: true 3147 | 3148 | /which@2.0.2: 3149 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 3150 | engines: {node: '>= 8'} 3151 | hasBin: true 3152 | dependencies: 3153 | isexe: 2.0.0 3154 | dev: true 3155 | 3156 | /word-wrap@1.2.5: 3157 | resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} 3158 | engines: {node: '>=0.10.0'} 3159 | dev: true 3160 | 3161 | /wrap-ansi@7.0.0: 3162 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 3163 | engines: {node: '>=10'} 3164 | dependencies: 3165 | ansi-styles: 4.3.0 3166 | string-width: 4.2.3 3167 | strip-ansi: 6.0.1 3168 | dev: true 3169 | 3170 | /wrappy@1.0.2: 3171 | resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} 3172 | dev: true 3173 | 3174 | /write-file-atomic@4.0.2: 3175 | resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} 3176 | engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} 3177 | dependencies: 3178 | imurmurhash: 0.1.4 3179 | signal-exit: 3.0.7 3180 | dev: true 3181 | 3182 | /write@1.0.3: 3183 | resolution: {integrity: sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==} 3184 | engines: {node: '>=4'} 3185 | dependencies: 3186 | mkdirp: 0.5.6 3187 | dev: true 3188 | 3189 | /y18n@5.0.8: 3190 | resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} 3191 | engines: {node: '>=10'} 3192 | dev: true 3193 | 3194 | /yallist@3.1.1: 3195 | resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} 3196 | dev: true 3197 | 3198 | /yargs-parser@21.1.1: 3199 | resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} 3200 | engines: {node: '>=12'} 3201 | dev: true 3202 | 3203 | /yargs@17.7.2: 3204 | resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} 3205 | engines: {node: '>=12'} 3206 | dependencies: 3207 | cliui: 8.0.1 3208 | escalade: 3.2.0 3209 | get-caller-file: 2.0.5 3210 | require-directory: 2.1.1 3211 | string-width: 4.2.3 3212 | y18n: 5.0.8 3213 | yargs-parser: 21.1.1 3214 | dev: true 3215 | 3216 | /yocto-queue@0.1.0: 3217 | resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} 3218 | engines: {node: '>=10'} 3219 | dev: true 3220 | -------------------------------------------------------------------------------- /test/access.test.ts: -------------------------------------------------------------------------------- 1 | import { Access } from '../lib/access'; 2 | 3 | const appId = 'SampleApp'; 4 | const url = 'http://localhost:8080/notifications/v2?appId=SampleApp&cluster=default¬ifications=%5B%7B%22namespaceName%22%3A%22application%22%2C%22notificationId%22%3A-1%7D%5D'; 5 | const secret = 'cf86d564d10a46d4a5989dfdeed3a3a2'; 6 | 7 | it('should return the correct access headers', () => { 8 | const headers = (Access as any).createAccessHeaderByTimestamp(1617795566349, appId, url, secret); 9 | expect(headers.Authorization).toBe('Apollo SampleApp:6VzjhD0wLAwRhyr4Rj/L7iwKK7Y='); 10 | }); 11 | -------------------------------------------------------------------------------- /test/config_change.test.ts: -------------------------------------------------------------------------------- 1 | import { ConfigChange } from '../lib/config_change'; 2 | import { PropertyChangeType } from '../lib/constants'; 3 | 4 | const configChange = new ConfigChange('application', 'key', 'oldValue', 'newValue', PropertyChangeType.MODIFIED); 5 | 6 | it('should return the correct namespaceName', () => { 7 | expect(configChange.getNamespace()).toBe('application'); 8 | }); 9 | 10 | it('should return the correct propertyName', () => { 11 | expect(configChange.getPropertyName()).toBe('key'); 12 | }); 13 | 14 | it('should return the correct oldValue', () => { 15 | expect(configChange.getOldValue()).toBe('oldValue'); 16 | }); 17 | 18 | it('should return the correct newValue', () => { 19 | expect(configChange.getNewValue()).toBe('newValue'); 20 | }); 21 | 22 | it('should return the correct changeType', () => { 23 | expect(configChange.getChangeType()).toBe(PropertyChangeType.MODIFIED); 24 | }); 25 | -------------------------------------------------------------------------------- /test/config_change_event.test.ts: -------------------------------------------------------------------------------- 1 | import { ConfigChangeEvent } from '../lib/config_change_event'; 2 | import { ConfigChange } from '../lib/config_change'; 3 | import { PropertyChangeType } from '../lib/constants'; 4 | 5 | const configChanges: Map> = new Map(); 6 | configChanges.set('key', new ConfigChange('application', 'key', 'oldValue', 'newValue', PropertyChangeType.MODIFIED)); 7 | 8 | const changeEvent = new ConfigChangeEvent('application', configChanges); 9 | 10 | it('should return the correct namespaceName', () => { 11 | expect(changeEvent.getNamespace()).toBe('application'); 12 | }); 13 | 14 | it('should get the correct changedKeys', () => { 15 | expect(changeEvent.changedKeys().sort()).toEqual(['key'].sort()); 16 | }); 17 | 18 | it('should return configChange', () => { 19 | expect(changeEvent.getChange('key') instanceof ConfigChange).toBeTruthy(); 20 | }); 21 | -------------------------------------------------------------------------------- /test/config_manager.test.ts: -------------------------------------------------------------------------------- 1 | import { ConfigManager } from '../lib/config_manager'; 2 | import { Request, Notification } from '../lib/request'; 3 | import { PropertiesConfig } from '../lib/properties_config'; 4 | import { JSONConfig } from '../lib/json_config'; 5 | import { PlainConfig } from '../lib/plain_config'; 6 | 7 | jest.mock('../lib/request'); 8 | const mockRequest = Request as jest.Mocked; 9 | 10 | const mockNotifications = (namespaceName: string, notificationId: number): Notification[] => { 11 | return [{ namespaceName, notificationId }]; 12 | }; 13 | 14 | const sleep = (time = 1000): Promise => { 15 | return new Promise(resolve => setTimeout(resolve, time)); 16 | }; 17 | 18 | const configManager = new ConfigManager({ 19 | configServerUrl: 'http://localhost:8080/', 20 | appId: 'SampleApp', 21 | clusterName: 'default', 22 | }); 23 | 24 | afterAll(() => { 25 | configManager.removeConfig('config'); 26 | configManager.removeConfig('config2.properties'); 27 | configManager.removeConfig('config3.json.properties'); 28 | configManager.removeConfig('config.json'); 29 | configManager.removeConfig('config.txt'); 30 | configManager.removeConfig('errorConfig'); 31 | configManager.removeConfig('errorConfig2'); 32 | }); 33 | 34 | describe('properties config', () => { 35 | const configs = { 36 | 'key1': 'value1', 37 | 'key1.key2': 'value2', 38 | 'key1.key2.key3': 'value3', 39 | }; 40 | let propertiesConfig1; 41 | let propertiesConfig2; 42 | 43 | const mockOnce = (namespaceName: string): void => { 44 | mockRequest.fetchNotifications.mockResolvedValueOnce(mockNotifications(namespaceName, 1)); 45 | mockRequest.fetchConfig.mockResolvedValueOnce({ 46 | 'appId': 'SampleApp', 47 | 'cluster': 'default', 48 | namespaceName, 49 | 'configurations': configs, 50 | 'releaseKey': '20200203154030-1dc524aa9a4a5974' 51 | }); 52 | }; 53 | 54 | it('should return a properties config', async () => { 55 | const configNamespaceName = 'config'; 56 | mockOnce(configNamespaceName); 57 | propertiesConfig1 = await configManager.getConfig(configNamespaceName); 58 | expect(propertiesConfig1.getNamespaceName()).toEqual(configNamespaceName); 59 | expect(propertiesConfig1 instanceof PropertiesConfig).toBeTruthy(); 60 | 61 | const config2NamespaceName = 'config2'; 62 | mockOnce(config2NamespaceName); 63 | propertiesConfig2 = await configManager.getConfig(`${config2NamespaceName}.properties`); 64 | expect(propertiesConfig2.getNamespaceName()).toEqual('config2'); 65 | expect(propertiesConfig2 instanceof PropertiesConfig).toBeTruthy(); 66 | 67 | expect(configManager.getConfig('.properties')).rejects.toThrowError('empty'); 68 | }); 69 | 70 | it('should get correct configs', () => { 71 | expect(propertiesConfig1.getAllConfig()).toStrictEqual(new Map(Object.entries(configs))); 72 | expect(propertiesConfig2.getAllConfig()).toStrictEqual(new Map(Object.entries(configs))); 73 | }); 74 | }); 75 | 76 | describe('json config', () => { 77 | const namespaceName = 'config.json'; 78 | const configs = { 79 | key: 'value', 80 | key2: [1, 2], 81 | key3: { 82 | key4: null 83 | }, 84 | }; 85 | let jsonConfig; 86 | 87 | it('should return a json config', async () => { 88 | mockRequest.fetchNotifications.mockResolvedValueOnce(mockNotifications(namespaceName, 1)); 89 | mockRequest.fetchConfig.mockResolvedValueOnce({ 90 | 'appId': 'SampleApp', 91 | 'cluster': 'default', 92 | namespaceName, 93 | 'configurations': { 94 | 'content': JSON.stringify(configs), 95 | }, 96 | 'releaseKey': '20200203154030-1dc524aa9a4a5974' 97 | }); 98 | jsonConfig = await configManager.getConfig(namespaceName); 99 | expect(jsonConfig.getNamespaceName()).toEqual(namespaceName); 100 | expect(jsonConfig instanceof JSONConfig).toBeTruthy(); 101 | }); 102 | 103 | it('should get correct configs', () => { 104 | expect(jsonConfig.getAllConfig()).toStrictEqual(configs); 105 | }); 106 | }); 107 | 108 | describe('plain config', () => { 109 | const namespaceName = 'config.txt'; 110 | const configs = 'plain configs'; 111 | let plainConfig; 112 | 113 | it('should return a plain config', async () => { 114 | mockRequest.fetchNotifications.mockResolvedValueOnce(mockNotifications(namespaceName, 1)); 115 | mockRequest.fetchConfig.mockResolvedValueOnce({ 116 | 'appId': 'SampleApp', 117 | 'cluster': 'default', 118 | namespaceName, 119 | 'configurations': { 120 | 'content': configs, 121 | }, 122 | 'releaseKey': '20200203154030-1dc524aa9a4a5974' 123 | }); 124 | plainConfig = await configManager.getConfig(namespaceName); 125 | expect(plainConfig.getNamespaceName()).toEqual(namespaceName); 126 | expect(plainConfig instanceof PlainConfig).toBeTruthy(); 127 | }); 128 | 129 | it('should get correct configs', () => { 130 | expect(plainConfig.getAllConfig()).toEqual(configs); 131 | }); 132 | 133 | it('should ignore the long poll error', async () => { 134 | mockRequest.fetchNotifications.mockRejectedValueOnce(new Error('mock reject fetch notifications')); 135 | await sleep(); 136 | expect(plainConfig.getAllConfig()).toEqual(configs); 137 | }); 138 | 139 | it('should long poll update config', async () => { 140 | const newConfigs = 'new configs'; 141 | mockRequest.fetchNotifications.mockResolvedValueOnce(mockNotifications(namespaceName, 3)); 142 | mockRequest.fetchConfig.mockResolvedValueOnce({ 143 | 'appId': 'SampleApp', 144 | 'cluster': 'default', 145 | namespaceName, 146 | 'configurations': { 147 | 'content': newConfigs, 148 | }, 149 | 'releaseKey': '20200203154030-1dc524aa9a4a5974' 150 | }); 151 | await sleep(); 152 | expect(plainConfig.getAllConfig()).toEqual(newConfigs); 153 | }); 154 | 155 | }); 156 | 157 | it('should ignore the request error', async () => { 158 | mockRequest.fetchNotifications.mockRejectedValueOnce(new Error('Mock reject fetch notifications')); 159 | expect(configManager.getConfig('errorConfig')).resolves.not.toThrowError(); 160 | 161 | const namespaceName2 = 'errorConfig2'; 162 | mockRequest.fetchNotifications.mockResolvedValueOnce(mockNotifications(namespaceName2, Number.MAX_VALUE)); 163 | mockRequest.fetchConfig.mockRejectedValueOnce(new Error('Mock reject fetch config')); 164 | expect(configManager.getConfig(namespaceName2)).resolves.not.toThrowError(); 165 | }); 166 | -------------------------------------------------------------------------------- /test/json_config.test.ts: -------------------------------------------------------------------------------- 1 | import { JSONConfig, JSONValueType } from '../lib/json_config'; 2 | import { LoadConfigResp, Request } from '../lib/request'; 3 | import { ConfigChangeEvent } from '../lib/config_change_event'; 4 | import { CHANGE_EVENT_NAME, PropertyChangeType } from '../lib/constants'; 5 | import { ConfigContentType } from '../lib/types'; 6 | 7 | jest.mock('../lib/request'); 8 | const mockRequest = Request as jest.Mocked; 9 | const namespaceName = 'test.json'; 10 | const mockResponse = (configs: JSONValueType): LoadConfigResp => { 11 | return { 12 | 'appId': 'SampleApp', 13 | 'cluster': 'default', 14 | 'namespaceName': `${namespaceName}.json`, 15 | 'configurations': { 16 | 'content': JSON.stringify(configs), 17 | }, 18 | 'releaseKey': '20200203154030-1dc524aa9a4a5974' 19 | }; 20 | }; 21 | 22 | const initConfigs = { 23 | strKey: 'string', 24 | objKey: { 25 | arrKey: [1, 2, 3], 26 | nullKey: null, 27 | }, 28 | numberKey: 3, 29 | }; 30 | 31 | const configOptions = { 32 | configServerUrl: 'http://localhost:8080/', 33 | appId: 'SampleApp', 34 | clusterName: 'default', 35 | namespaceName, 36 | }; 37 | 38 | const jsonConfig = new JSONConfig(configOptions, '0.0.0.0'); 39 | 40 | beforeAll(() => { 41 | mockRequest.fetchConfig.mockResolvedValueOnce(mockResponse(initConfigs)); 42 | return jsonConfig.loadAndUpdateConfig(); 43 | }); 44 | 45 | it('should return all the correct json configs', () => { 46 | expect(jsonConfig.getAllConfig()).toStrictEqual(initConfigs); 47 | }); 48 | 49 | it('should return the correct value and default value', () => { 50 | const defaultJsonValue = { 51 | default: ['defaultValue'], 52 | }; 53 | const value1 = jsonConfig.getProperty('objKey.arrKey.none', defaultJsonValue); 54 | const value2 = jsonConfig.getProperty('objKey..arrKey', defaultJsonValue); 55 | const value3 = jsonConfig.getProperty('strKey.none', defaultJsonValue); 56 | expect(value1).toStrictEqual(defaultJsonValue); 57 | expect(value2).toStrictEqual(defaultJsonValue); 58 | expect(value3).toStrictEqual(defaultJsonValue); 59 | 60 | const value4 = jsonConfig.getProperty('strKey'); 61 | const value5 = jsonConfig.getProperty('objKey'); 62 | const value6 = jsonConfig.getProperty('objKey.arrKey'); 63 | expect(value4).toStrictEqual(initConfigs.strKey); 64 | expect(value5).toStrictEqual(initConfigs.objKey); 65 | expect(value6).toStrictEqual(initConfigs.objKey.arrKey); 66 | }); 67 | 68 | it('should get the correct changeEvent', (done: jest.DoneCallback) => { 69 | try { 70 | const handle = (changeEvent: ConfigChangeEvent): void => { 71 | try { 72 | expect(changeEvent.getNamespace()).toBe(namespaceName); 73 | expect(changeEvent.changedKeys().sort()).toEqual(['objKey.nullKey', 'objKey.arrKey', 'addedKey', 'strKey'].sort()); 74 | 75 | const addedChange = changeEvent.getChange('addedKey'); 76 | if (!addedChange) { 77 | throw 'Missing added change'; 78 | } 79 | expect(addedChange.getNamespace()).toBe(namespaceName); 80 | expect(addedChange.getPropertyName()).toBe('addedKey'); 81 | expect(addedChange.getOldValue()).toBeUndefined(); 82 | expect(addedChange.getNewValue()).toEqual([1]); 83 | expect(addedChange.getChangeType()).toBe(PropertyChangeType.ADDED); 84 | 85 | const deletedChange = changeEvent.getChange('objKey.nullKey'); 86 | if (!deletedChange) { 87 | throw 'Missing deleted change'; 88 | } 89 | expect(deletedChange.getNamespace()).toBe(namespaceName); 90 | expect(deletedChange.getPropertyName()).toBe('objKey.nullKey'); 91 | expect(deletedChange.getOldValue()).toBe(null); 92 | expect(deletedChange.getNewValue()).toBeUndefined(); 93 | expect(deletedChange.getChangeType()).toBe(PropertyChangeType.DELETED); 94 | 95 | const modifiedChange = changeEvent.getChange('objKey.arrKey'); 96 | if (!modifiedChange) { 97 | throw 'Missing added change'; 98 | } 99 | expect(modifiedChange.getNamespace()).toBe(namespaceName); 100 | expect(modifiedChange.getPropertyName()).toBe('objKey.arrKey'); 101 | expect(modifiedChange.getOldValue()).toEqual([1, 2, 3]); 102 | expect(modifiedChange.getNewValue()).toEqual([1, 2, 3, 4]); 103 | expect(modifiedChange.getChangeType()).toBe(PropertyChangeType.MODIFIED); 104 | 105 | jsonConfig.removeListener(CHANGE_EVENT_NAME, handle); 106 | done(); 107 | } catch (error) { 108 | done(error); 109 | } 110 | }; 111 | jsonConfig.addChangeListener(handle); 112 | mockRequest.fetchConfig.mockResolvedValueOnce(mockResponse({ 113 | objKey: { 114 | arrKey: [1, 2, 3, 4] 115 | }, 116 | numberKey: 3, 117 | addedKey: [1], 118 | })); 119 | jsonConfig.loadAndUpdateConfig().then(); 120 | } catch (error) { 121 | done(error); 122 | } 123 | }); 124 | 125 | it('should throw requets error', async () => { 126 | const error = new Error('Mock reject fetch config'); 127 | mockRequest.fetchConfig.mockRejectedValueOnce(error); 128 | try { 129 | await jsonConfig.loadAndUpdateConfig(); 130 | } catch (e) { 131 | expect(e).toEqual(error); 132 | } 133 | }); 134 | 135 | it('should parse correctly when config type is a string', async () => { 136 | const stringValue = 'stringValue'; 137 | mockRequest.fetchConfig.mockResolvedValueOnce(mockResponse(stringValue)); 138 | await jsonConfig.loadAndUpdateConfig(); 139 | expect(jsonConfig.getAllConfig()).toEqual(stringValue); 140 | }); 141 | -------------------------------------------------------------------------------- /test/plain_config.test.ts: -------------------------------------------------------------------------------- 1 | import { LoadConfigResp } from '../lib/request'; 2 | import { ConfigContentType } from '../lib/types'; 3 | import { PlainConfig } from '../lib/plain_config'; 4 | import { Request } from '../lib/request'; 5 | import { ConfigChangeEvent } from '../lib/config_change_event'; 6 | import { CHANGE_EVENT_NAME, PropertyChangeType } from '../lib/constants'; 7 | 8 | jest.mock('../lib/request'); 9 | const mockRequest = Request as jest.Mocked; 10 | const namespaceName = 'test.txt'; 11 | const mockResponse = (configs: string): LoadConfigResp => { 12 | return { 13 | 'appId': 'SampleApp', 14 | 'cluster': 'default', 15 | 'namespaceName': `${namespaceName}.txt`, 16 | 'configurations': { 17 | 'content': configs, 18 | }, 19 | 'releaseKey': '20200203154030-1dc524aa9a4a5974' 20 | }; 21 | }; 22 | 23 | const initConfigs = 'init config'; 24 | 25 | const configOptions = { 26 | configServerUrl: 'http://localhost:8080/', 27 | appId: 'SampleApp', 28 | clusterName: 'default', 29 | namespaceName, 30 | }; 31 | 32 | const plainConfig = new PlainConfig(configOptions, '0.0.0.0'); 33 | 34 | beforeAll(() => { 35 | mockRequest.fetchConfig.mockResolvedValueOnce(mockResponse(initConfigs)); 36 | return plainConfig.loadAndUpdateConfig(); 37 | }); 38 | 39 | it('should return all the correct json configs', () => { 40 | expect(plainConfig.getAllConfig()).toStrictEqual(initConfigs); 41 | }); 42 | 43 | it('should return the correct value and default value', () => { 44 | expect(plainConfig.getProperty('key')).toEqual(initConfigs); 45 | }); 46 | 47 | it('should get the correct changeEvent', (done: jest.DoneCallback) => { 48 | try { 49 | const newConfigs = 'new configs'; 50 | const handle = (changeEvent: ConfigChangeEvent): void => { 51 | try { 52 | expect(changeEvent.getNamespace()).toBe(namespaceName); 53 | expect(changeEvent.changedKeys()).toEqual(['']); 54 | 55 | const modifiedChange = changeEvent.getChange(''); 56 | if (!modifiedChange) { 57 | throw 'Missing added change'; 58 | } 59 | expect(modifiedChange.getNamespace()).toBe(namespaceName); 60 | expect(modifiedChange.getPropertyName()).toBe(''); 61 | expect(modifiedChange.getOldValue()).toEqual(initConfigs); 62 | expect(modifiedChange.getNewValue()).toEqual(newConfigs); 63 | expect(modifiedChange.getChangeType()).toBe(PropertyChangeType.MODIFIED); 64 | 65 | plainConfig.removeListener(CHANGE_EVENT_NAME, handle); 66 | done(); 67 | } catch (error) { 68 | done(error); 69 | } 70 | }; 71 | plainConfig.addChangeListener(handle); 72 | mockRequest.fetchConfig.mockResolvedValueOnce(mockResponse(newConfigs)); 73 | plainConfig.loadAndUpdateConfig().then(); 74 | } catch (error) { 75 | done(error); 76 | } 77 | }); 78 | 79 | it('should throw request error', async () => { 80 | const error = new Error('Mock reject fetch config'); 81 | mockRequest.fetchConfig.mockRejectedValueOnce(error); 82 | try { 83 | await plainConfig.loadAndUpdateConfig(); 84 | } catch (e) { 85 | expect(e).toEqual(error); 86 | } 87 | }); 88 | 89 | it('should parse success when fetch config return null', async () => { 90 | mockRequest.fetchConfig.mockResolvedValueOnce(mockResponse(initConfigs)); 91 | await plainConfig.loadAndUpdateConfig(); 92 | expect(plainConfig.getAllConfig()).toEqual(initConfigs); 93 | 94 | mockRequest.fetchConfig.mockResolvedValueOnce(null); 95 | await plainConfig.loadAndUpdateConfig(); 96 | expect(plainConfig.getAllConfig()).toStrictEqual(initConfigs); 97 | }); 98 | -------------------------------------------------------------------------------- /test/properties_config.test.ts: -------------------------------------------------------------------------------- 1 | import { KVConfigContentType, PropertiesConfig } from '../lib/properties_config'; 2 | import { LoadConfigResp, Request } from '../lib/request'; 3 | import { ConfigChangeEvent } from '../lib/config_change_event'; 4 | import { CHANGE_EVENT_NAME, PropertyChangeType } from '../lib/constants'; 5 | 6 | 7 | jest.mock('../lib/request'); 8 | const mockRequest = Request as jest.Mocked; 9 | const namespaceName = 'application'; 10 | const mockResponse = (configurations: KVConfigContentType): LoadConfigResp => { 11 | return { 12 | 'appId': 'SampleApp', 13 | 'cluster': 'default', 14 | 'releaseKey': '20200203154030-1dc524aa9a4a5974', 15 | 'configurations': configurations, 16 | namespaceName, 17 | }; 18 | }; 19 | 20 | const initConfigs = { 21 | 'a.b': '', 22 | 'a.b.c': '2', 23 | }; 24 | 25 | const configOptions = { 26 | configServerUrl: 'http://localhost:8080/', 27 | appId: 'SampleApp', 28 | clusterName: 'default', 29 | namespaceName, 30 | }; 31 | 32 | const propertiesConfig = new PropertiesConfig(configOptions, '0.0.0.0'); 33 | 34 | beforeAll(() => { 35 | mockRequest.fetchConfig.mockResolvedValueOnce(mockResponse(initConfigs)); 36 | return propertiesConfig.loadAndUpdateConfig(); 37 | }); 38 | 39 | it('should return all the correct properties configs', () => { 40 | expect(propertiesConfig.getAllConfig()).toStrictEqual(new Map(Object.entries(initConfigs))); 41 | expect(propertiesConfig.getProperty('a.b')).toBe(initConfigs['a.b']); 42 | expect(propertiesConfig.getProperty('a.b.c')).toBe(initConfigs['a.b.c']); 43 | }); 44 | 45 | it('should return the correct value and default value', () => { 46 | expect(propertiesConfig.getProperty('a.none', 'default value')).toBe('default value'); 47 | }); 48 | 49 | it('should get the correct changeEvent', (done: jest.DoneCallback): void => { 50 | try { 51 | const handle = (changeEvent: ConfigChangeEvent): void => { 52 | expect(changeEvent.getNamespace()).toBe(namespaceName); 53 | expect(changeEvent.changedKeys().sort()).toStrictEqual(['a.b', 'a.b.c', 'b.a'].sort()); 54 | 55 | const addedChange = changeEvent.getChange('b.a'); 56 | if (!addedChange) { 57 | throw new Error('Missing added change'); 58 | } 59 | expect(addedChange.getNamespace()).toBe(namespaceName); 60 | expect(addedChange.getPropertyName()).toBe('b.a'); 61 | expect(addedChange.getOldValue()).toBeUndefined(); 62 | expect(addedChange.getNewValue()).toBe('3'); 63 | expect(addedChange.getChangeType()).toBe(PropertyChangeType.ADDED); 64 | 65 | const deletedChange = changeEvent.getChange('a.b'); 66 | if (!deletedChange) { 67 | throw new Error('Missing deleted change'); 68 | } 69 | expect(deletedChange.getNamespace()).toBe(namespaceName); 70 | expect(deletedChange.getPropertyName()).toBe('a.b'); 71 | expect(deletedChange.getOldValue()).toBe(''); 72 | expect(deletedChange.getNewValue()).toBeUndefined(); 73 | expect(deletedChange.getChangeType()).toBe(PropertyChangeType.DELETED); 74 | 75 | const modifiedChange = changeEvent.getChange('a.b.c'); 76 | if (!modifiedChange) { 77 | throw new Error('Missing modified change'); 78 | } 79 | expect(modifiedChange.getNamespace()).toBe(namespaceName); 80 | expect(modifiedChange.getPropertyName()).toBe('a.b.c'); 81 | expect(modifiedChange.getOldValue()).toBe('2'); 82 | expect(modifiedChange.getNewValue()).toBe('1'); 83 | expect(modifiedChange.getChangeType()).toBe(PropertyChangeType.MODIFIED); 84 | 85 | propertiesConfig.removeListener(CHANGE_EVENT_NAME, handle); 86 | done(); 87 | }; 88 | propertiesConfig.addChangeListener(handle); 89 | } catch (error) { 90 | done(error); 91 | } 92 | mockRequest.fetchConfig.mockResolvedValueOnce(mockResponse({ 93 | 'a.b.c': '1', 94 | 'b.a': '3', 95 | })); 96 | propertiesConfig.loadAndUpdateConfig().then(); 97 | }); 98 | 99 | it('should throw request error', async () => { 100 | const error = new Error('Mock reject fetch config'); 101 | mockRequest.fetchConfig.mockRejectedValueOnce(error); 102 | try { 103 | await propertiesConfig.loadAndUpdateConfig(); 104 | } catch (e) { 105 | expect(e).toEqual(error); 106 | } 107 | }); 108 | 109 | it('should update config and correctly', async () => { 110 | mockRequest.fetchConfig.mockResolvedValueOnce(mockResponse(initConfigs)); 111 | await propertiesConfig.loadAndUpdateConfig(); 112 | const newConfig = { 113 | '1': 'a', 114 | '2': 'b' 115 | }; 116 | mockRequest.fetchConfig.mockResolvedValueOnce(mockResponse(newConfig)); 117 | await propertiesConfig.loadAndUpdateConfig(); 118 | expect(propertiesConfig.getAllConfig()).toStrictEqual(new Map(Object.entries(newConfig))); 119 | }); 120 | 121 | it('should parse success when fetch config return null', async () => { 122 | mockRequest.fetchConfig.mockResolvedValueOnce(mockResponse(initConfigs)); 123 | await propertiesConfig.loadAndUpdateConfig(); 124 | expect(propertiesConfig.getAllConfig()).toStrictEqual(new Map(Object.entries(initConfigs))); 125 | 126 | mockRequest.fetchConfig.mockResolvedValueOnce(null); 127 | await propertiesConfig.loadAndUpdateConfig(); 128 | expect(propertiesConfig.getAllConfig()).toStrictEqual(new Map(Object.entries(initConfigs))); 129 | }); 130 | -------------------------------------------------------------------------------- /test/request.test.ts: -------------------------------------------------------------------------------- 1 | import { Request } from '../lib/request'; 2 | import http from 'http'; 3 | import { URL } from 'url'; 4 | import { PropertiesConfig } from '../lib/properties_config'; 5 | import { JSONConfig } from '../lib/json_config'; 6 | import { NOTIFICATION_ID_PLACEHOLDER } from '../lib/constants'; 7 | 8 | const releaseKey = '20170430092936-dee2d58e74515ff3'; 9 | const ip = '0.0.0.1'; 10 | const configServerUrl = 'http://localhost:3000/'; 11 | const appId = 'SampleApp'; 12 | const clusterName = 'default'; 13 | const namespaceName1 = 'test'; 14 | const namespaceName2 = 'first.json'; 15 | 16 | const fetchConfigResp = { 17 | appId, 18 | cluster: clusterName, 19 | namespaceName: namespaceName1, 20 | configurations: { 21 | 'portal.elastic.document.type': 'biz', 22 | 'portal.elastic.cluster.name': 'hermes-es-fws' 23 | }, 24 | releaseKey 25 | }; 26 | 27 | const fetchNotificationsResp = [ 28 | { 29 | namespaceName: namespaceName1, 30 | notificationId: 101 31 | }, 32 | { 33 | namespaceName: namespaceName2, 34 | notificationId: 63 35 | } 36 | ]; 37 | 38 | const configOptions = { 39 | configServerUrl, 40 | appId, 41 | clusterName, 42 | namespaceName: namespaceName1, 43 | }; 44 | 45 | const simpleConfigUrl = Request.formatConfigUrl({ 46 | ...configOptions 47 | }); 48 | 49 | const paramConfigUrl = Request.formatConfigUrl({ 50 | ...configOptions, 51 | releaseKey, 52 | ip, 53 | }); 54 | 55 | const notificationOptions = { 56 | configServerUrl, 57 | appId, 58 | clusterName, 59 | }; 60 | 61 | const propertiesConfig = new PropertiesConfig({ 62 | namespaceName: namespaceName1, 63 | ...notificationOptions 64 | }); 65 | 66 | const jsonConfig = new JSONConfig({ 67 | namespaceName: namespaceName2, 68 | ...notificationOptions 69 | }); 70 | 71 | const configsMap = new Map(); 72 | configsMap.set(namespaceName1, propertiesConfig); 73 | configsMap.set(namespaceName2, jsonConfig); 74 | 75 | const simpleNotificationUrl = Request.formatNotificationsUrl(notificationOptions, new Map()); 76 | 77 | const paramNotificationUrl = Request.formatNotificationsUrl(notificationOptions, configsMap); 78 | 79 | let mockHttpHandle: (req: http.IncomingMessage, res: http.ServerResponse & { 80 | req: http.IncomingMessage; 81 | }) => void; 82 | 83 | let server: http.Server; 84 | beforeAll((): Promise => { 85 | return new Promise(resolve => { 86 | 87 | const hostname = '127.0.0.1'; 88 | const port = 3000; 89 | 90 | server = http.createServer((req, res) => { 91 | mockHttpHandle(req, res); 92 | }); 93 | 94 | server.listen(port, hostname, () => { 95 | resolve(); 96 | }); 97 | }); 98 | }); 99 | 100 | afterAll((): Promise => { 101 | return new Promise(resolve => { 102 | server.close(() => { 103 | resolve(); 104 | }); 105 | }); 106 | }); 107 | 108 | describe('test config request', () => { 109 | describe('test format url', () => { 110 | it('should format the correct simple config url', () => { 111 | const simpleUrl = new URL(simpleConfigUrl); 112 | expect(simpleUrl.searchParams.get('releaseKey')).toBeNull(); 113 | expect(simpleUrl.searchParams.get('ip')).toBeNull(); 114 | expect(simpleUrl.origin + simpleUrl.pathname).toBe(`${configServerUrl}configs/SampleApp/default/test`); 115 | }); 116 | 117 | it('should format the correct config url with params', () => { 118 | const paramUrl = new URL(paramConfigUrl); 119 | expect(paramUrl.searchParams.get('releaseKey')).toBe(releaseKey); 120 | expect(paramUrl.searchParams.get('ip')).toBe(ip); 121 | expect(paramUrl.origin + paramUrl.pathname).toBe(`${configServerUrl}configs/SampleApp/default/test`); 122 | }); 123 | }); 124 | 125 | describe('test http request', () => { 126 | it('should return correct config response', async () => { 127 | mockHttpHandle = (req, res): void => { 128 | res.statusCode = 200; 129 | res.setHeader('Content-Type', 'application/json;charset=UTF-8'); 130 | res.end(JSON.stringify(fetchConfigResp)); 131 | }; 132 | const resp = await Request.fetchConfig(paramConfigUrl); 133 | expect(resp).toStrictEqual(fetchConfigResp); 134 | }); 135 | it('should throw server error', async () => { 136 | mockHttpHandle = (req, res): void => { 137 | res.statusCode = 500; 138 | res.end(JSON.stringify(fetchConfigResp)); 139 | }; 140 | await expect(Request.fetchConfig(paramConfigUrl)).rejects.toThrowErrorMatchingInlineSnapshot('"Http request error: 500, Internal Server Error"'); 141 | }); 142 | it('should receive http headers', async () => { 143 | mockHttpHandle = (req, res): void => { 144 | res.statusCode = 200; 145 | if (req.headers['header1'] != '1') res.statusCode = 500; 146 | res.end(JSON.stringify(fetchConfigResp)); 147 | }; 148 | const headers = { 149 | header1: '1' 150 | }; 151 | await expect(Request.fetchConfig(paramConfigUrl, headers)).resolves.toStrictEqual(fetchConfigResp); 152 | }); 153 | }); 154 | }); 155 | 156 | describe('test notification request', () => { 157 | describe('test format url', () => { 158 | it('should format the correct simple notification url', () => { 159 | const simpleUrl = new URL(simpleNotificationUrl); 160 | expect(simpleUrl.searchParams.get('notifications')).toBe('[]'); 161 | expect(simpleUrl.origin + simpleUrl.pathname).toBe(`${configServerUrl}notifications/v2`); 162 | }); 163 | 164 | it('should format the correct notification url with params', () => { 165 | const paramUrl = new URL(paramNotificationUrl); 166 | expect(JSON.parse(paramUrl.searchParams.get('notifications') || '').sort()) 167 | .toEqual([ 168 | { 169 | namespaceName: namespaceName1, 170 | notificationId: NOTIFICATION_ID_PLACEHOLDER 171 | }, 172 | { 173 | namespaceName: namespaceName2, 174 | notificationId: NOTIFICATION_ID_PLACEHOLDER 175 | } 176 | ].sort()); 177 | expect(paramUrl.origin + paramUrl.pathname).toBe(`${configServerUrl}notifications/v2`); 178 | }); 179 | }); 180 | 181 | describe('test http request', () => { 182 | it('should return correct notification response', async () => { 183 | mockHttpHandle = (req, res): void => { 184 | res.statusCode = 200; 185 | res.setHeader('Content-Type', 'application/json;charset=UTF-8'); 186 | res.end(JSON.stringify(fetchNotificationsResp)); 187 | }; 188 | const resp = await Request.fetchNotifications(paramNotificationUrl); 189 | expect(resp).toStrictEqual(fetchNotificationsResp); 190 | }); 191 | it('should throw server error', async () => { 192 | mockHttpHandle = (req, res): void => { 193 | res.statusCode = 500; 194 | res.end(JSON.stringify(fetchNotificationsResp)); 195 | }; 196 | await expect(Request.fetchConfig(paramNotificationUrl)).rejects.toThrowErrorMatchingInlineSnapshot('"Http request error: 500, Internal Server Error"'); 197 | }); 198 | it('should receive http headers', async () => { 199 | mockHttpHandle = (req, res): void => { 200 | res.statusCode = 200; 201 | if (req.headers['header1'] != '1') res.statusCode = 500; 202 | res.end(JSON.stringify(fetchNotificationsResp)); 203 | }; 204 | const headers = { 205 | header1: '1' 206 | }; 207 | await expect(Request.fetchConfig(paramNotificationUrl, headers)).resolves.toStrictEqual(fetchNotificationsResp); 208 | }); 209 | }); 210 | }); 211 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | // "incremental": true, /* Enable incremental compilation */ 5 | "target": "ES2018", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ 6 | "module": "UMD", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 7 | // "lib": [], /* Specify library files to be included in the compilation. */ 8 | // "allowJs": true, /* Allow javascript files to be compiled. */ 9 | // "checkJs": true, /* Report errors in .js files. */ 10 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 11 | "declaration": true, /* Generates corresponding '.d.ts' file. */ 12 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 13 | "sourceMap": true, /* Generates corresponding '.map' file. */ 14 | // "outFile": "./", /* Concatenate and emit output to single file. */ 15 | "outDir": "./dist", /* Redirect output structure to the directory. */ 16 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 17 | // "composite": true, /* Enable project compilation */ 18 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 19 | // "removeComments": true, /* Do not emit comments to output. */ 20 | // "noEmit": true, /* Do not emit outputs. */ 21 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 22 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 23 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 24 | 25 | /* Strict Type-Checking Options */ 26 | // "strict": true, /* Enable all strict type-checking options. */ 27 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 28 | "strictNullChecks": true, /* Enable strict null checks. */ 29 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 30 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 31 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 32 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 33 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 34 | 35 | /* Additional Checks */ 36 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 37 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 38 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 39 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 40 | 41 | /* Module Resolution Options */ 42 | "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 43 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 44 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 45 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 46 | // "typeRoots": [], /* List of folders to include type definitions from. */ 47 | "types": ["node", "jest"], /* Type declaration files to be included in compilation. */ 48 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 49 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 50 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 51 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 52 | 53 | /* Source Map Options */ 54 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 55 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 56 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 57 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 58 | 59 | /* Experimental Options */ 60 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 61 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 62 | 63 | /* Advanced Options */ 64 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 65 | }, 66 | "include": [ 67 | "./index.ts", 68 | "./lib/*.ts", 69 | // "examples", // for debug 70 | ], 71 | "exclude": [ 72 | ] 73 | } 74 | --------------------------------------------------------------------------------