Compare commits
14 Commits
30295dad3a
...
aa931c8f96
| Author | SHA1 | Date | |
|---|---|---|---|
| aa931c8f96 | |||
| 2fc477ab25 | |||
| 4d49a010c4 | |||
| a4740a3a26 | |||
| b49973c76b | |||
| f6e07e2cca | |||
| 94e0614852 | |||
| 675e1e6143 | |||
| 15c2f2982e | |||
| 9aac0f8316 | |||
| f72c27c588 | |||
| 950d47bcfa | |||
| 4653430c0f | |||
| aa4d2c6873 |
78
README.md
78
README.md
@ -1,11 +1,11 @@
|
||||
# FarmControl WebSocket Service
|
||||
|
||||
A WebSocket microservice for FarmControl that handles real-time communication and distributed locking using etcd.
|
||||
A WebSocket microservice for FarmControl that handles real-time communication and distributed locking.
|
||||
|
||||
## Features
|
||||
|
||||
- Real-time WebSocket communication
|
||||
- Distributed locking using etcd
|
||||
- Distributed locking
|
||||
- Keycloak authentication integration
|
||||
- MongoDB integration for user management
|
||||
- Event streaming and notifications
|
||||
@ -13,8 +13,8 @@ A WebSocket microservice for FarmControl that handles real-time communication an
|
||||
## Prerequisites
|
||||
|
||||
- Node.js (v16 or higher)
|
||||
- etcd server
|
||||
- MongoDB server
|
||||
- Redis server
|
||||
- Keycloak server (for authentication)
|
||||
|
||||
## Installation
|
||||
@ -29,19 +29,6 @@ A WebSocket microservice for FarmControl that handles real-time communication an
|
||||
|
||||
The application uses `config.json` for configuration. Update the following sections:
|
||||
|
||||
### Etcd Configuration
|
||||
|
||||
```json
|
||||
{
|
||||
"database": {
|
||||
"etcd": {
|
||||
"host": "localhost",
|
||||
"port": 2379
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### MongoDB Configuration
|
||||
|
||||
```json
|
||||
@ -84,59 +71,6 @@ npm run dev
|
||||
npm start
|
||||
```
|
||||
|
||||
## Etcd Setup
|
||||
|
||||
### Installation
|
||||
|
||||
#### Using Docker
|
||||
|
||||
```bash
|
||||
docker run -d --name etcd \
|
||||
-p 2379:2379 \
|
||||
-p 2380:2380 \
|
||||
quay.io/coreos/etcd:v3.5.0 \
|
||||
/usr/local/bin/etcd \
|
||||
--advertise-client-urls http://0.0.0.0:2379 \
|
||||
--listen-client-urls http://0.0.0.0:2379
|
||||
```
|
||||
|
||||
#### Using Homebrew (macOS)
|
||||
|
||||
```bash
|
||||
brew install etcd
|
||||
etcd
|
||||
```
|
||||
|
||||
#### Using apt (Ubuntu/Debian)
|
||||
|
||||
```bash
|
||||
sudo apt-get install etcd
|
||||
sudo systemctl start etcd
|
||||
```
|
||||
|
||||
### Verification
|
||||
|
||||
Test that etcd is running:
|
||||
|
||||
```bash
|
||||
curl http://localhost:2379/version
|
||||
```
|
||||
|
||||
## Migration from Redis
|
||||
|
||||
This application was migrated from Redis to etcd. The main changes include:
|
||||
|
||||
1. **Stream-like functionality**: Redis streams are replaced with etcd key-value pairs using a prefix pattern
|
||||
2. **Hash-like functionality**: Redis hashes are replaced with etcd key-value pairs using a prefix pattern
|
||||
3. **Pub/Sub**: Redis pub/sub is replaced with etcd watchers
|
||||
4. **Connection management**: Simplified connection handling with automatic reconnection
|
||||
|
||||
### Key Differences
|
||||
|
||||
- **Data structure**: etcd uses a flat key-value store, so we simulate Redis data structures using key prefixes
|
||||
- **Streams**: Instead of Redis streams, we use etcd keys with timestamps and random suffixes
|
||||
- **Watching**: etcd watchers provide real-time notifications for key changes
|
||||
- **Transactions**: etcd supports atomic operations for distributed locking
|
||||
|
||||
## API Endpoints
|
||||
|
||||
@ -153,7 +87,7 @@ The service exposes WebSocket endpoints for:
|
||||
```
|
||||
src/
|
||||
├── auth/ # Authentication logic
|
||||
├── database/ # Database connections (etcd, mongo)
|
||||
├── database/ # Database connections (redis, mongo)
|
||||
├── lock/ # Distributed locking
|
||||
├── notification/ # Notification management
|
||||
├── socket/ # WebSocket handling
|
||||
@ -162,7 +96,7 @@ src/
|
||||
|
||||
### Adding New Features
|
||||
|
||||
1. **Database operations**: Use the `etcdServer` instance for etcd operations
|
||||
1. **Database operations**: Use the `redisServer` instance for Redis operations
|
||||
2. **WebSocket events**: Extend the `SocketUser` class
|
||||
3. **Authentication**: Extend the `KeycloakAuth` class
|
||||
|
||||
@ -170,7 +104,7 @@ src/
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **Etcd connection failed**: Ensure etcd is running on the configured host and port
|
||||
1. **Redis connection failed**: Ensure Redis is running on the configured host and port
|
||||
2. **Authentication errors**: Verify Keycloak configuration and credentials
|
||||
3. **MongoDB connection issues**: Check MongoDB server status and connection string
|
||||
|
||||
|
||||
@ -15,10 +15,6 @@
|
||||
"requiredRoles": []
|
||||
},
|
||||
"database": {
|
||||
"etcd": {
|
||||
"host": "localhost",
|
||||
"port": 2379
|
||||
},
|
||||
"mongo": {
|
||||
"url": "mongodb://127.0.0.1:27017/farmcontrol"
|
||||
},
|
||||
@ -42,10 +38,6 @@
|
||||
"requiredRoles": []
|
||||
},
|
||||
"database": {
|
||||
"etcd": {
|
||||
"host": "localhost",
|
||||
"port": 2379
|
||||
},
|
||||
"mongo": {
|
||||
"url": "mongodb://farmcontrol.tombutcher.local:27017/farmcontrol"
|
||||
}
|
||||
|
||||
7721
package-lock.json
generated
7721
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -25,7 +25,6 @@
|
||||
"dayjs": "^1.11.19",
|
||||
"dotenv": "^17.2.3",
|
||||
"ejs": "^3.1.10",
|
||||
"etcd3": "^1.1.2",
|
||||
"express": "^5.1.0",
|
||||
"he": "^1.2.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
@ -38,7 +37,7 @@
|
||||
"object-hash": "^3.0.0",
|
||||
"posthtml": "^0.16.7",
|
||||
"puppeteer": "^24.31.0",
|
||||
"redis": "^4.6.14",
|
||||
"redis": "^5.10.0",
|
||||
"socket.io": "^4.8.1",
|
||||
"socket.io-adapter-mongo": "^2.0.5",
|
||||
"socketio-jwt": "^4.6.2"
|
||||
|
||||
@ -133,7 +133,9 @@ export class CodeAuth {
|
||||
// Verify a code with the database
|
||||
async verifyCode(id, authCode) {
|
||||
try {
|
||||
logger.trace('Verifying code:', { id, authCode });
|
||||
const host = await getObject({ model: hostModel, id, cached: true });
|
||||
logger.trace('Host retrieved:', host);
|
||||
if (host == undefined) {
|
||||
const error = 'Host not found.';
|
||||
logger.warn(error, 'Host:', id);
|
||||
@ -154,6 +156,7 @@ export class CodeAuth {
|
||||
logger.warn(error, 'Host:', id);
|
||||
return { valid: false, error: error };
|
||||
}
|
||||
logger.trace('Code verification successful:', host);
|
||||
return { valid: true, host: host };
|
||||
} catch (error) {
|
||||
logger.error('Code verification error:', error.message);
|
||||
|
||||
@ -5,12 +5,14 @@ import {
|
||||
editAuditLog,
|
||||
distributeUpdate,
|
||||
newAuditLog,
|
||||
distributeNew
|
||||
distributeNew,
|
||||
distributeStats
|
||||
} from './utils.js';
|
||||
import log4js from 'log4js';
|
||||
import { loadConfig } from '../config.js';
|
||||
import { jsonToCacheKey } from '../utils.js';
|
||||
import { getQueryToCacheKey } from '../utils.js';
|
||||
import { redisServer } from './redis.js';
|
||||
import { auditLogModel } from './schemas/management/auditlog.schema.js';
|
||||
|
||||
const config = loadConfig();
|
||||
|
||||
@ -23,27 +25,19 @@ cacheLogger.level = config.server.logLevel;
|
||||
const CACHE_TTL_SECONDS = config.database?.redis?.ttlSeconds || 5;
|
||||
|
||||
export const retrieveObjectCache = async ({ model, id, populate = [] }) => {
|
||||
const cacheKeyObject = {
|
||||
model: model.modelName,
|
||||
id: id?.toString()
|
||||
};
|
||||
const cacheKey = getQueryToCacheKey({ model: model.modelName, id, populate });
|
||||
|
||||
const cacheKey = jsonToCacheKey(cacheKeyObject);
|
||||
|
||||
cacheLogger.trace('Retrieving:', cacheKeyObject);
|
||||
cacheLogger.trace('Retrieving:', cacheKey);
|
||||
|
||||
try {
|
||||
const cachedObject = await redisServer.getKey(cacheKey);
|
||||
|
||||
if (cachedObject == null) {
|
||||
cacheLogger.trace('Miss:', cacheKeyObject);
|
||||
cacheLogger.trace('Miss:', cacheKey);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
cacheLogger.trace('Hit:', {
|
||||
model: model.modelName,
|
||||
id: cacheKeyObject.id
|
||||
});
|
||||
cacheLogger.trace('Hit:', cacheKey);
|
||||
|
||||
return cachedObject;
|
||||
} catch (err) {
|
||||
@ -52,65 +46,43 @@ export const retrieveObjectCache = async ({ model, id, populate = [] }) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const retrieveListCache = async ({
|
||||
export const updateObjectCache = async ({
|
||||
model,
|
||||
populate = [],
|
||||
filter = {},
|
||||
sort = '',
|
||||
order = 'ascend',
|
||||
project = {}
|
||||
id,
|
||||
object,
|
||||
populate = []
|
||||
}) => {
|
||||
const cacheKeyObject = {
|
||||
model: model.modelName,
|
||||
populate,
|
||||
filter,
|
||||
sort,
|
||||
project,
|
||||
order
|
||||
};
|
||||
const cacheKeyFilter = `${model.modelName}:${id?.toString()}*`;
|
||||
const cacheKey = getQueryToCacheKey({ model: model.modelName, id, populate });
|
||||
|
||||
const cacheKey = jsonToCacheKey(cacheKeyObject);
|
||||
|
||||
cacheLogger.trace('Retrieving:', cacheKeyObject);
|
||||
cacheLogger.trace('Updating:', cacheKeyFilter);
|
||||
|
||||
try {
|
||||
const cachedList = await redisServer.getKey(cacheKey);
|
||||
// Get all keys matching the filter pattern
|
||||
const matchingKeys = await redisServer.getKeysByPattern(cacheKeyFilter);
|
||||
|
||||
if (cachedList != null) {
|
||||
cacheLogger.trace('Hit:', {
|
||||
...cacheKeyObject,
|
||||
length: cachedList.length
|
||||
});
|
||||
return cachedList;
|
||||
logger.trace('Matching keys:', matchingKeys);
|
||||
|
||||
// Merge the object with each cached object and update
|
||||
const mergedObjects = [];
|
||||
for (const key of matchingKeys) {
|
||||
logger.trace('Updating object cache:', key);
|
||||
const cachedObject = (await redisServer.getKey(key)) || {};
|
||||
const mergedObject = _.merge(cachedObject, object);
|
||||
await redisServer.setKey(key, mergedObject, CACHE_TTL_SECONDS);
|
||||
mergedObjects.push(mergedObject);
|
||||
}
|
||||
|
||||
cacheLogger.trace('Miss:', {
|
||||
model: model.modelName
|
||||
});
|
||||
return undefined;
|
||||
} catch (err) {
|
||||
cacheLogger.error('Error retrieving list from Redis cache:', err);
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
export const updateObjectCache = async ({ model, id, object }) => {
|
||||
const cacheKeyObject = {
|
||||
model: model.modelName,
|
||||
id: id?.toString()
|
||||
};
|
||||
|
||||
const cacheKey = jsonToCacheKey(cacheKeyObject);
|
||||
|
||||
cacheLogger.trace('Updating:', cacheKeyObject);
|
||||
|
||||
try {
|
||||
const cachedObject = (await redisServer.getKey(cacheKey)) || {};
|
||||
const mergedObject = _.merge(cachedObject, object);
|
||||
|
||||
const cacheObject = (await redisServer.getKey(cacheKey)) || {};
|
||||
const mergedObject = _.merge(cacheObject, object);
|
||||
await redisServer.setKey(cacheKey, mergedObject, CACHE_TTL_SECONDS);
|
||||
cacheLogger.trace('Updated:', { ...cacheKeyObject });
|
||||
|
||||
cacheLogger.trace('Updated:', {
|
||||
filter: cacheKeyFilter,
|
||||
keysUpdated: matchingKeys.length
|
||||
});
|
||||
|
||||
// Return the merged object
|
||||
return mergedObject;
|
||||
} catch (err) {
|
||||
cacheLogger.error('Error updating object in Redis cache:', err);
|
||||
@ -120,69 +92,27 @@ export const updateObjectCache = async ({ model, id, object }) => {
|
||||
};
|
||||
|
||||
export const deleteObjectCache = async ({ model, id }) => {
|
||||
const cacheKeyObject = {
|
||||
model: model.modelName,
|
||||
id: id?.toString()
|
||||
};
|
||||
const cacheKeyFilter = `${model.modelName}:${id?.toString()}*`;
|
||||
|
||||
cacheLogger.trace('Deleting:', {
|
||||
...cacheKeyObject
|
||||
});
|
||||
cacheLogger.trace('Deleting:', cacheKeyFilter);
|
||||
|
||||
try {
|
||||
// Note: we currently delete the non-populated key; populated variants will expire via TTL.
|
||||
const cacheKey = jsonToCacheKey({ ...cacheKeyObject, populate: [] });
|
||||
await redisServer.deleteKey(cacheKey);
|
||||
// Get all keys matching the filter pattern and delete them
|
||||
const matchingKeys = await redisServer.getKeysByPattern(cacheKeyFilter);
|
||||
|
||||
for (const cacheKey of matchingKeys) {
|
||||
await redisServer.deleteKey(cacheKey);
|
||||
}
|
||||
|
||||
cacheLogger.trace('Deleted:', {
|
||||
...cacheKeyObject
|
||||
filter: cacheKeyFilter,
|
||||
keysDeleted: matchingKeys.length
|
||||
});
|
||||
} catch (err) {
|
||||
cacheLogger.error('Error deleting object from Redis cache:', err);
|
||||
}
|
||||
};
|
||||
|
||||
export const updateListCache = ({
|
||||
model,
|
||||
objects,
|
||||
populate = [],
|
||||
filter = {},
|
||||
sort = '',
|
||||
order = 'ascend',
|
||||
project = {}
|
||||
}) => {
|
||||
const cacheKeyObject = {
|
||||
model: model.modelName,
|
||||
populate,
|
||||
filter,
|
||||
sort,
|
||||
project,
|
||||
order
|
||||
};
|
||||
|
||||
cacheLogger.trace('Updating:', {
|
||||
...cacheKeyObject,
|
||||
length: objects.length
|
||||
});
|
||||
|
||||
const cacheKey = jsonToCacheKey(cacheKeyObject);
|
||||
|
||||
return (async () => {
|
||||
try {
|
||||
await redisServer.setKey(cacheKey, objects, CACHE_TTL_SECONDS);
|
||||
|
||||
cacheLogger.trace('Updated:', {
|
||||
...cacheKeyObject,
|
||||
length: objects.length
|
||||
});
|
||||
} catch (err) {
|
||||
cacheLogger.error('Error updating list in Redis cache:', err);
|
||||
}
|
||||
|
||||
return objects;
|
||||
})();
|
||||
};
|
||||
|
||||
// Reusable function to list objects with aggregation, filtering, search, sorting, and pagination
|
||||
export const listObjects = async ({
|
||||
model,
|
||||
@ -204,20 +134,6 @@ export const listObjects = async ({
|
||||
cached
|
||||
});
|
||||
|
||||
if (cached == true) {
|
||||
const objectsCache = await retrieveListCache({
|
||||
model,
|
||||
populate,
|
||||
filter,
|
||||
sort,
|
||||
order,
|
||||
project
|
||||
});
|
||||
if (objectsCache != undefined) {
|
||||
return objectsCache;
|
||||
}
|
||||
}
|
||||
|
||||
// Fix: descend should be -1, ascend should be 1
|
||||
const sortOrder = order === 'descend' ? -1 : 1;
|
||||
|
||||
@ -261,16 +177,6 @@ export const listObjects = async ({
|
||||
|
||||
const finalResult = expandObjectIds(queryResult);
|
||||
|
||||
updateListCache({
|
||||
model,
|
||||
objects: finalResult,
|
||||
populate,
|
||||
filter,
|
||||
sort,
|
||||
order,
|
||||
project
|
||||
});
|
||||
|
||||
logger.trace('Retreived from database:', {
|
||||
model,
|
||||
populate,
|
||||
@ -338,7 +244,9 @@ export const getObject = async ({
|
||||
populate
|
||||
});
|
||||
|
||||
updateObjectCache({
|
||||
logger.trace(finalResult);
|
||||
|
||||
await updateObjectCache({
|
||||
model: model,
|
||||
id: finalResult._id.toString(),
|
||||
populate,
|
||||
@ -353,6 +261,152 @@ export const getObject = async ({
|
||||
}
|
||||
};
|
||||
|
||||
// Utility to run one or many rollup aggregations in a single query via $facet.
|
||||
export const aggregateRollups = async ({
|
||||
model,
|
||||
baseFilter = {},
|
||||
rollupConfigs = []
|
||||
}) => {
|
||||
if (!rollupConfigs.length) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const facetStage = rollupConfigs.reduce((facets, definition, index) => {
|
||||
const key = definition.name || `rollup${index}`;
|
||||
const matchStage = {
|
||||
$match: { ...baseFilter, ...(definition.filter || {}) }
|
||||
};
|
||||
const groupStage = { $group: { _id: null } };
|
||||
|
||||
(definition.rollups || []).forEach(rollup => {
|
||||
switch (rollup.operation) {
|
||||
case 'sum':
|
||||
groupStage.$group[rollup.name] = { $sum: `$${rollup.property}` };
|
||||
break;
|
||||
case 'count':
|
||||
groupStage.$group[rollup.name] = { $sum: 1 };
|
||||
break;
|
||||
case 'avg':
|
||||
groupStage.$group[rollup.name] = { $avg: `$${rollup.property}` };
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unsupported rollup operation: ${rollup.operation}`);
|
||||
}
|
||||
});
|
||||
|
||||
facets[key] = [matchStage, groupStage];
|
||||
return facets;
|
||||
}, {});
|
||||
|
||||
const [results] = await model.aggregate([{ $facet: facetStage }]);
|
||||
|
||||
return rollupConfigs.reduce((acc, definition, index) => {
|
||||
const key = definition.name || `rollup${index}`;
|
||||
const rawResult = results?.[key]?.[0] || {};
|
||||
|
||||
// Transform the result to nest rollup values under operation type
|
||||
const transformedResult = {};
|
||||
(definition.rollups || []).forEach(rollup => {
|
||||
const value = rawResult[rollup.name] || 0;
|
||||
// If there's only one rollup and its name matches the key, flatten the structure
|
||||
if (definition.rollups.length === 1 && rollup.name === key) {
|
||||
transformedResult[rollup.operation] = value;
|
||||
} else {
|
||||
transformedResult[rollup.name] = { [rollup.operation]: value };
|
||||
}
|
||||
});
|
||||
|
||||
acc[key] = transformedResult;
|
||||
return acc;
|
||||
}, {});
|
||||
};
|
||||
|
||||
// Reusable function to aggregate rollups over history using audit logs
|
||||
export const aggregateRollupsHistory = async ({
|
||||
model,
|
||||
baseFilter = {},
|
||||
rollupConfigs = [],
|
||||
startDate,
|
||||
endDate
|
||||
}) => {
|
||||
if (!rollupConfigs.length) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Helper to map filter keys to audit log structure
|
||||
const mapFilterToAudit = filter => {
|
||||
if (Array.isArray(filter)) {
|
||||
return filter.map(mapFilterToAudit);
|
||||
}
|
||||
|
||||
if (_.isPlainObject(filter)) {
|
||||
const newFilter = {};
|
||||
for (const key in filter) {
|
||||
if (['$or', '$and', '$nor', '$in', '$nin'].includes(key)) {
|
||||
newFilter[key] = mapFilterToAudit(filter[key]);
|
||||
} else if (key.startsWith('$')) {
|
||||
newFilter[key] = mapFilterToAudit(filter[key]);
|
||||
} else if (
|
||||
[
|
||||
'operation',
|
||||
'parent',
|
||||
'parentType',
|
||||
'owner',
|
||||
'ownerType',
|
||||
'createdAt',
|
||||
'updatedAt',
|
||||
'_id',
|
||||
'_reference',
|
||||
'changes'
|
||||
].includes(key)
|
||||
) {
|
||||
newFilter[key] = mapFilterToAudit(filter[key]);
|
||||
} else {
|
||||
newFilter[`changes.new.${key}`] = mapFilterToAudit(filter[key]);
|
||||
}
|
||||
}
|
||||
return newFilter;
|
||||
}
|
||||
|
||||
return filter;
|
||||
};
|
||||
|
||||
const matchQuery = {
|
||||
parentType: model.modelName,
|
||||
...mapFilterToAudit(baseFilter)
|
||||
};
|
||||
|
||||
if (startDate || endDate) {
|
||||
matchQuery.createdAt = {};
|
||||
if (startDate) matchQuery.createdAt.$gte = new Date(startDate);
|
||||
if (endDate) matchQuery.createdAt.$lte = new Date(endDate);
|
||||
if (Object.keys(matchQuery.createdAt).length === 0)
|
||||
delete matchQuery.createdAt;
|
||||
}
|
||||
|
||||
const mappedRollupConfigs = rollupConfigs.map(config => ({
|
||||
...config,
|
||||
filter: config.filter ? mapFilterToAudit(config.filter) : undefined,
|
||||
rollups: (config.rollups || []).map(rollup => ({
|
||||
...rollup,
|
||||
property: `changes.new.${rollup.property}`
|
||||
}))
|
||||
}));
|
||||
|
||||
return await aggregateRollups({
|
||||
model: auditLogModel,
|
||||
baseFilter: matchQuery,
|
||||
rollupConfigs: mappedRollupConfigs
|
||||
});
|
||||
};
|
||||
|
||||
export const getModelStats = async ({ model }) => {
|
||||
if (!model.stats) {
|
||||
return { error: 'Model does not have a stats method.', code: 500 };
|
||||
}
|
||||
return await model.stats();
|
||||
};
|
||||
|
||||
// Reusable function to edit an object by ID, with audit logging and distribution
|
||||
export const editObject = async ({
|
||||
model,
|
||||
@ -405,13 +459,24 @@ export const editObject = async ({
|
||||
// Distribute update
|
||||
await distributeUpdate(updateData, id, parentType);
|
||||
|
||||
updateObjectCache({
|
||||
await updateObjectCache({
|
||||
model: model,
|
||||
id: id.toString(),
|
||||
object: { ...previousExpandedObject, ...updateData },
|
||||
populate
|
||||
});
|
||||
|
||||
if (model.recalculate) {
|
||||
logger.debug(`Recalculating ${model.modelName}`);
|
||||
await model.recalculate(newExpandedObject, owner, ownerType);
|
||||
}
|
||||
|
||||
if (model.stats) {
|
||||
logger.debug(`Getting stats for ${model.modelName}`);
|
||||
const statsData = await model.stats(newExpandedObject);
|
||||
await distributeStats(statsData, parentType);
|
||||
}
|
||||
|
||||
return { ...previousExpandedObject, ...updateData };
|
||||
} catch (error) {
|
||||
logger.error('editObject error:', error);
|
||||
@ -441,10 +506,11 @@ export const newObject = async ({
|
||||
|
||||
await distributeNew(created._id, parentType);
|
||||
|
||||
updateObjectCache({
|
||||
await updateObjectCache({
|
||||
model: model,
|
||||
id: created._id.toString(),
|
||||
object: { _id: created._id, ...newData }
|
||||
object: { _id: created._id, ...newData },
|
||||
populate: []
|
||||
});
|
||||
|
||||
return created;
|
||||
|
||||
@ -1,386 +0,0 @@
|
||||
import { Etcd3 } from 'etcd3';
|
||||
import log4js from 'log4js';
|
||||
import { loadConfig } from '../config.js';
|
||||
|
||||
const config = loadConfig();
|
||||
const logger = log4js.getLogger('Etcd');
|
||||
logger.level = config.server.logLevel;
|
||||
|
||||
class EtcdServer {
|
||||
constructor() {
|
||||
this.client = null;
|
||||
this.prefixPutWatchers = new Map(); // prefix → { watcher, callbacks }
|
||||
this.prefixDeleteWatchers = new Map(); // prefix → { watcher, callbacks }
|
||||
this.keyPutWatchers = new Map(); // key → { watcher, callbacks }
|
||||
this.keyDeleteWatchers = new Map(); // key → { watcher, callbacks }
|
||||
const etcdConfig = config.database?.etcd || config.database; // fallback for production config
|
||||
const host = etcdConfig.host || 'localhost';
|
||||
const port = etcdConfig.port || 2379;
|
||||
this.hosts = [`${host}:${port}`];
|
||||
logger.trace(`EtcdServer: hosts set to ${JSON.stringify(this.hosts)}`);
|
||||
}
|
||||
|
||||
async connect() {
|
||||
if (!this.client) {
|
||||
logger.info('Connecting to Etcd...');
|
||||
logger.trace(
|
||||
`Creating Etcd client with hosts ${JSON.stringify(this.hosts)}`
|
||||
);
|
||||
this.client = new Etcd3({
|
||||
hosts: this.hosts
|
||||
});
|
||||
|
||||
// Test connection
|
||||
try {
|
||||
await this.client.get('test-connection').string();
|
||||
logger.trace('Etcd client connected successfully.');
|
||||
} catch (error) {
|
||||
if (error.code === 'NOT_FOUND') {
|
||||
logger.trace(
|
||||
'Etcd client connected successfully (test key not found as expected).'
|
||||
);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.trace('Etcd client already exists, skipping connection.');
|
||||
}
|
||||
return this.client;
|
||||
}
|
||||
|
||||
async getClient() {
|
||||
if (!this.client) {
|
||||
logger.trace('No client found, calling connect().');
|
||||
await this.connect();
|
||||
}
|
||||
return this.client;
|
||||
}
|
||||
|
||||
async setKey(key, value) {
|
||||
const client = await this.getClient();
|
||||
const stringValue =
|
||||
typeof value === 'string' ? value : JSON.stringify(value);
|
||||
|
||||
await client.put(key).value(stringValue);
|
||||
logger.trace(`Set key: ${key}, value: ${stringValue}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
async getKey(key) {
|
||||
const client = await this.getClient();
|
||||
|
||||
try {
|
||||
const value = await client.get(key).string();
|
||||
logger.trace(`Retrieved key: ${key}, value: ${value}`);
|
||||
|
||||
// Try to parse as JSON, fallback to string
|
||||
try {
|
||||
return JSON.parse(value);
|
||||
} catch {
|
||||
return value;
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.code === 'NOT_FOUND') {
|
||||
logger.trace(`Key not found: ${key}`);
|
||||
return null;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async deleteKey(key) {
|
||||
const client = await this.getClient();
|
||||
|
||||
try {
|
||||
await client.delete().key(key);
|
||||
logger.trace(`Deleted key: ${key}`);
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
if (error.code === 'NOT_FOUND') {
|
||||
const error = `Key not found for deletion.`;
|
||||
console.log(error, 'Key:', key);
|
||||
return { error: error };
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async onPrefixPutEvent(prefix, owner, callback) {
|
||||
const client = await this.getClient();
|
||||
const watcherKey = prefix;
|
||||
|
||||
if (this.prefixPutWatchers.has(watcherKey)) {
|
||||
this.prefixPutWatchers.get(watcherKey).callbacks.set(owner, callback);
|
||||
logger.trace(`Added put callback for owner=${owner} on prefix=${prefix}`);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.trace(`Creating new put watcher for prefix: ${prefix}`);
|
||||
const watcher = await client.watch().prefix(prefix).create();
|
||||
const callbacks = new Map();
|
||||
callbacks.set(owner, callback);
|
||||
|
||||
watcher.on('put', (kv, previous) => {
|
||||
logger.trace(`Prefix put event detected: ${prefix}, key: ${kv.key}`);
|
||||
const valueStr = kv.value.toString();
|
||||
let parsedValue;
|
||||
try {
|
||||
parsedValue = JSON.parse(valueStr);
|
||||
} catch {
|
||||
parsedValue = valueStr;
|
||||
}
|
||||
|
||||
for (const [ownerId, cb] of callbacks) {
|
||||
try {
|
||||
cb(kv.key.toString(), parsedValue, kv, previous);
|
||||
} catch (err) {
|
||||
logger.error(
|
||||
`Error in onPrefixPutEvent callback for owner=${ownerId}, prefix=${prefix}:`,
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.prefixPutWatchers.set(watcherKey, { watcher, callbacks });
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
async onPrefixDeleteEvent(prefix, owner, callback) {
|
||||
const client = await this.getClient();
|
||||
const watcherKey = prefix;
|
||||
|
||||
if (this.prefixDeleteWatchers.has(watcherKey)) {
|
||||
this.prefixDeleteWatchers.get(watcherKey).callbacks.set(owner, callback);
|
||||
logger.trace(
|
||||
`Added delete callback for owner=${owner} on prefix=${prefix}`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.trace(`Creating new delete watcher for prefix: ${prefix}`);
|
||||
const watcher = await client.watch().prefix(prefix).create();
|
||||
const callbacks = new Map();
|
||||
callbacks.set(owner, callback);
|
||||
|
||||
watcher.on('delete', (kv, previous) => {
|
||||
logger.trace(`Prefix delete event detected: ${prefix}, key: ${kv.key}`);
|
||||
for (const [ownerId, cb] of callbacks) {
|
||||
try {
|
||||
cb(kv.key.toString(), kv, previous);
|
||||
} catch (err) {
|
||||
logger.error(
|
||||
`Error in onPrefixDeleteEvent callback for owner=${ownerId}, prefix=${prefix}:`,
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.prefixDeleteWatchers.set(watcherKey, { watcher, callbacks });
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
async onKeyPutEvent(key, owner, callback) {
|
||||
const client = await this.getClient();
|
||||
const watcherKey = key;
|
||||
|
||||
if (this.keyPutWatchers.has(watcherKey)) {
|
||||
this.keyPutWatchers.get(watcherKey).callbacks.set(owner, callback);
|
||||
logger.trace(`Added put callback for owner: ${owner}, on key: ${key}`);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.trace(`Creating new put watcher for key: ${key}`);
|
||||
const watcher = await client.watch().key(key).create();
|
||||
const callbacks = new Map();
|
||||
callbacks.set(owner, callback);
|
||||
|
||||
watcher.on('put', (kv, previous) => {
|
||||
logger.trace(`Key put event detected: ${key}, key: ${kv.key}`);
|
||||
const valueStr = kv.value.toString();
|
||||
let parsedValue;
|
||||
try {
|
||||
parsedValue = JSON.parse(valueStr);
|
||||
} catch {
|
||||
parsedValue = valueStr;
|
||||
}
|
||||
|
||||
for (const [ownerId, cb] of callbacks) {
|
||||
try {
|
||||
cb(kv.key.toString(), parsedValue, kv, previous);
|
||||
} catch (err) {
|
||||
logger.error(
|
||||
`Error in onKeyPutEvent callback for owner: ${ownerId}, key: ${key}:`,
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.keyPutWatchers.set(watcherKey, { watcher, callbacks });
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
async onKeyDeleteEvent(key, owner, callback) {
|
||||
const client = await this.getClient();
|
||||
const watcherKey = key;
|
||||
|
||||
if (this.keyDeleteWatchers.has(watcherKey)) {
|
||||
this.keyDeleteWatchers.get(watcherKey).callbacks.set(owner, callback);
|
||||
logger.trace(`Added delete callback for owner: ${owner} on key: ${key}`);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.trace(`Creating new delete watcher for key: ${key}`);
|
||||
const watcher = await client.watch().key(key).create();
|
||||
const callbacks = new Map();
|
||||
callbacks.set(owner, callback);
|
||||
|
||||
watcher.on('delete', (kv, previous) => {
|
||||
logger.trace(`Key delete event detected: ${key}, key: ${kv.key}`);
|
||||
for (const [ownerId, cb] of callbacks) {
|
||||
try {
|
||||
cb(kv.key.toString(), kv, previous);
|
||||
} catch (err) {
|
||||
logger.error(
|
||||
`Error in onKeyDeleteEvent callback for owner=${ownerId}, key=${key}:`,
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.keyDeleteWatchers.set(watcherKey, { watcher, callbacks });
|
||||
}
|
||||
|
||||
async onKeyEvent(key, callback) {
|
||||
const client = await this.getClient();
|
||||
logger.trace(`Setting up watcher for key events: ${key}`);
|
||||
|
||||
client
|
||||
.watch()
|
||||
.key(key)
|
||||
.create()
|
||||
.then(watcher => {
|
||||
// Handle put events
|
||||
watcher.on('put', (kv, previous) => {
|
||||
logger.trace(`Key put event detected: ${key}`);
|
||||
try {
|
||||
const value = kv.value.toString();
|
||||
let parsedValue;
|
||||
try {
|
||||
parsedValue = JSON.parse(value);
|
||||
} catch {
|
||||
parsedValue = value;
|
||||
}
|
||||
callback(key, parsedValue, kv, previous);
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
`Error in onKeyEvent put callback for key ${key}:`,
|
||||
error
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// Handle delete events
|
||||
watcher.on('delete', (kv, previous) => {
|
||||
logger.trace(`Key delete event detected: ${key}`);
|
||||
try {
|
||||
callback(key, null, kv, previous);
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
`Error in onKeyEvent delete callback for key ${key}:`,
|
||||
error
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// Store watcher with a unique key
|
||||
const watcherKey = `event:key:${key}`;
|
||||
this.watchers.set(watcherKey, watcher);
|
||||
});
|
||||
}
|
||||
|
||||
async removePrefixWatcher(prefix, owner, type = 'put') {
|
||||
const store =
|
||||
type === 'put' ? this.prefixPutWatchers : this.prefixDeleteWatchers;
|
||||
const entry = store.get(prefix);
|
||||
|
||||
if (!entry) {
|
||||
logger.trace(`Watcher not found for prefix: ${prefix}, type: ${type}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (entry.callbacks.delete(owner)) {
|
||||
logger.trace(
|
||||
`Removed ${type} callback for owner: ${owner} on prefix: ${prefix}`
|
||||
);
|
||||
} else {
|
||||
logger.trace(
|
||||
`No ${type} callback found for owner: ${owner} on prefix: ${prefix}`
|
||||
);
|
||||
}
|
||||
|
||||
if (entry.callbacks.size === 0) {
|
||||
logger.trace(`No callbacks left, stopping ${type} watcher for ${prefix}`);
|
||||
entry.watcher.removeAllListeners();
|
||||
await entry.watcher.cancel();
|
||||
store.delete(prefix);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
async removeKeyWatcher(key, owner, type = 'put') {
|
||||
const store = type === 'put' ? this.keyPutWatchers : this.keyDeleteWatchers;
|
||||
const entry = store.get(key);
|
||||
|
||||
if (!entry) {
|
||||
logger.trace(`Watcher not found for key: ${key}, type: ${type}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (entry.callbacks.delete(owner)) {
|
||||
logger.trace(
|
||||
`Removed ${type} callback for owner: ${owner} on key: ${key}`
|
||||
);
|
||||
} else {
|
||||
logger.trace(
|
||||
`No ${type} callback found for owner: ${owner} on key: ${key}`
|
||||
);
|
||||
}
|
||||
|
||||
if (entry.callbacks.size === 0) {
|
||||
logger.trace(`No callbacks left, stopping ${type} watcher for ${key}`);
|
||||
entry.watcher.removeAllListeners();
|
||||
await entry.watcher.cancel();
|
||||
store.delete(key);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
async disconnect() {
|
||||
logger.info('Disconnecting from Etcd...');
|
||||
|
||||
// Stop all watchers
|
||||
for (const [key, watcher] of this.watchers) {
|
||||
logger.trace(`Stopping watcher: ${key}`);
|
||||
watcher.removeAllListeners();
|
||||
await watcher.close();
|
||||
}
|
||||
this.watchers.clear();
|
||||
|
||||
if (this.client) {
|
||||
await this.client.close();
|
||||
this.client = null;
|
||||
logger.info('Disconnected from Etcd');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const etcdServer = new EtcdServer();
|
||||
|
||||
export { EtcdServer, etcdServer };
|
||||
@ -44,6 +44,14 @@ class MongoServer {
|
||||
}
|
||||
return mongoose.connection;
|
||||
}
|
||||
|
||||
async disconnect() {
|
||||
if (!this.connected) return;
|
||||
logger.info('Disconnecting from MongoDB...');
|
||||
await mongoose.connection.close();
|
||||
this.connected = false;
|
||||
logger.info('Disconnected from MongoDB');
|
||||
}
|
||||
}
|
||||
|
||||
const mongoServer = new MongoServer();
|
||||
|
||||
@ -28,11 +28,20 @@ class RedisServer {
|
||||
|
||||
async connect() {
|
||||
if (this.connected) return;
|
||||
logger.info('Connecting to Redis...');
|
||||
await this.client.connect();
|
||||
this.connected = true;
|
||||
logger.info('Connected to Redis');
|
||||
}
|
||||
|
||||
async disconnect() {
|
||||
if (!this.connected) return;
|
||||
logger.info('Disconnecting from Redis...');
|
||||
await this.client.quit();
|
||||
this.connected = false;
|
||||
logger.info('Disconnected from Redis');
|
||||
}
|
||||
|
||||
async setKey(key, value, ttlSeconds) {
|
||||
await this.connect();
|
||||
const payload = typeof value === 'string' ? value : JSON.stringify(value);
|
||||
@ -58,6 +67,24 @@ class RedisServer {
|
||||
await this.connect();
|
||||
await this.client.del(key);
|
||||
}
|
||||
|
||||
async getKeysByPattern(pattern) {
|
||||
await this.connect();
|
||||
const keys = [];
|
||||
let cursor = '0';
|
||||
logger.trace('Getting keys by pattern:', pattern);
|
||||
do {
|
||||
logger.trace('Scanning keys:', cursor);
|
||||
const result = await this.client.scan(cursor, {
|
||||
MATCH: pattern,
|
||||
COUNT: 100
|
||||
});
|
||||
cursor = result.cursor;
|
||||
logger.trace('Result:', result);
|
||||
keys.push(...result.keys);
|
||||
} while (cursor !== '0');
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
|
||||
const redisServer = new RedisServer();
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import mongoose from 'mongoose';
|
||||
import { generateId } from '../../utils.js';
|
||||
const { Schema } = mongoose;
|
||||
import { aggregateRollups, aggregateRollupsHistory } from '../../database.js';
|
||||
|
||||
// Define the main filamentStock schema
|
||||
const filamentStockSchema = new Schema(
|
||||
@ -23,6 +24,35 @@ const filamentStockSchema = new Schema(
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
const rollupConfigs = [
|
||||
{
|
||||
name: 'totalCurrentWeight',
|
||||
filter: {},
|
||||
rollups: [{ name: 'totalCurrentWeight', property: 'currentWeight.net', operation: 'sum' }],
|
||||
},
|
||||
];
|
||||
|
||||
filamentStockSchema.statics.stats = async function () {
|
||||
const results = await aggregateRollups({
|
||||
model: this,
|
||||
rollupConfigs: rollupConfigs,
|
||||
});
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
filamentStockSchema.statics.history = async function (from, to) {
|
||||
const results = await aggregateRollupsHistory({
|
||||
model: this,
|
||||
startDate: from,
|
||||
endDate: to,
|
||||
rollupConfigs: rollupConfigs,
|
||||
});
|
||||
|
||||
// Return time-series data array
|
||||
return results;
|
||||
};
|
||||
|
||||
// Add virtual id getter
|
||||
filamentStockSchema.virtual('id').get(function () {
|
||||
return this._id;
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
import mongoose from 'mongoose';
|
||||
import { purchaseOrderModel } from './purchaseorder.schema.js';
|
||||
import { aggregateRollups, editObject } from '../../database.js';
|
||||
import { generateId } from '../../utils.js';
|
||||
const { Schema } = mongoose;
|
||||
|
||||
@ -20,6 +22,52 @@ const orderItemSchema = new Schema(
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
orderItemSchema.statics.recalculate = async function (orderItem, user) {
|
||||
// Only purchase orders are supported for now
|
||||
if (orderItem.orderType !== 'purchaseOrder') {
|
||||
return;
|
||||
}
|
||||
|
||||
const orderId = orderItem.order?._id || orderItem.order;
|
||||
if (!orderId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const rollupResults = await aggregateRollups({
|
||||
model: this,
|
||||
baseFilter: {
|
||||
order: new mongoose.Types.ObjectId(orderId),
|
||||
orderType: orderItem.orderType,
|
||||
},
|
||||
rollupConfigs: [
|
||||
{
|
||||
name: 'orderTotals',
|
||||
rollups: [
|
||||
{ name: 'totalAmount', property: 'totalAmount', operation: 'sum' },
|
||||
{
|
||||
name: 'totalAmountWithTax',
|
||||
property: 'totalAmountWithTax',
|
||||
operation: 'sum',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const totals = rollupResults.orderTotals || {};
|
||||
const totalAmount = totals.totalAmount.sum?.toFixed(2) || 0;
|
||||
const totalAmountWithTax = totals.totalAmountWithTax.sum?.toFixed(2) || 0;
|
||||
|
||||
await editObject({
|
||||
model: purchaseOrderModel,
|
||||
id: orderId,
|
||||
updateData: {
|
||||
cost: { net: totalAmount, gross: totalAmountWithTax },
|
||||
},
|
||||
user,
|
||||
});
|
||||
};
|
||||
|
||||
// Add virtual id getter
|
||||
orderItemSchema.virtual('id').get(function () {
|
||||
return this._id;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import mongoose from 'mongoose';
|
||||
import { generateId } from '../../utils.js';
|
||||
const { Schema } = mongoose;
|
||||
import { aggregateRollups, aggregateRollupsHistory } from '../../database.js';
|
||||
|
||||
// Define the main partStock schema
|
||||
const partStockSchema = new Schema(
|
||||
@ -11,12 +12,42 @@ const partStockSchema = new Schema(
|
||||
progress: { type: Number, required: false },
|
||||
},
|
||||
part: { type: mongoose.Schema.Types.ObjectId, ref: 'part', required: true },
|
||||
startingQuantity: { type: Number, required: true },
|
||||
currentQuantity: { type: Number, required: true },
|
||||
sourceType: { type: String, required: true },
|
||||
source: { type: Schema.Types.ObjectId, refPath: 'sourceType', required: true },
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
const rollupConfigs = [
|
||||
{
|
||||
name: 'totalCurrentQuantity',
|
||||
filter: {},
|
||||
rollups: [{ name: 'totalCurrentQuantity', property: 'currentQuantity', operation: 'sum' }],
|
||||
},
|
||||
];
|
||||
|
||||
partStockSchema.statics.stats = async function () {
|
||||
const results = await aggregateRollups({
|
||||
model: this,
|
||||
rollupConfigs: rollupConfigs,
|
||||
});
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
partStockSchema.statics.history = async function (from, to) {
|
||||
const results = await aggregateRollupsHistory({
|
||||
model: this,
|
||||
startDate: from,
|
||||
endDate: to,
|
||||
rollupConfigs: rollupConfigs,
|
||||
});
|
||||
|
||||
// Return time-series data array
|
||||
return results;
|
||||
};
|
||||
|
||||
// Add virtual id getter
|
||||
partStockSchema.virtual('id').get(function () {
|
||||
return this._id;
|
||||
|
||||
@ -18,7 +18,8 @@ const documentJobSchema = new Schema(
|
||||
},
|
||||
state: {
|
||||
type: { type: String, required: true, default: 'queued' },
|
||||
percent: { type: Number, required: false },
|
||||
progress: { type: Number, required: false },
|
||||
message: { type: String, required: false },
|
||||
},
|
||||
documentTemplate: {
|
||||
type: Schema.Types.ObjectId,
|
||||
|
||||
@ -12,6 +12,8 @@ const filamentSchema = new mongoose.Schema({
|
||||
vendor: { type: Schema.Types.ObjectId, ref: 'vendor', required: true },
|
||||
type: { required: true, type: String },
|
||||
cost: { required: true, type: Number },
|
||||
costTaxRate: { type: Schema.Types.ObjectId, ref: 'taxRate', required: true },
|
||||
costWithTax: { required: true, type: Number },
|
||||
diameter: { required: true, type: Number },
|
||||
density: { required: true, type: Number },
|
||||
createdAt: { required: true, type: Date },
|
||||
|
||||
@ -41,22 +41,25 @@ const deviceInfoSchema = new mongoose.Schema(
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
const hostSchema = new mongoose.Schema({
|
||||
_reference: { type: String, default: () => generateId()() },
|
||||
name: { required: true, type: String },
|
||||
tags: [{ required: false, type: String }],
|
||||
online: { required: true, type: Boolean, default: false },
|
||||
state: {
|
||||
type: { type: String, required: true, default: 'offline' },
|
||||
message: { type: String, required: false },
|
||||
percent: { type: Number, required: false },
|
||||
const hostSchema = new mongoose.Schema(
|
||||
{
|
||||
_reference: { type: String, default: () => generateId()() },
|
||||
name: { required: true, type: String },
|
||||
tags: [{ required: false, type: String }],
|
||||
online: { required: true, type: Boolean, default: false },
|
||||
state: {
|
||||
type: { type: String, required: true, default: 'offline' },
|
||||
message: { type: String, required: false },
|
||||
percent: { type: Number, required: false },
|
||||
},
|
||||
active: { required: true, type: Boolean, default: true },
|
||||
connectedAt: { required: false, type: Date },
|
||||
authCode: { type: { required: false, type: String } },
|
||||
deviceInfo: { deviceInfoSchema },
|
||||
files: [{ type: mongoose.Schema.Types.ObjectId, ref: 'file' }],
|
||||
},
|
||||
active: { required: true, type: Boolean, default: true },
|
||||
connectedAt: { required: false, type: Date },
|
||||
authCode: { type: { required: false, type: String } },
|
||||
deviceInfo: { deviceInfoSchema },
|
||||
files: [{ type: mongoose.Schema.Types.ObjectId, ref: 'file' }],
|
||||
});
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
hostSchema.virtual('id').get(function () {
|
||||
return this._id;
|
||||
|
||||
@ -8,6 +8,7 @@ import { productModel } from './management/product.schema.js';
|
||||
import { vendorModel } from './management/vendor.schema.js';
|
||||
import { filamentStockModel } from './inventory/filamentstock.schema.js';
|
||||
import { purchaseOrderModel } from './inventory/purchaseorder.schema.js';
|
||||
import { orderItemModel } from './inventory/orderitem.schema.js';
|
||||
import { stockEventModel } from './inventory/stockevent.schema.js';
|
||||
import { stockAuditModel } from './inventory/stockaudit.schema.js';
|
||||
import { partStockModel } from './inventory/partstock.schema.js';
|
||||
@ -82,6 +83,12 @@ export const models = {
|
||||
type: 'purchaseOrder',
|
||||
referenceField: '_reference',
|
||||
},
|
||||
ODI: {
|
||||
model: orderItemModel,
|
||||
idField: '_id',
|
||||
type: 'orderItem',
|
||||
referenceField: '_reference',
|
||||
},
|
||||
COS: {
|
||||
model: courierServiceModel,
|
||||
idField: '_id',
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import mongoose from 'mongoose';
|
||||
import { generateId } from '../../utils.js';
|
||||
const { Schema } = mongoose;
|
||||
import { aggregateRollups, aggregateRollupsHistory } from '../../database.js';
|
||||
|
||||
const jobSchema = new mongoose.Schema(
|
||||
{
|
||||
@ -31,6 +32,56 @@ const jobSchema = new mongoose.Schema(
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
const rollupConfigs = [
|
||||
{
|
||||
name: 'queued',
|
||||
filter: { 'state.type': 'queued' },
|
||||
rollups: [{ name: 'queued', property: 'state.type', operation: 'count' }],
|
||||
},
|
||||
{
|
||||
name: 'printing',
|
||||
filter: { 'state.type': 'printing' },
|
||||
rollups: [{ name: 'printing', property: 'state.type', operation: 'count' }],
|
||||
},
|
||||
{
|
||||
name: 'draft',
|
||||
filter: { 'state.type': 'draft' },
|
||||
rollups: [{ name: 'draft', property: 'state.type', operation: 'count' }],
|
||||
},
|
||||
{
|
||||
name: 'complete',
|
||||
filter: { 'state.type': 'complete' },
|
||||
rollups: [{ name: 'complete', property: 'state.type', operation: 'count' }],
|
||||
},
|
||||
{
|
||||
name: 'failed',
|
||||
filter: { 'state.type': 'failed' },
|
||||
rollups: [{ name: 'failed', property: 'state.type', operation: 'count' }],
|
||||
},
|
||||
];
|
||||
|
||||
jobSchema.statics.stats = async function () {
|
||||
const results = await aggregateRollups({
|
||||
model: this,
|
||||
rollupConfigs: rollupConfigs,
|
||||
});
|
||||
|
||||
// Transform the results to match the expected format
|
||||
return results;
|
||||
};
|
||||
|
||||
jobSchema.statics.history = async function (from, to) {
|
||||
const results = await aggregateRollupsHistory({
|
||||
model: this,
|
||||
startDate: from,
|
||||
endDate: to,
|
||||
rollupConfigs: rollupConfigs,
|
||||
});
|
||||
|
||||
// Return time-series data array
|
||||
return results;
|
||||
};
|
||||
|
||||
jobSchema.virtual('id').get(function () {
|
||||
return this._id;
|
||||
});
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import mongoose from 'mongoose';
|
||||
import { generateId } from '../../utils.js';
|
||||
const { Schema } = mongoose;
|
||||
import { aggregateRollups, aggregateRollupsHistory } from '../../database.js';
|
||||
|
||||
// Define the moonraker connection schema
|
||||
const moonrakerSchema = new Schema(
|
||||
@ -56,6 +57,59 @@ const printerSchema = new Schema(
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
const rollupConfigs = [
|
||||
{
|
||||
name: 'standby',
|
||||
filter: { 'state.type': 'standby' },
|
||||
rollups: [{ name: 'standby', property: 'state.type', operation: 'count' }],
|
||||
},
|
||||
{
|
||||
name: 'complete',
|
||||
filter: { 'state.type': 'complete' },
|
||||
rollups: [{ name: 'complete', property: 'state.type', operation: 'count' }],
|
||||
},
|
||||
{
|
||||
name: 'printing',
|
||||
filter: { 'state.type': 'printing' },
|
||||
rollups: [{ name: 'printing', property: 'state.type', operation: 'count' }],
|
||||
},
|
||||
{
|
||||
name: 'error',
|
||||
filter: { 'state.type': 'error' },
|
||||
rollups: [{ name: 'error', property: 'state.type', operation: 'count' }],
|
||||
},
|
||||
{
|
||||
name: 'offline',
|
||||
filter: { 'state.type': 'offline' },
|
||||
rollups: [{ name: 'offline', property: 'state.type', operation: 'count' }],
|
||||
},
|
||||
];
|
||||
|
||||
printerSchema.statics.stats = async function () {
|
||||
const results = await aggregateRollups({
|
||||
model: this,
|
||||
baseFilter: { active: true },
|
||||
rollupConfigs: rollupConfigs,
|
||||
});
|
||||
|
||||
console.log(results);
|
||||
|
||||
// Transform the results to match the expected format
|
||||
return results;
|
||||
};
|
||||
|
||||
printerSchema.statics.history = async function (from, to) {
|
||||
const results = await aggregateRollupsHistory({
|
||||
model: this,
|
||||
startDate: from,
|
||||
endDate: to,
|
||||
rollupConfigs: rollupConfigs,
|
||||
});
|
||||
|
||||
// Return time-series data array
|
||||
return results;
|
||||
};
|
||||
|
||||
// Add virtual id getter
|
||||
printerSchema.virtual('id').get(function () {
|
||||
return this._id;
|
||||
|
||||
@ -436,6 +436,10 @@ async function distributeUpdate(value, id, type) {
|
||||
await natsServer.publish(`${type}s.${id}.object`, value);
|
||||
}
|
||||
|
||||
async function distributeStats(value, type) {
|
||||
await natsServer.publish(`${type}s.stats`, value);
|
||||
}
|
||||
|
||||
async function distributeNew(id, type) {
|
||||
await natsServer.publish(`${type}s.new`, id);
|
||||
}
|
||||
@ -541,6 +545,7 @@ export {
|
||||
expandObjectIds,
|
||||
distributeUpdate,
|
||||
distributeNew,
|
||||
distributeStats,
|
||||
getFilter, // <-- add here
|
||||
convertPropertiesString
|
||||
};
|
||||
|
||||
28
src/index.js
28
src/index.js
@ -1,7 +1,7 @@
|
||||
import { loadConfig } from './config.js';
|
||||
import { SocketManager } from './socket/socketmanager.js';
|
||||
import { etcdServer } from './database/etcd.js';
|
||||
import { natsServer } from './database/nats.js';
|
||||
import { redisServer } from './database/redis.js';
|
||||
import express from 'express';
|
||||
import log4js from 'log4js';
|
||||
import http from 'http';
|
||||
@ -21,19 +21,9 @@ import { mongoServer } from './database/mongo.js';
|
||||
|
||||
new SocketManager(server);
|
||||
|
||||
// Connect to Etcd (await)
|
||||
try {
|
||||
//await etcdServer.connect();
|
||||
// logger.info('Connected to Etcd');
|
||||
} catch (err) {
|
||||
logger.error('Failed to connect to Etcd:', err);
|
||||
throw err;
|
||||
}
|
||||
|
||||
// Connect to NATS (await)
|
||||
try {
|
||||
await natsServer.connect();
|
||||
logger.info('Connected to NATS');
|
||||
} catch (err) {
|
||||
logger.error('Failed to connect to NATS:', err);
|
||||
throw err;
|
||||
@ -42,12 +32,19 @@ import { mongoServer } from './database/mongo.js';
|
||||
// Connect to Mongo DB (await)
|
||||
try {
|
||||
await mongoServer.connect();
|
||||
logger.info('Connected to Mongo DB');
|
||||
} catch (err) {
|
||||
logger.error('Failed to connect to Mongo DB:', err);
|
||||
throw err;
|
||||
}
|
||||
|
||||
// Connect to Redis (await)
|
||||
try {
|
||||
await redisServer.connect();
|
||||
} catch (err) {
|
||||
logger.error('Failed to connect to Redis:', err);
|
||||
throw err;
|
||||
}
|
||||
|
||||
// Start HTTP server
|
||||
server.listen(config.server.port, () => {
|
||||
logger.info(`Server listening on port ${config.server.port}`);
|
||||
@ -55,6 +52,11 @@ import { mongoServer } from './database/mongo.js';
|
||||
|
||||
process.on('SIGINT', async () => {
|
||||
logger.info('Shutting down...');
|
||||
await etcdServer.disconnect();
|
||||
await redisServer.disconnect();
|
||||
await mongoServer.disconnect();
|
||||
await natsServer.disconnect();
|
||||
await server.close();
|
||||
logger.info('Shutdown complete');
|
||||
process.exit(0);
|
||||
});
|
||||
})();
|
||||
|
||||
@ -9,7 +9,7 @@ const logger = log4js.getLogger('Lock Manager');
|
||||
logger.level = config.server.logLevel;
|
||||
|
||||
/**
|
||||
* LockManager handles distributed locking using Etcd and broadcasts lock events via websockets.
|
||||
* LockManager handles distributed locking and broadcasts lock events via websockets.
|
||||
*/
|
||||
export class LockManager {
|
||||
constructor(socketClient) {
|
||||
|
||||
@ -7,6 +7,7 @@ import { LockManager } from '../lock/lockmanager.js';
|
||||
import { UpdateManager } from '../updates/updatemanager.js';
|
||||
import { ActionManager } from '../actions/actionmanager.js';
|
||||
import { EventManager } from '../events/eventmanager.js';
|
||||
import { StatsManager } from '../stats/statsmanager.js';
|
||||
|
||||
const config = loadConfig();
|
||||
|
||||
@ -25,6 +26,7 @@ export class SocketUser {
|
||||
this.updateManager = new UpdateManager(this);
|
||||
this.actionManager = new ActionManager(this);
|
||||
this.eventManager = new EventManager(this);
|
||||
this.statsManager = new StatsManager(this);
|
||||
this.templateManager = socketManager.templateManager;
|
||||
this.keycloakAuth = new KeycloakAuth();
|
||||
this.setupSocketEventHandlers();
|
||||
@ -60,6 +62,14 @@ export class SocketUser {
|
||||
'unsubscribeObjectEvent',
|
||||
this.handleUnsubscribeObjectEventEvent.bind(this)
|
||||
);
|
||||
this.socket.on(
|
||||
'subscribeToModelStats',
|
||||
this.handleSubscribeToStatsEvent.bind(this)
|
||||
);
|
||||
this.socket.on(
|
||||
'unsubscribeModelStats',
|
||||
this.handleUnsubscribeToStatsEvent.bind(this)
|
||||
);
|
||||
this.socket.on(
|
||||
'previewTemplate',
|
||||
this.handlePreviewTemplateEvent.bind(this)
|
||||
@ -191,6 +201,14 @@ export class SocketUser {
|
||||
);
|
||||
}
|
||||
|
||||
async handleSubscribeToStatsEvent(data) {
|
||||
await this.statsManager.subscribeToStats(data.objectType);
|
||||
}
|
||||
|
||||
async handleUnsubscribeToStatsEvent(data) {
|
||||
await this.statsManager.removeStatsListener(data.objectType);
|
||||
}
|
||||
|
||||
async handlePreviewTemplateEvent(data, callback) {
|
||||
const result = await this.templateManager.renderTemplate(
|
||||
data._id,
|
||||
@ -227,6 +245,7 @@ export class SocketUser {
|
||||
async handleDisconnect() {
|
||||
await this.actionManager.removeAllListeners();
|
||||
await this.eventManager.removeAllListeners();
|
||||
await this.statsManager.removeAllListeners();
|
||||
logger.info('External user disconnected:', this.socket.user?.username);
|
||||
}
|
||||
}
|
||||
|
||||
82
src/stats/statsmanager.js
Normal file
82
src/stats/statsmanager.js
Normal file
@ -0,0 +1,82 @@
|
||||
import log4js from 'log4js';
|
||||
import { loadConfig } from '../config.js';
|
||||
import { natsServer } from '../database/nats.js';
|
||||
|
||||
const config = loadConfig();
|
||||
|
||||
// Setup logger
|
||||
const logger = log4js.getLogger('Stats Manager');
|
||||
logger.level = config.server.logLevel;
|
||||
|
||||
/**
|
||||
* StatsManager handles tracking stats updates using NATS and broadcasts stats updates via websockets.
|
||||
*/
|
||||
export class StatsManager {
|
||||
constructor(socketClient) {
|
||||
this.socketClient = socketClient;
|
||||
this.subscriptions = new Set();
|
||||
}
|
||||
|
||||
async subscribeToStats(type) {
|
||||
logger.debug('Subscribing to stats:', type);
|
||||
const subject = `${type}s.stats`;
|
||||
const subscriptionKey = `${subject}:${this.socketClient.socketId}`;
|
||||
|
||||
await natsServer.subscribe(
|
||||
subject,
|
||||
this.socketClient.socketId,
|
||||
(key, value) => {
|
||||
if (!value?.result) {
|
||||
logger.trace('Stats update detected:', type);
|
||||
console.log('Stats update detected:', type, value);
|
||||
this.socketClient.socket.emit('modelStats', {
|
||||
objectType: type,
|
||||
stats: { ...value }
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
this.subscriptions.add(subscriptionKey);
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
async removeStatsListener(type) {
|
||||
// Remove stats subscription for this type
|
||||
const subject = `${type}s.stats`;
|
||||
const subscriptionKey = `${subject}:${this.socketClient.socketId}`;
|
||||
|
||||
await natsServer.removeSubscription(subject, this.socketClient.socketId);
|
||||
|
||||
this.subscriptions.delete(subscriptionKey);
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
async sendStats(type, stats) {
|
||||
try {
|
||||
logger.trace(`Publishing stats: type=${type}, stats:`, stats);
|
||||
await natsServer.publish(`${type}s.stats`, stats);
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
logger.error(`Failed to publish stats for ${type}s.stats:`, error);
|
||||
return {
|
||||
error: error?.message || `Failed to publish stats for ${type}s.stats.`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async removeAllListeners() {
|
||||
logger.debug('Removing all stats listeners...');
|
||||
const removePromises = Array.from(this.subscriptions).map(
|
||||
subscriptionKey => {
|
||||
const [subject, socketId] = subscriptionKey.split(':');
|
||||
return natsServer.removeSubscription(subject, socketId);
|
||||
}
|
||||
);
|
||||
|
||||
await Promise.all(removePromises);
|
||||
this.subscriptions.clear();
|
||||
logger.debug(`Removed ${removePromises.length} stats listener(s)`);
|
||||
return { success: true };
|
||||
}
|
||||
}
|
||||
@ -18,18 +18,18 @@
|
||||
}
|
||||
|
||||
.previewWrapper {
|
||||
width: <%= (width * scale) + 'mm' || '50mm' %>;
|
||||
height: <%= (height * scale) + 'mm' || '50mm' %>;
|
||||
width: <%= (scaledWidth) || '50mm' %>;
|
||||
height: <%= (scaledHeight) || '50mm' %>;
|
||||
}
|
||||
.previewDocument {
|
||||
width: <%= (width) + 'mm' || '50mm' %>;
|
||||
height: <%= (height) + 'mm' || '50mm' %>;
|
||||
width: <%= (width) || '50mm' %>;
|
||||
height: <%= (height) || '50mm' %>;
|
||||
transform: scale(<%= scale || '1' %>);
|
||||
transform-origin: top left;
|
||||
}
|
||||
.renderDocument {
|
||||
width: <%= (width * scale) + 'mm' || '50mm' %>;
|
||||
height: <%= (height * scale) + 'mm' || '50mm' %>;
|
||||
width: <%= (scaledWidth) || '50mm' %>;
|
||||
height: <%= (scaledHeight) || '50mm' %>;
|
||||
transform: scale(<%= scale || '1' %>);
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1 +1 @@
|
||||
<div class="renderDocument"><%- content %></div>
|
||||
<div class="renderDocument" id="content"><%- content %></div>
|
||||
|
||||
@ -30,13 +30,22 @@ export async function generatePDF(html, options = {}) {
|
||||
waitUntil: 'networkidle0'
|
||||
});
|
||||
|
||||
var height = `${options?.height || '50'}mm`;
|
||||
|
||||
if (options.height == 'auto') {
|
||||
console.log('Calculating height');
|
||||
const calculatedHeight = await page.evaluate(() => {
|
||||
return document.getElementById('content').scrollHeight;
|
||||
});
|
||||
|
||||
height = `${calculatedHeight}px`;
|
||||
}
|
||||
// Generate PDF with specified dimensions
|
||||
const pdfBuffer = await page.pdf({
|
||||
format: options.format || undefined,
|
||||
width: options.width ? `${options.width}mm` : undefined,
|
||||
height: options.height ? `${options.height}mm` : undefined,
|
||||
printBackground: true,
|
||||
preferCSSPageSize: true,
|
||||
width: options.width ? `${options.width}mm` : undefined,
|
||||
height: height ? `${height}` : undefined,
|
||||
margin: {
|
||||
top: '0mm',
|
||||
right: '0mm',
|
||||
|
||||
@ -430,8 +430,14 @@ export class TemplateManager {
|
||||
documentTemplate.parent.content == null ||
|
||||
typeof documentTemplate.parent.content !== 'string'
|
||||
) {
|
||||
console.log(
|
||||
'Parent template content is required and must be a string.',
|
||||
documentTemplate.parent.content
|
||||
);
|
||||
return {
|
||||
error: 'Parent template content is required and must be a string.'
|
||||
error:
|
||||
'Parent template content is required and must be a string.' +
|
||||
documentTemplate.parent.content
|
||||
};
|
||||
}
|
||||
templateWithParentContent = await ejs.render(
|
||||
@ -481,12 +487,18 @@ export class TemplateManager {
|
||||
return { error: 'Failed to render inner template content.' };
|
||||
}
|
||||
|
||||
const infiniteHeight = documentSize.infiniteHeight == true;
|
||||
|
||||
const baseHtml = await ejs.render(
|
||||
baseTemplate,
|
||||
{
|
||||
content: innerHtml,
|
||||
width: documentSize.width,
|
||||
height: documentSize.height,
|
||||
width: `${documentSize.width}mm`,
|
||||
height: infiniteHeight ? 'fit-content' : `${documentSize.height}mm`,
|
||||
scaledWidth: `${documentSize.width * scale}mm`,
|
||||
scaledHeight: infiniteHeight
|
||||
? 'auto'
|
||||
: `${documentSize.height * scale}mm`,
|
||||
scale: `${scale}`,
|
||||
baseCSS: baseCSS,
|
||||
previewPaginationScript: preview ? previewPaginationScript : ''
|
||||
@ -497,7 +509,8 @@ export class TemplateManager {
|
||||
const previewObject = {
|
||||
html: baseHtml,
|
||||
width: documentSize.width,
|
||||
height: documentSize.height
|
||||
height: infiniteHeight ? 'auto' : documentSize.height,
|
||||
infiniteHeight: infiniteHeight
|
||||
};
|
||||
|
||||
return previewObject;
|
||||
@ -552,7 +565,8 @@ export class TemplateManager {
|
||||
// Generate PDF using PDF factory
|
||||
const pdfBuffer = await generatePDF(baseHtml, {
|
||||
width: renderedTemplate.width,
|
||||
height: renderedTemplate.height
|
||||
height: renderedTemplate.height,
|
||||
infiniteHeight: renderedTemplate.infiniteHeight
|
||||
});
|
||||
|
||||
const pdfObject = {
|
||||
|
||||
@ -8,7 +8,7 @@ const logger = log4js.getLogger('Update Manager');
|
||||
logger.level = config.server.logLevel;
|
||||
|
||||
/**
|
||||
* UpdateManager handles tracking object updates using Etcd and broadcasts update events via websockets.
|
||||
* UpdateManager handles tracking object updates and broadcasts update events via websockets.
|
||||
*/
|
||||
export class UpdateManager {
|
||||
constructor(socketClient) {
|
||||
|
||||
14
src/utils.js
14
src/utils.js
@ -76,8 +76,14 @@ export function getModelByName(modelName) {
|
||||
return modelList.filter(model => model.modelName == modelName)[0];
|
||||
}
|
||||
|
||||
export function jsonToCacheKey(obj) {
|
||||
const normalized = canonicalize(obj);
|
||||
const hash = crypto.createHash('sha256').update(normalized).digest('hex');
|
||||
return hash;
|
||||
export function getQueryToCacheKey({ model, id, populate }) {
|
||||
const populateKey = [];
|
||||
for (const pop of populate) {
|
||||
if (typeof pop === 'string') {
|
||||
populateKey.push(pop);
|
||||
} else if (typeof pop === 'object') {
|
||||
populateKey.push(pop.path);
|
||||
}
|
||||
}
|
||||
return `${model}:${id?.toString()}-${populateKey.join(',')}`;
|
||||
}
|
||||
|
||||
406
yarn.lock
406
yarn.lock
@ -104,34 +104,6 @@
|
||||
"@eslint/core" "^0.17.0"
|
||||
levn "^0.4.1"
|
||||
|
||||
"@grpc/grpc-js@^1.8.20":
|
||||
version "1.14.1"
|
||||
resolved "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.1.tgz"
|
||||
integrity sha512-sPxgEWtPUR3EnRJCEtbGZG2iX8LQDUls2wUS3o27jg07KqJFMq6YDeWvMo1wfpmy3rqRdS0rivpLwhqQtEyCuQ==
|
||||
dependencies:
|
||||
"@grpc/proto-loader" "^0.8.0"
|
||||
"@js-sdsl/ordered-map" "^4.4.2"
|
||||
|
||||
"@grpc/proto-loader@^0.7.8":
|
||||
version "0.7.15"
|
||||
resolved "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.15.tgz"
|
||||
integrity sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==
|
||||
dependencies:
|
||||
lodash.camelcase "^4.3.0"
|
||||
long "^5.0.0"
|
||||
protobufjs "^7.2.5"
|
||||
yargs "^17.7.2"
|
||||
|
||||
"@grpc/proto-loader@^0.8.0":
|
||||
version "0.8.0"
|
||||
resolved "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.8.0.tgz"
|
||||
integrity sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ==
|
||||
dependencies:
|
||||
lodash.camelcase "^4.3.0"
|
||||
long "^5.0.0"
|
||||
protobufjs "^7.5.3"
|
||||
yargs "^17.7.2"
|
||||
|
||||
"@humanfs/core@^0.19.1":
|
||||
version "0.19.1"
|
||||
resolved "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz"
|
||||
@ -169,11 +141,6 @@
|
||||
resolved "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz"
|
||||
integrity sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==
|
||||
|
||||
"@js-sdsl/ordered-map@^4.4.2":
|
||||
version "4.4.2"
|
||||
resolved "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz"
|
||||
integrity sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==
|
||||
|
||||
"@mongodb-js/saslprep@^1.3.0":
|
||||
version "1.3.2"
|
||||
resolved "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.3.2.tgz"
|
||||
@ -181,7 +148,7 @@
|
||||
dependencies:
|
||||
sparse-bitfield "^3.0.3"
|
||||
|
||||
"@nats-io/nats-core@^3.2.0", "@nats-io/nats-core@3.2.0":
|
||||
"@nats-io/nats-core@3.2.0", "@nats-io/nats-core@^3.2.0":
|
||||
version "3.2.0"
|
||||
resolved "https://registry.npmjs.org/@nats-io/nats-core/-/nats-core-3.2.0.tgz"
|
||||
integrity sha512-yHMsS0RTkKRh80COCGY/kuhEj0KPU47qkVU6IPEXmqjmskH6mX2roykxY5CXCAQc78FKYrpKQp6EHv02dRAjDw==
|
||||
@ -236,59 +203,6 @@
|
||||
resolved "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz"
|
||||
integrity sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==
|
||||
|
||||
"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz"
|
||||
integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==
|
||||
|
||||
"@protobufjs/base64@^1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz"
|
||||
integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==
|
||||
|
||||
"@protobufjs/codegen@^2.0.4":
|
||||
version "2.0.4"
|
||||
resolved "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz"
|
||||
integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==
|
||||
|
||||
"@protobufjs/eventemitter@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz"
|
||||
integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==
|
||||
|
||||
"@protobufjs/fetch@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz"
|
||||
integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==
|
||||
dependencies:
|
||||
"@protobufjs/aspromise" "^1.1.1"
|
||||
"@protobufjs/inquire" "^1.1.0"
|
||||
|
||||
"@protobufjs/float@^1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz"
|
||||
integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==
|
||||
|
||||
"@protobufjs/inquire@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz"
|
||||
integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==
|
||||
|
||||
"@protobufjs/path@^1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz"
|
||||
integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==
|
||||
|
||||
"@protobufjs/pool@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz"
|
||||
integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==
|
||||
|
||||
"@protobufjs/utf8@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz"
|
||||
integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
|
||||
|
||||
"@puppeteer/browsers@2.10.13":
|
||||
version "2.10.13"
|
||||
resolved "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.10.13.tgz"
|
||||
@ -302,39 +216,32 @@
|
||||
tar-fs "^3.1.1"
|
||||
yargs "^17.7.2"
|
||||
|
||||
"@redis/bloom@1.2.0":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz"
|
||||
integrity sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==
|
||||
"@redis/bloom@5.10.0":
|
||||
version "5.10.0"
|
||||
resolved "https://registry.yarnpkg.com/@redis/bloom/-/bloom-5.10.0.tgz#1079373583b82a8b61b0d3721755245686b4a602"
|
||||
integrity sha512-doIF37ob+l47n0rkpRNgU8n4iacBlKM9xLiP1LtTZTvz8TloJB8qx/MgvhMhKdYG+CvCY2aPBnN2706izFn/4A==
|
||||
|
||||
"@redis/client@^1.0.0", "@redis/client@1.6.1":
|
||||
version "1.6.1"
|
||||
resolved "https://registry.npmjs.org/@redis/client/-/client-1.6.1.tgz"
|
||||
integrity sha512-/KCsg3xSlR+nCK8/8ZYSknYxvXHwubJrU82F3Lm1Fp6789VQ0/3RJKfsmRXjqfaTA++23CvC3hqmqe/2GEt6Kw==
|
||||
"@redis/client@5.10.0":
|
||||
version "5.10.0"
|
||||
resolved "https://registry.yarnpkg.com/@redis/client/-/client-5.10.0.tgz#621d5de1898a4f2c3a813769779ca5902ef9d57a"
|
||||
integrity sha512-JXmM4XCoso6C75Mr3lhKA3eNxSzkYi3nCzxDIKY+YOszYsJjuKbFgVtguVPbLMOttN4iu2fXoc2BGhdnYhIOxA==
|
||||
dependencies:
|
||||
cluster-key-slot "1.1.2"
|
||||
generic-pool "3.9.0"
|
||||
yallist "4.0.0"
|
||||
|
||||
"@redis/graph@1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.npmjs.org/@redis/graph/-/graph-1.1.1.tgz"
|
||||
integrity sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==
|
||||
"@redis/json@5.10.0":
|
||||
version "5.10.0"
|
||||
resolved "https://registry.yarnpkg.com/@redis/json/-/json-5.10.0.tgz#a550a7859c3cbae45535aad157fcaa8e6bd3e7d3"
|
||||
integrity sha512-B2G8XlOmTPUuZtD44EMGbtoepQG34RCDXLZbjrtON1Djet0t5Ri7/YPXvL9aomXqP8lLTreaprtyLKF4tmXEEA==
|
||||
|
||||
"@redis/json@1.0.7":
|
||||
version "1.0.7"
|
||||
resolved "https://registry.npmjs.org/@redis/json/-/json-1.0.7.tgz"
|
||||
integrity sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ==
|
||||
"@redis/search@5.10.0":
|
||||
version "5.10.0"
|
||||
resolved "https://registry.yarnpkg.com/@redis/search/-/search-5.10.0.tgz#587851479c6abb9b40b31ab9b31c234db7a04919"
|
||||
integrity sha512-3SVcPswoSfp2HnmWbAGUzlbUPn7fOohVu2weUQ0S+EMiQi8jwjL+aN2p6V3TI65eNfVsJ8vyPvqWklm6H6esmg==
|
||||
|
||||
"@redis/search@1.2.0":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.npmjs.org/@redis/search/-/search-1.2.0.tgz"
|
||||
integrity sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==
|
||||
|
||||
"@redis/time-series@1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/@redis/time-series/-/time-series-1.1.0.tgz"
|
||||
integrity sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==
|
||||
"@redis/time-series@5.10.0":
|
||||
version "5.10.0"
|
||||
resolved "https://registry.yarnpkg.com/@redis/time-series/-/time-series-5.10.0.tgz#9c7de35fe023e36233fba5c8478ce25832ead64c"
|
||||
integrity sha512-cPkpddXH5kc/SdRhF0YG0qtjL+noqFT0AcHbQ6axhsPsO7iqPi1cjxgdkE9TNeKiBUUdCaU1DbqkR/LzbzPBhg==
|
||||
|
||||
"@rtsao/scc@^1.1.0":
|
||||
version "1.1.0"
|
||||
@ -373,7 +280,7 @@
|
||||
resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz"
|
||||
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
|
||||
|
||||
"@types/node@*", "@types/node@>=10.0.0", "@types/node@>=13.7.0":
|
||||
"@types/node@*", "@types/node@>=10.0.0":
|
||||
version "24.10.1"
|
||||
resolved "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz"
|
||||
integrity sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==
|
||||
@ -425,7 +332,7 @@ acorn-jsx@^5.3.2:
|
||||
resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
|
||||
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
|
||||
|
||||
"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.15.0, acorn@^8.9.0:
|
||||
acorn@^8.15.0, acorn@^8.9.0:
|
||||
version "8.15.0"
|
||||
resolved "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz"
|
||||
integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==
|
||||
@ -609,7 +516,7 @@ balanced-match@^1.0.0:
|
||||
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
|
||||
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
||||
|
||||
bare-events@*, bare-events@^2.5.4, bare-events@^2.7.0:
|
||||
bare-events@^2.5.4, bare-events@^2.7.0:
|
||||
version "2.8.2"
|
||||
resolved "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz"
|
||||
integrity sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==
|
||||
@ -656,7 +563,7 @@ base64-js@0.0.2:
|
||||
resolved "https://registry.npmjs.org/base64-js/-/base64-js-0.0.2.tgz"
|
||||
integrity sha512-Pj9L87dCdGcKlSqPVUjD+q96pbIx1zQQLb2CUiWURfjiBELv84YX+0nGnKmyT/9KkC7PQk7UN1w+Al8bBozaxQ==
|
||||
|
||||
base64id@~2.0.0, base64id@2.0.0:
|
||||
base64id@2.0.0, base64id@~2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz"
|
||||
integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==
|
||||
@ -666,11 +573,6 @@ basic-ftp@^5.0.2:
|
||||
resolved "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz"
|
||||
integrity sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==
|
||||
|
||||
bignumber.js@^9.1.1:
|
||||
version "9.3.1"
|
||||
resolved "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz"
|
||||
integrity sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==
|
||||
|
||||
binary-extensions@^2.0.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz"
|
||||
@ -753,7 +655,7 @@ builtins@^5.0.1:
|
||||
dependencies:
|
||||
semver "^7.0.0"
|
||||
|
||||
bytes@^3.1.2, bytes@3.1.2:
|
||||
bytes@3.1.2, bytes@^3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz"
|
||||
integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
|
||||
@ -844,11 +746,6 @@ cluster-key-slot@1.1.2:
|
||||
resolved "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz"
|
||||
integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==
|
||||
|
||||
cockatiel@^3.1.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.npmjs.org/cockatiel/-/cockatiel-3.2.1.tgz"
|
||||
integrity sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q==
|
||||
|
||||
color-convert@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz"
|
||||
@ -974,6 +871,20 @@ dayjs@^1.11.19:
|
||||
resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz"
|
||||
integrity sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==
|
||||
|
||||
debug@2.6.9:
|
||||
version "2.6.9"
|
||||
resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
|
||||
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@4, debug@4.x, debug@^4, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5, debug@^4.4.0, debug@^4.4.3:
|
||||
version "4.4.3"
|
||||
resolved "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz"
|
||||
integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==
|
||||
dependencies:
|
||||
ms "^2.1.3"
|
||||
|
||||
debug@^3.2.7:
|
||||
version "3.2.7"
|
||||
resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz"
|
||||
@ -981,34 +892,13 @@ debug@^3.2.7:
|
||||
dependencies:
|
||||
ms "^2.1.1"
|
||||
|
||||
debug@^4, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5, debug@^4.4.0, debug@^4.4.3, debug@4, debug@4.x:
|
||||
version "4.4.3"
|
||||
resolved "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz"
|
||||
integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==
|
||||
dependencies:
|
||||
ms "^2.1.3"
|
||||
|
||||
debug@~4.3.1:
|
||||
debug@~4.3.1, debug@~4.3.2, debug@~4.3.4:
|
||||
version "4.3.7"
|
||||
resolved "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz"
|
||||
integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==
|
||||
dependencies:
|
||||
ms "^2.1.3"
|
||||
|
||||
debug@~4.3.2, debug@~4.3.4:
|
||||
version "4.3.7"
|
||||
resolved "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz"
|
||||
integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==
|
||||
dependencies:
|
||||
ms "^2.1.3"
|
||||
|
||||
debug@2.6.9:
|
||||
version "2.6.9"
|
||||
resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
|
||||
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
deep-is@^0.1.3:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz"
|
||||
@ -1046,12 +936,12 @@ delayed-stream@~1.0.0:
|
||||
resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
|
||||
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
|
||||
|
||||
depd@^2.0.0, depd@2.0.0:
|
||||
depd@2.0.0, depd@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz"
|
||||
integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
|
||||
|
||||
devtools-protocol@*, devtools-protocol@0.0.1521046:
|
||||
devtools-protocol@0.0.1521046:
|
||||
version "0.0.1521046"
|
||||
resolved "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1521046.tgz"
|
||||
integrity sha512-vhE6eymDQSKWUXwwA37NtTTVEzjtGVfDr3pRbsWEQ5onH/Snp2c+2xZHWJJawG/0hCCJLRGt4xVtEVUVILol4w==
|
||||
@ -1348,7 +1238,7 @@ escodegen@^2.1.0:
|
||||
optionalDependencies:
|
||||
source-map "~0.6.1"
|
||||
|
||||
eslint-config-prettier@^10.1.8, "eslint-config-prettier@>= 7.0.0 <10.0.0 || >=10.1.0":
|
||||
eslint-config-prettier@^10.1.8:
|
||||
version "10.1.8"
|
||||
resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz"
|
||||
integrity sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==
|
||||
@ -1387,7 +1277,7 @@ eslint-plugin-es@^4.1.0:
|
||||
eslint-utils "^2.0.0"
|
||||
regexpp "^3.0.0"
|
||||
|
||||
eslint-plugin-import@^2.25.2, eslint-plugin-import@^2.27.5:
|
||||
eslint-plugin-import@^2.27.5:
|
||||
version "2.32.0"
|
||||
resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz"
|
||||
integrity sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==
|
||||
@ -1412,7 +1302,7 @@ eslint-plugin-import@^2.25.2, eslint-plugin-import@^2.27.5:
|
||||
string.prototype.trimend "^1.0.9"
|
||||
tsconfig-paths "^3.15.0"
|
||||
|
||||
"eslint-plugin-n@^15.0.0 || ^16.0.0 ", eslint-plugin-n@^15.7.0:
|
||||
eslint-plugin-n@^15.7.0:
|
||||
version "15.7.0"
|
||||
resolved "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.7.0.tgz"
|
||||
integrity sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q==
|
||||
@ -1434,12 +1324,12 @@ eslint-plugin-prettier@^5.5.4:
|
||||
prettier-linter-helpers "^1.0.0"
|
||||
synckit "^0.11.7"
|
||||
|
||||
eslint-plugin-promise@^6.0.0, eslint-plugin-promise@^6.1.1:
|
||||
eslint-plugin-promise@^6.1.1:
|
||||
version "6.6.0"
|
||||
resolved "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.6.0.tgz"
|
||||
integrity sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ==
|
||||
|
||||
eslint-plugin-react@^7.28.0, eslint-plugin-react@^7.36.1:
|
||||
eslint-plugin-react@^7.36.1:
|
||||
version "7.37.5"
|
||||
resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz"
|
||||
integrity sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==
|
||||
@ -1513,7 +1403,7 @@ eslint-visitor-keys@^4.2.1:
|
||||
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz"
|
||||
integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==
|
||||
|
||||
"eslint@^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9", "eslint@^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7", "eslint@^7.0.0 || ^8.0.0 || ^9.0.0", eslint@^8.0.1, eslint@^8.41.0, eslint@^8.8.0, eslint@>=4.19.1, eslint@>=5:
|
||||
eslint@^8.41.0:
|
||||
version "8.57.1"
|
||||
resolved "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz"
|
||||
integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==
|
||||
@ -1557,7 +1447,7 @@ eslint-visitor-keys@^4.2.1:
|
||||
strip-ansi "^6.0.1"
|
||||
text-table "^0.2.0"
|
||||
|
||||
"eslint@^6.0.0 || ^7.0.0 || >=8.0.0", eslint@^9.39.1, eslint@>=7.0.0, eslint@>=8.0.0:
|
||||
eslint@^9.39.1:
|
||||
version "9.39.1"
|
||||
resolved "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz"
|
||||
integrity sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==
|
||||
@ -1649,16 +1539,6 @@ etag@^1.8.1:
|
||||
resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz"
|
||||
integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==
|
||||
|
||||
etcd3@^1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npmjs.org/etcd3/-/etcd3-1.1.2.tgz"
|
||||
integrity sha512-YIampCz1/OmrVo/tR3QltAVUtYCQQOSFoqmHKKeoHbalm+WdXe3l4rhLIylklu8EzR/I3PBiOF4dC847dDskKg==
|
||||
dependencies:
|
||||
"@grpc/grpc-js" "^1.8.20"
|
||||
"@grpc/proto-loader" "^0.7.8"
|
||||
bignumber.js "^9.1.1"
|
||||
cockatiel "^3.1.1"
|
||||
|
||||
events-universal@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz"
|
||||
@ -1905,11 +1785,6 @@ generator-function@^2.0.0:
|
||||
resolved "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz"
|
||||
integrity sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==
|
||||
|
||||
generic-pool@3.9.0:
|
||||
version "3.9.0"
|
||||
resolved "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz"
|
||||
integrity sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==
|
||||
|
||||
get-caller-file@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz"
|
||||
@ -2093,7 +1968,7 @@ htmlparser2@^7.1.1:
|
||||
domutils "^2.8.0"
|
||||
entities "^3.0.1"
|
||||
|
||||
http-errors@^2.0.0, http-errors@2.0.0:
|
||||
http-errors@2.0.0, http-errors@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz"
|
||||
integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
|
||||
@ -2120,13 +1995,6 @@ https-proxy-agent@^7.0.6:
|
||||
agent-base "^7.1.2"
|
||||
debug "4"
|
||||
|
||||
iconv-lite@^0.6.3:
|
||||
version "0.6.3"
|
||||
resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz"
|
||||
integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3.0.0"
|
||||
|
||||
iconv-lite@0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz"
|
||||
@ -2134,6 +2002,13 @@ iconv-lite@0.7.0:
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3.0.0"
|
||||
|
||||
iconv-lite@^0.6.3:
|
||||
version "0.6.3"
|
||||
resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz"
|
||||
integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3.0.0"
|
||||
|
||||
ignore-by-default@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz"
|
||||
@ -2165,7 +2040,7 @@ inflight@^1.0.4:
|
||||
once "^1.3.0"
|
||||
wrappy "1"
|
||||
|
||||
inherits@~2.0.1, inherits@2, inherits@2.0.4:
|
||||
inherits@2, inherits@2.0.4, inherits@~2.0.1:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
@ -2601,11 +2476,6 @@ locate-path@^6.0.0:
|
||||
dependencies:
|
||||
p-locate "^5.0.0"
|
||||
|
||||
lodash.camelcase@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz"
|
||||
integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==
|
||||
|
||||
lodash.includes@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz"
|
||||
@ -2662,11 +2532,6 @@ log4js@^6.9.1:
|
||||
rfdc "^1.3.0"
|
||||
streamroller "^3.1.5"
|
||||
|
||||
long@^5.0.0:
|
||||
version "5.3.2"
|
||||
resolved "https://registry.npmjs.org/long/-/long-5.3.2.tgz"
|
||||
integrity sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==
|
||||
|
||||
loose-envify@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz"
|
||||
@ -2699,17 +2564,17 @@ merge-descriptors@^2.0.0:
|
||||
resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz"
|
||||
integrity sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==
|
||||
|
||||
mime-db@^1.54.0:
|
||||
version "1.54.0"
|
||||
resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz"
|
||||
integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==
|
||||
|
||||
mime-db@1.52.0:
|
||||
version "1.52.0"
|
||||
resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz"
|
||||
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
|
||||
|
||||
mime-types@^2.1.12:
|
||||
mime-db@^1.54.0:
|
||||
version "1.54.0"
|
||||
resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz"
|
||||
integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==
|
||||
|
||||
mime-types@^2.1.12, mime-types@~2.1.34:
|
||||
version "2.1.35"
|
||||
resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz"
|
||||
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
|
||||
@ -2723,13 +2588,6 @@ mime-types@^3.0.0, mime-types@^3.0.1:
|
||||
dependencies:
|
||||
mime-db "^1.54.0"
|
||||
|
||||
mime-types@~2.1.34:
|
||||
version "2.1.35"
|
||||
resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz"
|
||||
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
|
||||
dependencies:
|
||||
mime-db "1.52.0"
|
||||
|
||||
minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz"
|
||||
@ -2775,6 +2633,15 @@ mongodb-uri@^0.9.7:
|
||||
resolved "https://registry.npmjs.org/mongodb-uri/-/mongodb-uri-0.9.7.tgz"
|
||||
integrity sha512-s6BdnqNoEYfViPJgkH85X5Nw5NpzxN8hoflKLweNa7vBxt2V7kaS06d74pAtqDxde8fn4r9h4dNdLiFGoNV0KA==
|
||||
|
||||
mongodb@6:
|
||||
version "6.21.0"
|
||||
resolved "https://registry.npmjs.org/mongodb/-/mongodb-6.21.0.tgz"
|
||||
integrity sha512-URyb/VXMjJ4da46OeSXg+puO39XH9DeQpWCslifrRn9JWugy0D+DvvBvkm2WxmHe61O/H19JM66p1z7RHVkZ6A==
|
||||
dependencies:
|
||||
"@mongodb-js/saslprep" "^1.3.0"
|
||||
bson "^6.10.4"
|
||||
mongodb-connection-string-url "^3.0.2"
|
||||
|
||||
mongodb@^2.0.35:
|
||||
version "2.2.36"
|
||||
resolved "https://registry.npmjs.org/mongodb/-/mongodb-2.2.36.tgz"
|
||||
@ -2793,15 +2660,6 @@ mongodb@~6.20.0:
|
||||
bson "^6.10.4"
|
||||
mongodb-connection-string-url "^3.0.2"
|
||||
|
||||
mongodb@6:
|
||||
version "6.21.0"
|
||||
resolved "https://registry.npmjs.org/mongodb/-/mongodb-6.21.0.tgz"
|
||||
integrity sha512-URyb/VXMjJ4da46OeSXg+puO39XH9DeQpWCslifrRn9JWugy0D+DvvBvkm2WxmHe61O/H19JM66p1z7RHVkZ6A==
|
||||
dependencies:
|
||||
"@mongodb-js/saslprep" "^1.3.0"
|
||||
bson "^6.10.4"
|
||||
mongodb-connection-string-url "^3.0.2"
|
||||
|
||||
mongoose@^8.19.4:
|
||||
version "8.19.4"
|
||||
resolved "https://registry.npmjs.org/mongoose/-/mongoose-8.19.4.tgz"
|
||||
@ -2827,16 +2685,16 @@ mquery@5.0.0:
|
||||
dependencies:
|
||||
debug "4.x"
|
||||
|
||||
ms@^2.1.1, ms@^2.1.3, ms@2.1.3:
|
||||
version "2.1.3"
|
||||
resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
|
||||
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
|
||||
|
||||
ms@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz"
|
||||
integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
|
||||
|
||||
ms@2.1.3, ms@^2.1.1, ms@^2.1.3:
|
||||
version "2.1.3"
|
||||
resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
|
||||
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
|
||||
|
||||
msgpack-js@0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.npmjs.org/msgpack-js/-/msgpack-js-0.3.0.tgz"
|
||||
@ -2861,16 +2719,16 @@ natural-compare@^1.4.0:
|
||||
resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz"
|
||||
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
|
||||
|
||||
negotiator@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz"
|
||||
integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==
|
||||
|
||||
negotiator@0.6.3:
|
||||
version "0.6.3"
|
||||
resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz"
|
||||
integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
|
||||
|
||||
negotiator@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz"
|
||||
integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==
|
||||
|
||||
netmask@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz"
|
||||
@ -3197,7 +3055,7 @@ prettier-linter-helpers@^1.0.0:
|
||||
dependencies:
|
||||
fast-diff "^1.1.2"
|
||||
|
||||
prettier@^3.6.2, prettier@>=3.0.0:
|
||||
prettier@^3.6.2:
|
||||
version "3.6.2"
|
||||
resolved "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz"
|
||||
integrity sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==
|
||||
@ -3221,24 +3079,6 @@ prop-types@^15.8.1:
|
||||
object-assign "^4.1.1"
|
||||
react-is "^16.13.1"
|
||||
|
||||
protobufjs@^7.2.5, protobufjs@^7.5.3:
|
||||
version "7.5.4"
|
||||
resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz"
|
||||
integrity sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==
|
||||
dependencies:
|
||||
"@protobufjs/aspromise" "^1.1.2"
|
||||
"@protobufjs/base64" "^1.1.2"
|
||||
"@protobufjs/codegen" "^2.0.4"
|
||||
"@protobufjs/eventemitter" "^1.1.0"
|
||||
"@protobufjs/fetch" "^1.1.0"
|
||||
"@protobufjs/float" "^1.0.2"
|
||||
"@protobufjs/inquire" "^1.1.0"
|
||||
"@protobufjs/path" "^1.1.2"
|
||||
"@protobufjs/pool" "^1.1.0"
|
||||
"@protobufjs/utf8" "^1.1.0"
|
||||
"@types/node" ">=13.7.0"
|
||||
long "^5.0.0"
|
||||
|
||||
proxy-addr@^2.0.7:
|
||||
version "2.0.7"
|
||||
resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz"
|
||||
@ -3361,17 +3201,16 @@ readdirp@~3.6.0:
|
||||
dependencies:
|
||||
picomatch "^2.2.1"
|
||||
|
||||
redis@^4.6.14:
|
||||
version "4.7.1"
|
||||
resolved "https://registry.npmjs.org/redis/-/redis-4.7.1.tgz"
|
||||
integrity sha512-S1bJDnqLftzHXHP8JsT5II/CtHWQrASX5K96REjWjlmWKrviSOLWmM7QnRLstAWsu1VBBV1ffV6DzCvxNP0UJQ==
|
||||
redis@^5.10.0:
|
||||
version "5.10.0"
|
||||
resolved "https://registry.yarnpkg.com/redis/-/redis-5.10.0.tgz#c1b26ba2acd9c5fcc0d1724a3c7f0984ca43f48b"
|
||||
integrity sha512-0/Y+7IEiTgVGPrLFKy8oAEArSyEJkU0zvgV5xyi9NzNQ+SLZmyFbUsWIbgPcd4UdUh00opXGKlXJwMmsis5Byw==
|
||||
dependencies:
|
||||
"@redis/bloom" "1.2.0"
|
||||
"@redis/client" "1.6.1"
|
||||
"@redis/graph" "1.1.1"
|
||||
"@redis/json" "1.0.7"
|
||||
"@redis/search" "1.2.0"
|
||||
"@redis/time-series" "1.1.0"
|
||||
"@redis/bloom" "5.10.0"
|
||||
"@redis/client" "5.10.0"
|
||||
"@redis/json" "5.10.0"
|
||||
"@redis/search" "5.10.0"
|
||||
"@redis/time-series" "5.10.0"
|
||||
|
||||
reflect.getprototypeof@^1.0.6, reflect.getprototypeof@^1.0.9:
|
||||
version "1.0.10"
|
||||
@ -3404,6 +3243,11 @@ regexpp@^3.0.0:
|
||||
resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz"
|
||||
integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==
|
||||
|
||||
require-directory@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz"
|
||||
integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
|
||||
|
||||
require_optional@~1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz"
|
||||
@ -3412,11 +3256,6 @@ require_optional@~1.0.0:
|
||||
resolve-from "^2.0.0"
|
||||
semver "^5.1.0"
|
||||
|
||||
require-directory@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz"
|
||||
integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
|
||||
|
||||
resolve-from@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz"
|
||||
@ -3491,7 +3330,7 @@ safe-array-concat@^1.1.3:
|
||||
has-symbols "^1.1.0"
|
||||
isarray "^2.0.5"
|
||||
|
||||
safe-buffer@^5.0.1, safe-buffer@5.2.1:
|
||||
safe-buffer@5.2.1, safe-buffer@^5.0.1:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz"
|
||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||
@ -3523,12 +3362,7 @@ safe-regex-test@^1.1.0:
|
||||
resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
||||
semver@^5.1.0:
|
||||
version "5.7.2"
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz"
|
||||
integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
|
||||
|
||||
semver@^5.6.0:
|
||||
semver@^5.1.0, semver@^5.6.0:
|
||||
version "5.7.2"
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz"
|
||||
integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
|
||||
@ -3538,12 +3372,7 @@ semver@^6.3.1:
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz"
|
||||
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
|
||||
|
||||
semver@^7.0.0, semver@^7.5.3, semver@^7.5.4, semver@^7.7.3:
|
||||
version "7.7.3"
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz"
|
||||
integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==
|
||||
|
||||
semver@^7.3.8:
|
||||
semver@^7.0.0, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@^7.7.3:
|
||||
version "7.7.3"
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz"
|
||||
integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==
|
||||
@ -3743,7 +3572,7 @@ socks-proxy-agent@^8.0.5:
|
||||
debug "^4.3.4"
|
||||
socks "^2.8.3"
|
||||
|
||||
socks@^2.7.1, socks@^2.8.3:
|
||||
socks@^2.8.3:
|
||||
version "2.8.7"
|
||||
resolved "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz"
|
||||
integrity sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==
|
||||
@ -3788,16 +3617,16 @@ standard@^17.1.2:
|
||||
standard-engine "^15.1.0"
|
||||
version-guard "^1.1.1"
|
||||
|
||||
statuses@^2.0.1:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz"
|
||||
integrity sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==
|
||||
|
||||
statuses@2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz"
|
||||
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
|
||||
|
||||
statuses@^2.0.1:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz"
|
||||
integrity sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==
|
||||
|
||||
stop-iteration-iterator@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz"
|
||||
@ -3824,13 +3653,6 @@ streamx@^2.15.0, streamx@^2.21.0:
|
||||
fast-fifo "^1.3.2"
|
||||
text-decoder "^1.1.0"
|
||||
|
||||
string_decoder@~1.0.0:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz"
|
||||
integrity sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==
|
||||
dependencies:
|
||||
safe-buffer "~5.1.0"
|
||||
|
||||
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
|
||||
@ -3899,6 +3721,13 @@ string.prototype.trimstart@^1.0.8:
|
||||
define-properties "^1.2.1"
|
||||
es-object-atoms "^1.0.0"
|
||||
|
||||
string_decoder@~1.0.0:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz"
|
||||
integrity sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==
|
||||
dependencies:
|
||||
safe-buffer "~5.1.0"
|
||||
|
||||
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
|
||||
@ -4280,11 +4109,6 @@ y18n@^5.0.5:
|
||||
resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz"
|
||||
integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
|
||||
|
||||
yallist@4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz"
|
||||
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
|
||||
|
||||
yargs-parser@^21.1.1:
|
||||
version "21.1.1"
|
||||
resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user