s3db.js 10.0.4 → 10.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/s3db-cli.js +0 -0
- package/dist/s3db.cjs.js +99 -11
- package/dist/s3db.cjs.js.map +1 -1
- package/dist/s3db.es.js +99 -11
- package/dist/s3db.es.js.map +1 -1
- package/mcp/README.md +1728 -0
- package/package.json +24 -22
- package/src/plugins/eventual-consistency.plugin.js +122 -10
package/dist/s3db-cli.js
CHANGED
|
File without changes
|
package/dist/s3db.cjs.js
CHANGED
|
@@ -5352,79 +5352,163 @@ class EventualConsistencyPlugin extends Plugin {
|
|
|
5352
5352
|
recordCount: a.recordCount
|
|
5353
5353
|
}));
|
|
5354
5354
|
}
|
|
5355
|
+
/**
|
|
5356
|
+
* Fill gaps in analytics data with zeros for continuous time series
|
|
5357
|
+
* @private
|
|
5358
|
+
* @param {Array} data - Sparse analytics data
|
|
5359
|
+
* @param {string} period - Period type ('hour', 'day', 'month')
|
|
5360
|
+
* @param {string} startDate - Start date (ISO format)
|
|
5361
|
+
* @param {string} endDate - End date (ISO format)
|
|
5362
|
+
* @returns {Array} Complete time series with gaps filled
|
|
5363
|
+
*/
|
|
5364
|
+
_fillGaps(data, period, startDate, endDate) {
|
|
5365
|
+
if (!data || data.length === 0) {
|
|
5366
|
+
data = [];
|
|
5367
|
+
}
|
|
5368
|
+
const dataMap = /* @__PURE__ */ new Map();
|
|
5369
|
+
data.forEach((item) => {
|
|
5370
|
+
dataMap.set(item.cohort, item);
|
|
5371
|
+
});
|
|
5372
|
+
const result = [];
|
|
5373
|
+
const emptyRecord = {
|
|
5374
|
+
count: 0,
|
|
5375
|
+
sum: 0,
|
|
5376
|
+
avg: 0,
|
|
5377
|
+
min: 0,
|
|
5378
|
+
max: 0,
|
|
5379
|
+
recordCount: 0
|
|
5380
|
+
};
|
|
5381
|
+
if (period === "hour") {
|
|
5382
|
+
const start = /* @__PURE__ */ new Date(startDate + "T00:00:00Z");
|
|
5383
|
+
const end = /* @__PURE__ */ new Date(endDate + "T23:59:59Z");
|
|
5384
|
+
for (let dt = new Date(start); dt <= end; dt.setHours(dt.getHours() + 1)) {
|
|
5385
|
+
const cohort = dt.toISOString().substring(0, 13);
|
|
5386
|
+
result.push(dataMap.get(cohort) || { cohort, ...emptyRecord });
|
|
5387
|
+
}
|
|
5388
|
+
} else if (period === "day") {
|
|
5389
|
+
const start = new Date(startDate);
|
|
5390
|
+
const end = new Date(endDate);
|
|
5391
|
+
for (let dt = new Date(start); dt <= end; dt.setDate(dt.getDate() + 1)) {
|
|
5392
|
+
const cohort = dt.toISOString().substring(0, 10);
|
|
5393
|
+
result.push(dataMap.get(cohort) || { cohort, ...emptyRecord });
|
|
5394
|
+
}
|
|
5395
|
+
} else if (period === "month") {
|
|
5396
|
+
const startYear = parseInt(startDate.substring(0, 4));
|
|
5397
|
+
const startMonth = parseInt(startDate.substring(5, 7));
|
|
5398
|
+
const endYear = parseInt(endDate.substring(0, 4));
|
|
5399
|
+
const endMonth = parseInt(endDate.substring(5, 7));
|
|
5400
|
+
for (let year = startYear; year <= endYear; year++) {
|
|
5401
|
+
const firstMonth = year === startYear ? startMonth : 1;
|
|
5402
|
+
const lastMonth = year === endYear ? endMonth : 12;
|
|
5403
|
+
for (let month = firstMonth; month <= lastMonth; month++) {
|
|
5404
|
+
const cohort = `${year}-${month.toString().padStart(2, "0")}`;
|
|
5405
|
+
result.push(dataMap.get(cohort) || { cohort, ...emptyRecord });
|
|
5406
|
+
}
|
|
5407
|
+
}
|
|
5408
|
+
}
|
|
5409
|
+
return result;
|
|
5410
|
+
}
|
|
5355
5411
|
/**
|
|
5356
5412
|
* Get analytics for entire month, broken down by days
|
|
5357
5413
|
* @param {string} resourceName - Resource name
|
|
5358
5414
|
* @param {string} field - Field name
|
|
5359
5415
|
* @param {string} month - Month in YYYY-MM format
|
|
5416
|
+
* @param {Object} options - Options
|
|
5417
|
+
* @param {boolean} options.fillGaps - Fill missing days with zeros (default: false)
|
|
5360
5418
|
* @returns {Promise<Array>} Daily analytics for the month
|
|
5361
5419
|
*/
|
|
5362
|
-
async getMonthByDay(resourceName, field, month) {
|
|
5420
|
+
async getMonthByDay(resourceName, field, month, options = {}) {
|
|
5363
5421
|
const year = parseInt(month.substring(0, 4));
|
|
5364
5422
|
const monthNum = parseInt(month.substring(5, 7));
|
|
5365
5423
|
const firstDay = new Date(year, monthNum - 1, 1);
|
|
5366
5424
|
const lastDay = new Date(year, monthNum, 0);
|
|
5367
5425
|
const startDate = firstDay.toISOString().substring(0, 10);
|
|
5368
5426
|
const endDate = lastDay.toISOString().substring(0, 10);
|
|
5369
|
-
|
|
5427
|
+
const data = await this.getAnalytics(resourceName, field, {
|
|
5370
5428
|
period: "day",
|
|
5371
5429
|
startDate,
|
|
5372
5430
|
endDate
|
|
5373
5431
|
});
|
|
5432
|
+
if (options.fillGaps) {
|
|
5433
|
+
return this._fillGaps(data, "day", startDate, endDate);
|
|
5434
|
+
}
|
|
5435
|
+
return data;
|
|
5374
5436
|
}
|
|
5375
5437
|
/**
|
|
5376
5438
|
* Get analytics for entire day, broken down by hours
|
|
5377
5439
|
* @param {string} resourceName - Resource name
|
|
5378
5440
|
* @param {string} field - Field name
|
|
5379
5441
|
* @param {string} date - Date in YYYY-MM-DD format
|
|
5442
|
+
* @param {Object} options - Options
|
|
5443
|
+
* @param {boolean} options.fillGaps - Fill missing hours with zeros (default: false)
|
|
5380
5444
|
* @returns {Promise<Array>} Hourly analytics for the day
|
|
5381
5445
|
*/
|
|
5382
|
-
async getDayByHour(resourceName, field, date) {
|
|
5383
|
-
|
|
5446
|
+
async getDayByHour(resourceName, field, date, options = {}) {
|
|
5447
|
+
const data = await this.getAnalytics(resourceName, field, {
|
|
5384
5448
|
period: "hour",
|
|
5385
5449
|
date
|
|
5386
5450
|
});
|
|
5451
|
+
if (options.fillGaps) {
|
|
5452
|
+
return this._fillGaps(data, "hour", date, date);
|
|
5453
|
+
}
|
|
5454
|
+
return data;
|
|
5387
5455
|
}
|
|
5388
5456
|
/**
|
|
5389
5457
|
* Get analytics for last N days, broken down by days
|
|
5390
5458
|
* @param {string} resourceName - Resource name
|
|
5391
5459
|
* @param {string} field - Field name
|
|
5392
5460
|
* @param {number} days - Number of days to look back (default: 7)
|
|
5461
|
+
* @param {Object} options - Options
|
|
5462
|
+
* @param {boolean} options.fillGaps - Fill missing days with zeros (default: false)
|
|
5393
5463
|
* @returns {Promise<Array>} Daily analytics
|
|
5394
5464
|
*/
|
|
5395
|
-
async getLastNDays(resourceName, field, days = 7) {
|
|
5465
|
+
async getLastNDays(resourceName, field, days = 7, options = {}) {
|
|
5396
5466
|
const dates = Array.from({ length: days }, (_, i) => {
|
|
5397
5467
|
const date = /* @__PURE__ */ new Date();
|
|
5398
5468
|
date.setDate(date.getDate() - i);
|
|
5399
5469
|
return date.toISOString().substring(0, 10);
|
|
5400
5470
|
}).reverse();
|
|
5401
|
-
|
|
5471
|
+
const data = await this.getAnalytics(resourceName, field, {
|
|
5402
5472
|
period: "day",
|
|
5403
5473
|
startDate: dates[0],
|
|
5404
5474
|
endDate: dates[dates.length - 1]
|
|
5405
5475
|
});
|
|
5476
|
+
if (options.fillGaps) {
|
|
5477
|
+
return this._fillGaps(data, "day", dates[0], dates[dates.length - 1]);
|
|
5478
|
+
}
|
|
5479
|
+
return data;
|
|
5406
5480
|
}
|
|
5407
5481
|
/**
|
|
5408
5482
|
* Get analytics for entire year, broken down by months
|
|
5409
5483
|
* @param {string} resourceName - Resource name
|
|
5410
5484
|
* @param {string} field - Field name
|
|
5411
5485
|
* @param {number} year - Year (e.g., 2025)
|
|
5486
|
+
* @param {Object} options - Options
|
|
5487
|
+
* @param {boolean} options.fillGaps - Fill missing months with zeros (default: false)
|
|
5412
5488
|
* @returns {Promise<Array>} Monthly analytics for the year
|
|
5413
5489
|
*/
|
|
5414
|
-
async getYearByMonth(resourceName, field, year) {
|
|
5415
|
-
|
|
5490
|
+
async getYearByMonth(resourceName, field, year, options = {}) {
|
|
5491
|
+
const data = await this.getAnalytics(resourceName, field, {
|
|
5416
5492
|
period: "month",
|
|
5417
5493
|
year
|
|
5418
5494
|
});
|
|
5495
|
+
if (options.fillGaps) {
|
|
5496
|
+
const startDate = `${year}-01`;
|
|
5497
|
+
const endDate = `${year}-12`;
|
|
5498
|
+
return this._fillGaps(data, "month", startDate, endDate);
|
|
5499
|
+
}
|
|
5500
|
+
return data;
|
|
5419
5501
|
}
|
|
5420
5502
|
/**
|
|
5421
5503
|
* Get analytics for entire month, broken down by hours
|
|
5422
5504
|
* @param {string} resourceName - Resource name
|
|
5423
5505
|
* @param {string} field - Field name
|
|
5424
5506
|
* @param {string} month - Month in YYYY-MM format (or 'last' for previous month)
|
|
5507
|
+
* @param {Object} options - Options
|
|
5508
|
+
* @param {boolean} options.fillGaps - Fill missing hours with zeros (default: false)
|
|
5425
5509
|
* @returns {Promise<Array>} Hourly analytics for the month (up to 24*31=744 records)
|
|
5426
5510
|
*/
|
|
5427
|
-
async getMonthByHour(resourceName, field, month) {
|
|
5511
|
+
async getMonthByHour(resourceName, field, month, options = {}) {
|
|
5428
5512
|
let year, monthNum;
|
|
5429
5513
|
if (month === "last") {
|
|
5430
5514
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -5439,11 +5523,15 @@ class EventualConsistencyPlugin extends Plugin {
|
|
|
5439
5523
|
const lastDay = new Date(year, monthNum, 0);
|
|
5440
5524
|
const startDate = firstDay.toISOString().substring(0, 10);
|
|
5441
5525
|
const endDate = lastDay.toISOString().substring(0, 10);
|
|
5442
|
-
|
|
5526
|
+
const data = await this.getAnalytics(resourceName, field, {
|
|
5443
5527
|
period: "hour",
|
|
5444
5528
|
startDate,
|
|
5445
5529
|
endDate
|
|
5446
5530
|
});
|
|
5531
|
+
if (options.fillGaps) {
|
|
5532
|
+
return this._fillGaps(data, "hour", startDate, endDate);
|
|
5533
|
+
}
|
|
5534
|
+
return data;
|
|
5447
5535
|
}
|
|
5448
5536
|
/**
|
|
5449
5537
|
* Get top records by volume
|
|
@@ -11564,7 +11652,7 @@ class Database extends EventEmitter {
|
|
|
11564
11652
|
this.id = idGenerator(7);
|
|
11565
11653
|
this.version = "1";
|
|
11566
11654
|
this.s3dbVersion = (() => {
|
|
11567
|
-
const [ok, err, version] = tryFn(() => true ? "10.0.
|
|
11655
|
+
const [ok, err, version] = tryFn(() => true ? "10.0.5" : "latest");
|
|
11568
11656
|
return ok ? version : "latest";
|
|
11569
11657
|
})();
|
|
11570
11658
|
this.resources = {};
|