
Security News
upm Launches as a Fast, Tiny Package Manager Written in TypeScript
upm uses Node.js to deliver fast npm installs in about 250 KB, with a JavaScript API and security defaults.
@xiboplayer/stats
Advanced tools
Proof of play tracking, log reporting, and fault alerts for Xibo CMS.
Collects and reports display analytics to the Xibo CMS:
Renderer events StatsCollector CMS
(widgetStart/widgetEnd) (IndexedDB) (XMDS)
|
widgetStart(id, layout) -----> startWidget() -----> [in-progress Map]
|
widgetEnd(id, layout) -------> endWidget() -------> [split at hour]
| |
v v
IndexedDB getStatsForSubmission(50)
(xibo-player-stats) |
| formatStats() -> XML
| |
v submitStats() -----> CMS
clearSubmittedStats()
Renderer events LogReporter CMS
(errors, status) (IndexedDB) (XMDS)
|
log('error', msg) -----------> _saveLog() -------> IndexedDB
reportFault(code, reason) ---> [dedup 5min] -----> [alertType field]
|
getLogsForSubmission(50)
|
formatLogs() -> XML
|
submitLog() ---------> CMS
npm install @xiboplayer/stats
import { StatsCollector, formatStats } from '@xiboplayer/stats';
const stats = new StatsCollector();
await stats.init();
// Track layout playback
await stats.startLayout(123, 456); // layoutId, scheduleId
// ... layout plays for 30 seconds ...
await stats.endLayout(123, 456);
// Track widget playback
await stats.startWidget(789, 123, 456); // mediaId, layoutId, scheduleId
// ... widget plays ...
await stats.endWidget(789, 123, 456);
// Record interactive event
await stats.recordEvent('touch', 123, 789, 456); // tag, layoutId, widgetId, scheduleId
// Submit to CMS
const pending = await stats.getStatsForSubmission(50);
if (pending.length > 0) {
const xml = formatStats(pending);
await xmds.submitStats(xml);
await stats.clearSubmittedStats(pending);
}
// When CMS aggregationLevel is 'Aggregate':
const aggregated = await stats.getAggregatedStatsForSubmission(50);
// Groups by (type, layoutId, mediaId, scheduleId, hour) and sums durations
const xml = formatStats(aggregated);
await xmds.submitStats(xml);
// Clear using _rawIds from aggregated records
import { LogReporter, formatLogs, formatFaults } from '@xiboplayer/stats';
const reporter = new LogReporter();
await reporter.init();
// Log messages (stored in IndexedDB, submitted in batches)
await reporter.error('Failed to load layout', 'PLAYER');
await reporter.info('Layout loaded successfully', 'PLAYER');
await reporter.debug('Rendering widget 42', 'RENDERER');
// Report fault (triggers CMS dashboard alert)
await reporter.reportFault('LAYOUT_LOAD_FAILED', 'Layout 123 failed to render');
// Same code won't be reported again within 5 minutes (deduplication)
// Submit logs to CMS
const logs = await reporter.getLogsForSubmission(50);
if (logs.length > 0) {
const xml = formatLogs(logs);
await xmds.submitLog(xml);
await reporter.clearSubmittedLogs(logs);
}
// Submit faults (faster cycle, ~60s)
const faults = await reporter.getFaultsForSubmission(10);
if (faults.length > 0) {
const json = formatFaults(faults);
await xmds.reportFaults(json);
await reporter.clearSubmittedLogs(faults);
}
| Type | Tracked by | Fields |
|---|---|---|
layout | startLayout/endLayout | layoutId, scheduleId, start, end, duration, count |
media | startWidget/endWidget | mediaId, widgetId, layoutId, scheduleId, start, end, duration |
event | recordEvent | tag, layoutId, widgetId, scheduleId, start (point-in-time) |
new StatsCollector(cmsId?)
| Method | Returns | Description |
|---|---|---|
init() | Promise | Initialize IndexedDB (idempotent) |
startLayout(layoutId, scheduleId, opts?) | Promise | Start tracking layout |
endLayout(layoutId, scheduleId) | Promise | End layout, save to DB |
startWidget(mediaId, layoutId, scheduleId, widgetId?, opts?) | Promise | Start tracking widget |
endWidget(mediaId, layoutId, scheduleId) | Promise | End widget, save to DB |
recordEvent(tag, layoutId, widgetId, scheduleId) | Promise | Record instant event |
getStatsForSubmission(limit?) | Promise | Get unsubmitted stats (default 50) |
getAggregatedStatsForSubmission(limit?) | Promise | Get grouped stats |
clearSubmittedStats(stats) | Promise | Delete submitted records |
getAllStats() | Promise | All stats (debugging) |
clearAllStats() | Promise | Clear everything (testing) |
new LogReporter(cmsId?)
| Method | Returns | Description |
|---|---|---|
init() | Promise | Initialize IndexedDB |
log(level, message, category?, extra?) | Promise | Store log entry |
error(message, category?) | Promise | Shorthand for log('error', ...) |
audit(message, category?) | Promise | Shorthand for log('audit', ...) |
info(message, category?) | Promise | Shorthand for log('info', ...) |
debug(message, category?) | Promise | Shorthand for log('debug', ...) |
reportFault(code, reason, cooldownMs?) | Promise | Report fault with dedup (default 5min cooldown) |
getLogsForSubmission(limit?) | Promise | Get unsubmitted logs (default 50) |
getFaultsForSubmission(limit?) | Promise | Get unsubmitted faults (default 10) |
clearSubmittedLogs(logs) | Promise | Delete submitted records |
| Function | Returns | Description |
|---|---|---|
formatStats(stats) | string | Format stats as XML for XMDS SubmitStats |
formatLogs(logs) | string | Format logs as XML for XMDS SubmitLog |
formatFaults(faults) | string | Format faults as JSON for XMDS ReportFaults |
@xiboplayer/utils -- loggerxiboplayer.org · Part of the XiboPlayer SDK
FAQs
Proof of play tracking, stats reporting, and CMS logging
We found that @xiboplayer/stats demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
upm uses Node.js to deliver fast npm installs in about 250 KB, with a JavaScript API and security defaults.

Company News
Socket is joining the OpenJS Security Stewardship Program to fund Node.js vulnerability research, maintainer remediation, and security releases.

Security News
Two compromised GitHub Actions were re-enabled with malicious tags intact, exposing thousands of downstream repositories to Mini Shai-Hulud.