@xiboplayer/xmds 0.3.5 → 0.3.7
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/package.json +2 -2
- package/src/rest-client.js +11 -0
- package/src/xmds-client.js +14 -1
- package/src/xmds.test.js +141 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xiboplayer/xmds",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"description": "XMDS SOAP client for Xibo CMS communication",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"./xmds": "./src/xmds.js"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@xiboplayer/utils": "0.3.
|
|
12
|
+
"@xiboplayer/utils": "0.3.7"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"vitest": "^2.0.0"
|
package/src/rest-client.js
CHANGED
|
@@ -326,6 +326,17 @@ export class RestClient {
|
|
|
326
326
|
* SubmitStats - submit proof of play statistics
|
|
327
327
|
* POST /stats → JSON acknowledgement
|
|
328
328
|
*/
|
|
329
|
+
/**
|
|
330
|
+
* ReportFaults - submit fault data to CMS for dashboard alerts
|
|
331
|
+
* POST /fault → JSON acknowledgement
|
|
332
|
+
* @param {string} faultJson - JSON-encoded fault data
|
|
333
|
+
* @returns {Promise<boolean>}
|
|
334
|
+
*/
|
|
335
|
+
async reportFaults(faultJson) {
|
|
336
|
+
const result = await this.restSend('POST', '/fault', { fault: faultJson });
|
|
337
|
+
return result?.success === true;
|
|
338
|
+
}
|
|
339
|
+
|
|
329
340
|
async submitStats(statsXml) {
|
|
330
341
|
try {
|
|
331
342
|
// Accept array (JSON-native) or string (XML) — send under the right key
|
package/src/xmds-client.js
CHANGED
|
@@ -73,7 +73,7 @@ export class XmdsClient {
|
|
|
73
73
|
*/
|
|
74
74
|
async call(method, params = {}) {
|
|
75
75
|
const xmdsUrl = this.rewriteXmdsUrl(this.config.cmsAddress);
|
|
76
|
-
const url = `${xmdsUrl}${xmdsUrl.includes('?') ? '&' : '?'}v=${this.schemaVersion}`;
|
|
76
|
+
const url = `${xmdsUrl}${xmdsUrl.includes('?') ? '&' : '?'}v=${this.schemaVersion}&method=${method}`;
|
|
77
77
|
const body = this.buildEnvelope(method, params);
|
|
78
78
|
|
|
79
79
|
log.debug(`${method}`, params);
|
|
@@ -354,6 +354,19 @@ export class XmdsClient {
|
|
|
354
354
|
* @param {string} statsXml - XML-encoded stats string
|
|
355
355
|
* @returns {Promise<boolean>} - true if stats were successfully submitted
|
|
356
356
|
*/
|
|
357
|
+
/**
|
|
358
|
+
* ReportFaults - submit fault data to CMS for dashboard alerts
|
|
359
|
+
* @param {string} faultJson - JSON-encoded fault data
|
|
360
|
+
* @returns {Promise<boolean>}
|
|
361
|
+
*/
|
|
362
|
+
async reportFaults(faultJson) {
|
|
363
|
+
return this.call('ReportFaults', {
|
|
364
|
+
serverKey: this.config.cmsKey,
|
|
365
|
+
hardwareKey: this.config.hardwareKey,
|
|
366
|
+
fault: faultJson
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
|
|
357
370
|
async submitStats(statsXml) {
|
|
358
371
|
try {
|
|
359
372
|
const xml = await this.call('SubmitStats', {
|
package/src/xmds.test.js
CHANGED
|
@@ -70,6 +70,68 @@ describe('XmdsClient - RegisterDisplay', () => {
|
|
|
70
70
|
});
|
|
71
71
|
});
|
|
72
72
|
|
|
73
|
+
describe('XmdsClient - URL construction', () => {
|
|
74
|
+
let client;
|
|
75
|
+
let mockFetch;
|
|
76
|
+
|
|
77
|
+
beforeEach(() => {
|
|
78
|
+
client = new XmdsClient({
|
|
79
|
+
cmsAddress: 'https://cms.example.com',
|
|
80
|
+
cmsKey: 'test-server-key',
|
|
81
|
+
hardwareKey: 'test-hardware-key',
|
|
82
|
+
retryOptions: { maxRetries: 0 }
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
mockFetch = vi.fn();
|
|
86
|
+
global.fetch = mockFetch;
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should include &method= query parameter in SOAP URLs', async () => {
|
|
90
|
+
mockFetch.mockResolvedValue({
|
|
91
|
+
ok: true,
|
|
92
|
+
text: async () => `<?xml version="1.0"?>
|
|
93
|
+
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
|
|
94
|
+
<soap:Body>
|
|
95
|
+
<RegisterDisplayResponse>
|
|
96
|
+
<display code="READY" message="ok"></display>
|
|
97
|
+
</RegisterDisplayResponse>
|
|
98
|
+
</soap:Body>
|
|
99
|
+
</soap:Envelope>`
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
await client.call('RegisterDisplay', {
|
|
103
|
+
serverKey: 'test-server-key',
|
|
104
|
+
hardwareKey: 'test-hardware-key'
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
const url = mockFetch.mock.calls[0][0];
|
|
108
|
+
expect(url).toBe('https://cms.example.com/xmds.php?v=5&method=RegisterDisplay');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should append method to proxy URLs with existing query params', async () => {
|
|
112
|
+
// Simulate Electron proxy URL that already has ?cms=...
|
|
113
|
+
client.rewriteXmdsUrl = () => '/xmds-proxy?cms=https%3A%2F%2Fcms.example.com';
|
|
114
|
+
|
|
115
|
+
mockFetch.mockResolvedValue({
|
|
116
|
+
ok: true,
|
|
117
|
+
text: async () => `<?xml version="1.0"?>
|
|
118
|
+
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
|
|
119
|
+
<soap:Body>
|
|
120
|
+
<ScheduleResponse><result></result></ScheduleResponse>
|
|
121
|
+
</soap:Body>
|
|
122
|
+
</soap:Envelope>`
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
await client.call('Schedule', {
|
|
126
|
+
serverKey: 'test-server-key',
|
|
127
|
+
hardwareKey: 'test-hardware-key'
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const url = mockFetch.mock.calls[0][0];
|
|
131
|
+
expect(url).toContain('&v=5&method=Schedule');
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
73
135
|
describe('XmdsClient - SubmitLog', () => {
|
|
74
136
|
let client;
|
|
75
137
|
let mockFetch;
|
|
@@ -104,7 +166,7 @@ describe('XmdsClient - SubmitLog', () => {
|
|
|
104
166
|
await client.submitLog(logXml);
|
|
105
167
|
|
|
106
168
|
expect(mockFetch).toHaveBeenCalledWith(
|
|
107
|
-
'https://cms.example.com/xmds.php?v=5',
|
|
169
|
+
'https://cms.example.com/xmds.php?v=5&method=SubmitLog',
|
|
108
170
|
expect.objectContaining({
|
|
109
171
|
method: 'POST',
|
|
110
172
|
headers: {
|
|
@@ -245,7 +307,7 @@ describe('XmdsClient - SubmitScreenShot', () => {
|
|
|
245
307
|
await client.submitScreenShot(base64Image);
|
|
246
308
|
|
|
247
309
|
expect(mockFetch).toHaveBeenCalledWith(
|
|
248
|
-
'https://cms.example.com/xmds.php?v=5',
|
|
310
|
+
'https://cms.example.com/xmds.php?v=5&method=SubmitScreenShot',
|
|
249
311
|
expect.objectContaining({
|
|
250
312
|
method: 'POST',
|
|
251
313
|
headers: {
|
|
@@ -389,7 +451,7 @@ describe('XmdsClient - BlackList', () => {
|
|
|
389
451
|
await client.blackList('42', 'media', 'Corrupt file');
|
|
390
452
|
|
|
391
453
|
expect(mockFetch).toHaveBeenCalledWith(
|
|
392
|
-
'https://cms.example.com/xmds.php?v=5',
|
|
454
|
+
'https://cms.example.com/xmds.php?v=5&method=BlackList',
|
|
393
455
|
expect.objectContaining({
|
|
394
456
|
method: 'POST',
|
|
395
457
|
headers: {
|
|
@@ -517,6 +579,80 @@ describe('XmdsClient - BlackList', () => {
|
|
|
517
579
|
});
|
|
518
580
|
});
|
|
519
581
|
|
|
582
|
+
describe('XmdsClient - ReportFaults', () => {
|
|
583
|
+
let client;
|
|
584
|
+
let mockFetch;
|
|
585
|
+
|
|
586
|
+
beforeEach(() => {
|
|
587
|
+
client = new XmdsClient({
|
|
588
|
+
cmsAddress: 'https://cms.example.com',
|
|
589
|
+
cmsKey: 'test-server-key',
|
|
590
|
+
hardwareKey: 'test-hardware-key',
|
|
591
|
+
retryOptions: { maxRetries: 0 }
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
mockFetch = vi.fn();
|
|
595
|
+
global.fetch = mockFetch;
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
it('should build correct SOAP envelope for ReportFaults with JSON fault data', async () => {
|
|
599
|
+
mockFetch.mockResolvedValue({
|
|
600
|
+
ok: true,
|
|
601
|
+
text: async () => `<?xml version="1.0"?>
|
|
602
|
+
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
|
|
603
|
+
<soap:Body>
|
|
604
|
+
<ReportFaultsResponse>
|
|
605
|
+
<success>true</success>
|
|
606
|
+
</ReportFaultsResponse>
|
|
607
|
+
</soap:Body>
|
|
608
|
+
</soap:Envelope>`
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
const fault = JSON.stringify([{
|
|
612
|
+
code: 'LAYOUT_LOAD_FAILED',
|
|
613
|
+
reason: 'Missing resource',
|
|
614
|
+
date: '2026-02-21 10:00:00',
|
|
615
|
+
layoutId: 5
|
|
616
|
+
}]);
|
|
617
|
+
|
|
618
|
+
await client.reportFaults(fault);
|
|
619
|
+
|
|
620
|
+
expect(mockFetch).toHaveBeenCalledWith(
|
|
621
|
+
'https://cms.example.com/xmds.php?v=5&method=ReportFaults',
|
|
622
|
+
expect.objectContaining({
|
|
623
|
+
method: 'POST',
|
|
624
|
+
headers: {
|
|
625
|
+
'Content-Type': 'text/xml; charset=utf-8'
|
|
626
|
+
}
|
|
627
|
+
})
|
|
628
|
+
);
|
|
629
|
+
|
|
630
|
+
const body = mockFetch.mock.calls[0][1].body;
|
|
631
|
+
expect(body).toContain('<tns:ReportFaults>');
|
|
632
|
+
expect(body).toContain('<serverKey xsi:type="xsd:string">test-server-key</serverKey>');
|
|
633
|
+
expect(body).toContain('<hardwareKey xsi:type="xsd:string">test-hardware-key</hardwareKey>');
|
|
634
|
+
expect(body).toContain('<fault xsi:type="xsd:string">');
|
|
635
|
+
expect(body).toContain('LAYOUT_LOAD_FAILED');
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
it('should handle SOAP fault', async () => {
|
|
639
|
+
mockFetch.mockResolvedValue({
|
|
640
|
+
ok: true,
|
|
641
|
+
text: async () => `<?xml version="1.0"?>
|
|
642
|
+
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
|
|
643
|
+
<soap:Body>
|
|
644
|
+
<soap:Fault>
|
|
645
|
+
<faultcode>Server</faultcode>
|
|
646
|
+
<faultstring>Display not licensed</faultstring>
|
|
647
|
+
</soap:Fault>
|
|
648
|
+
</soap:Body>
|
|
649
|
+
</soap:Envelope>`
|
|
650
|
+
});
|
|
651
|
+
|
|
652
|
+
await expect(client.reportFaults('[]')).rejects.toThrow('SOAP Fault: Display not licensed');
|
|
653
|
+
});
|
|
654
|
+
});
|
|
655
|
+
|
|
520
656
|
describe('XmdsClient - NotifyStatus', () => {
|
|
521
657
|
let client;
|
|
522
658
|
let mockFetch;
|
|
@@ -565,7 +701,7 @@ describe('XmdsClient - NotifyStatus', () => {
|
|
|
565
701
|
await client.notifyStatus(status);
|
|
566
702
|
|
|
567
703
|
expect(mockFetch).toHaveBeenCalledWith(
|
|
568
|
-
'https://cms.example.com/xmds.php?v=5',
|
|
704
|
+
'https://cms.example.com/xmds.php?v=5&method=NotifyStatus',
|
|
569
705
|
expect.objectContaining({
|
|
570
706
|
method: 'POST',
|
|
571
707
|
headers: {
|
|
@@ -781,7 +917,7 @@ describe('XmdsClient - MediaInventory', () => {
|
|
|
781
917
|
await client.mediaInventory(inventoryXml);
|
|
782
918
|
|
|
783
919
|
expect(mockFetch).toHaveBeenCalledWith(
|
|
784
|
-
'https://cms.example.com/xmds.php?v=5',
|
|
920
|
+
'https://cms.example.com/xmds.php?v=5&method=MediaInventory',
|
|
785
921
|
expect.objectContaining({
|
|
786
922
|
method: 'POST',
|
|
787
923
|
headers: {
|