@xiboplayer/proxy 0.4.1 → 0.4.4

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiboplayer/proxy",
3
- "version": "0.4.1",
3
+ "version": "0.4.4",
4
4
  "description": "CORS proxy and static server for Xibo Player (serves PWA + proxies CMS)",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
package/src/proxy.js CHANGED
@@ -150,17 +150,17 @@ export function createProxyApp({ pwaPath, appVersion = '0.0.0' }) {
150
150
  });
151
151
 
152
152
  // ─── Serve PWA static files ────────────────────────────────────────
153
- app.use('/player/pwa', express.static(pwaPath, {
153
+ app.use('/player', express.static(pwaPath, {
154
154
  setHeaders: (res, filePath) => {
155
155
  if (filePath.endsWith('sw-pwa.js')) {
156
156
  res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
157
- res.setHeader('Service-Worker-Allowed', '/player/pwa/');
157
+ res.setHeader('Service-Worker-Allowed', '/player/');
158
158
  }
159
159
  },
160
160
  }));
161
161
 
162
- app.get('/', (req, res) => res.redirect('/player/pwa/'));
163
- app.get('/player/pwa/{*splat}', (req, res) => res.sendFile(path.join(pwaPath, 'index.html')));
162
+ app.get('/', (req, res) => res.redirect('/player/'));
163
+ app.get('/player/{*splat}', (req, res) => res.sendFile(path.join(pwaPath, 'index.html')));
164
164
 
165
165
  return app;
166
166
  }
package/src/proxy.test.js CHANGED
@@ -24,33 +24,36 @@ function makeApp() {
24
24
  }
25
25
 
26
26
  // Helper to make a request to the Express app without starting a persistent server
27
- async function request(app, method, url) {
27
+ async function request(app, method, url, opts = {}) {
28
28
  return new Promise((resolve) => {
29
29
  const server = app.listen(0, 'localhost', () => {
30
30
  const port = server.address().port;
31
- realFetch(`http://localhost:${port}${url}`, { method })
31
+ realFetch(`http://localhost:${port}${url}`, {
32
+ method,
33
+ redirect: opts.redirect || 'follow',
34
+ })
32
35
  .then(async (res) => {
33
36
  const body = await res.text();
34
37
  server.close();
35
- resolve({ status: res.status, body, headers: res.headers });
38
+ resolve({ status: res.status, body, headers: res.headers, url: res.url });
36
39
  })
37
40
  .catch((err) => {
38
41
  server.close();
39
- resolve({ status: 0, body: err.message, headers: new Headers() });
42
+ resolve({ status: 0, body: err.message, headers: new Headers(), url: '' });
40
43
  });
41
44
  });
42
45
  });
43
46
  }
44
47
 
45
48
  describe('createProxyApp', () => {
46
- it('serves PWA at /player/pwa/', async () => {
49
+ it('serves PWA at /player/', async () => {
47
50
  const app = makeApp();
48
- const res = await request(app, 'GET', '/player/pwa/');
51
+ const res = await request(app, 'GET', '/player/');
49
52
  expect(res.status).toBe(200);
50
53
  expect(res.body).toContain('test');
51
54
  });
52
55
 
53
- it('redirects / to /player/pwa/', async () => {
56
+ it('redirects / to /player/', async () => {
54
57
  const app = makeApp();
55
58
  // fetch follows redirects by default, so we check the final body
56
59
  const res = await request(app, 'GET', '/');
@@ -81,8 +84,20 @@ describe('createProxyApp', () => {
81
84
 
82
85
  it('SPA fallback serves index.html for sub-routes', async () => {
83
86
  const app = makeApp();
84
- const res = await request(app, 'GET', '/player/pwa/some/deep/route');
87
+ const res = await request(app, 'GET', '/player/some/deep/route');
85
88
  expect(res.status).toBe(200);
86
89
  expect(res.body).toContain('test');
87
90
  });
91
+
92
+ // Regression: CMS widget JS requests /player/cache/media/193.json
93
+ // which must be within the SW scope (/player/) to be intercepted.
94
+ // Previously PWA was at /player/pwa/ and these requests 404'd.
95
+ it('serves /player/cache/* paths within SW scope (RSS widget data)', async () => {
96
+ const app = makeApp();
97
+ // /player/cache/media/193.json is a virtual path handled by SW in-browser,
98
+ // but Express should serve the SPA fallback (not 404)
99
+ const res = await request(app, 'GET', '/player/cache/media/193.json');
100
+ expect(res.status).toBe(200);
101
+ expect(res.body).toContain('test'); // SPA fallback
102
+ });
88
103
  });