jamdesk 1.0.15 → 1.0.16

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.
@@ -18,6 +18,26 @@ const { mockOutput } = vi.hoisted(() => ({
18
18
  vi.mock('../../lib/output.js', () => ({ output: mockOutput }));
19
19
  vi.mock('open', () => ({ default: vi.fn() }));
20
20
  import { login } from '../../commands/login.js';
21
+ function sendOptions(port) {
22
+ return new Promise((resolve, reject) => {
23
+ const req = http.request({
24
+ hostname: '127.0.0.1',
25
+ port,
26
+ path: '/callback',
27
+ method: 'OPTIONS',
28
+ headers: {
29
+ Origin: 'https://dashboard.jamdesk.com',
30
+ 'Access-Control-Request-Method': 'POST',
31
+ 'Access-Control-Request-Private-Network': 'true',
32
+ },
33
+ }, (res) => {
34
+ res.resume();
35
+ res.on('end', () => resolve({ statusCode: res.statusCode || 0, headers: res.headers }));
36
+ });
37
+ req.on('error', reject);
38
+ req.end();
39
+ });
40
+ }
21
41
  function sendCallback(port, body) {
22
42
  return new Promise((resolve, reject) => {
23
43
  const data = JSON.stringify(body);
@@ -26,7 +46,11 @@ function sendCallback(port, body) {
26
46
  port,
27
47
  path: '/callback',
28
48
  method: 'POST',
29
- headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) },
49
+ headers: {
50
+ 'Content-Type': 'application/json',
51
+ 'Content-Length': Buffer.byteLength(data),
52
+ Origin: 'https://dashboard.jamdesk.com',
53
+ },
30
54
  }, (res) => {
31
55
  res.resume();
32
56
  res.on('end', () => resolve({ statusCode: res.statusCode || 0 }));
@@ -38,15 +62,22 @@ function sendCallback(port, body) {
38
62
  }
39
63
  /** Start login, extract port and state from the logged URL. */
40
64
  async function startLoginAndGetParams() {
41
- const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
65
+ vi.spyOn(console, 'log').mockImplementation(() => { });
42
66
  const loginPromise = login();
43
67
  await new Promise((r) => setTimeout(r, 200));
68
+ const consoleSpy = vi.mocked(console.log);
44
69
  const urlLog = consoleSpy.mock.calls.find((c) => typeof c[0] === 'string' && c[0].includes('cli-auth'));
45
70
  expect(urlLog).toBeTruthy();
46
71
  const url = new URL(urlLog[0].trim());
47
72
  const port = parseInt(url.searchParams.get('port'), 10);
48
73
  const state = url.searchParams.get('state');
49
- return { loginPromise, port, state, consoleSpy };
74
+ return { loginPromise, port, state };
75
+ }
76
+ /** Send a valid callback to shut down the login server. */
77
+ function shutdownServer(port, state) {
78
+ return sendCallback(port, {
79
+ token: 't', refreshToken: 't', email: 'e@e.com', uid: 'u', state, firebaseApiKey: 'k',
80
+ });
50
81
  }
51
82
  describe('login', () => {
52
83
  beforeEach(() => {
@@ -87,15 +118,35 @@ describe('login', () => {
87
118
  });
88
119
  expect(response.statusCode).toBe(403);
89
120
  expect(mockStoreAuth).not.toHaveBeenCalled();
90
- // Send valid state to clean up
91
- await sendCallback(port, {
92
- token: 'test',
93
- refreshToken: 'test',
94
- email: 'test@test.com',
95
- uid: 'uid',
96
- state,
97
- firebaseApiKey: 'key',
121
+ await shutdownServer(port, state);
122
+ await loginPromise;
123
+ }, 10000);
124
+ it('responds to CORS preflight with PNA header', async () => {
125
+ const { loginPromise, port, state } = await startLoginAndGetParams();
126
+ const res = await sendOptions(port);
127
+ expect(res.statusCode).toBe(204);
128
+ expect(res.headers['access-control-allow-private-network']).toBe('true');
129
+ expect(res.headers['access-control-allow-origin']).toBe('https://dashboard.jamdesk.com');
130
+ await shutdownServer(port, state);
131
+ await loginPromise;
132
+ }, 10000);
133
+ it('rejects POST without Origin header', async () => {
134
+ const { loginPromise, port, state } = await startLoginAndGetParams();
135
+ // POST without Origin (non-browser client) should be rejected
136
+ const res = await new Promise((resolve, reject) => {
137
+ const data = JSON.stringify({
138
+ refreshToken: 't', email: 'e@e.com', uid: 'u', state, firebaseApiKey: 'k',
139
+ });
140
+ const req = http.request({
141
+ hostname: '127.0.0.1', port, path: '/callback', method: 'POST',
142
+ headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) },
143
+ }, (r) => { r.resume(); r.on('end', () => resolve({ statusCode: r.statusCode || 0 })); });
144
+ req.on('error', reject);
145
+ req.write(data);
146
+ req.end();
98
147
  });
148
+ expect(res.statusCode).toBe(403);
149
+ await shutdownServer(port, state);
99
150
  await loginPromise;
100
151
  }, 10000);
101
152
  it('rejects callback missing firebaseApiKey', async () => {
@@ -110,15 +161,7 @@ describe('login', () => {
110
161
  });
111
162
  expect(response.statusCode).toBe(400);
112
163
  expect(mockStoreAuth).not.toHaveBeenCalled();
113
- // Send valid callback to clean up
114
- await sendCallback(port, {
115
- token: 'test',
116
- refreshToken: 'test',
117
- email: 'test@test.com',
118
- uid: 'uid',
119
- state,
120
- firebaseApiKey: 'key',
121
- });
164
+ await shutdownServer(port, state);
122
165
  await loginPromise;
123
166
  }, 10000);
124
167
  });
@@ -1 +1 @@
1
- {"version":3,"file":"login.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/login.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"login.test.js","sourceRoot":"","sources":["../../../src/__tests__/unit/login.test.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAaH,wBAAsB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CA0I3C"}
1
+ {"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAaH,wBAAsB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAiJ3C"}
@@ -26,8 +26,15 @@ export async function login() {
26
26
  }
27
27
  }, TIMEOUT_MS);
28
28
  const server = http.createServer(async (req, res) => {
29
- // Validate Origin header (defense-in-depth alongside state parameter)
29
+ // Validate Origin header (defense-in-depth alongside state parameter).
30
+ // OPTIONS preflight may omit Origin in non-browser clients, so only
31
+ // require it on POST where browsers always send it cross-origin.
30
32
  const origin = req.headers.origin;
33
+ if (req.method === 'POST' && origin !== ALLOWED_ORIGIN) {
34
+ res.writeHead(403);
35
+ res.end();
36
+ return;
37
+ }
31
38
  if (origin && origin !== ALLOWED_ORIGIN) {
32
39
  res.writeHead(403);
33
40
  res.end();
@@ -37,6 +44,7 @@ export async function login() {
37
44
  res.setHeader('Access-Control-Allow-Origin', ALLOWED_ORIGIN);
38
45
  res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
39
46
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
47
+ res.setHeader('Access-Control-Allow-Private-Network', 'true');
40
48
  if (req.method === 'OPTIONS') {
41
49
  res.writeHead(204);
42
50
  res.end();
@@ -74,7 +82,6 @@ export async function login() {
74
82
  res.end(JSON.stringify({ error: 'Missing required fields' }));
75
83
  return;
76
84
  }
77
- // Store auth
78
85
  await storeAuth({
79
86
  refreshToken,
80
87
  email,
@@ -1 +1 @@
1
- {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,MAAM,aAAa,GAAG,+BAA+B,CAAC;AACtD,MAAM,cAAc,GAAG,IAAI,CAAC;AAC5B,MAAM,UAAU,GAAG,OAAO,CAAC,CAAC,YAAY;AACxC,MAAM,cAAc,GAAG,aAAa,CAAC;AAErC,MAAM,CAAC,KAAK,UAAU,KAAK;IACzB,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAErD,qEAAqE;IACrE,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC3C,IAAI,OAAO,GAAG,KAAK,CAAC;QAEpB,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC9B,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO,GAAG,IAAI,CAAC;gBACf,MAAM,CAAC,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,IAAI,QAAQ,CAAC,oCAAoC,EAAE,eAAe,CAAC,CAAC,CAAC;YAC9E,CAAC;QACH,CAAC,EAAE,UAAU,CAAC,CAAC;QAEf,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;YAClD,sEAAsE;YACtE,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;YAClC,IAAI,MAAM,IAAI,MAAM,KAAK,cAAc,EAAE,CAAC;gBACxC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBACnB,GAAG,CAAC,GAAG,EAAE,CAAC;gBACV,OAAO;YACT,CAAC;YAED,6BAA6B;YAC7B,GAAG,CAAC,SAAS,CAAC,6BAA6B,EAAE,cAAc,CAAC,CAAC;YAC7D,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,eAAe,CAAC,CAAC;YAC/D,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,cAAc,CAAC,CAAC;YAE9D,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC7B,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBACnB,GAAG,CAAC,GAAG,EAAE,CAAC;gBACV,OAAO;YACT,CAAC;YAED,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,GAAG,CAAC,GAAG,KAAK,WAAW,EAAE,CAAC;gBACrD,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBACnB,GAAG,CAAC,GAAG,EAAE,CAAC;gBACV,OAAO;YACT,CAAC;YAED,uCAAuC;YACvC,MAAM,MAAM,GAAa,EAAE,CAAC;YAC5B,IAAI,QAAQ,GAAG,CAAC,CAAC;YACjB,MAAM,aAAa,GAAG,EAAE,GAAG,IAAI,CAAC;YAChC,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;gBAC9B,QAAQ,IAAK,KAAgB,CAAC,MAAM,CAAC;gBACrC,IAAI,QAAQ,GAAG,aAAa,EAAE,CAAC;oBAC7B,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;oBACnB,GAAG,CAAC,GAAG,EAAE,CAAC;oBACV,OAAO;gBACT,CAAC;gBACD,MAAM,CAAC,IAAI,CAAC,KAAe,CAAC,CAAC;YAC/B,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAC1D,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,GAAG,IAAI,CAAC;gBAEhF,mCAAmC;gBACnC,IAAI,aAAa,KAAK,KAAK,EAAE,CAAC;oBAC5B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;oBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC,CAAC,CAAC;oBAC9D,OAAO;gBACT,CAAC;gBAED,IAAI,CAAC,YAAY,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;oBACvD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;oBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC,CAAC,CAAC;oBAC9D,OAAO;gBACT,CAAC;gBAED,aAAa;gBACb,MAAM,SAAS,CAAC;oBACd,YAAY;oBACZ,KAAK;oBACL,GAAG;oBACH,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,SAAS;oBAC9C,cAAc;iBACf,CAAC,CAAC;gBAEH,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;gBAE3C,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,OAAO,GAAG,IAAI,CAAC;oBACf,YAAY,CAAC,OAAO,CAAC,CAAC;oBACtB,MAAM,CAAC,KAAK,EAAE,CAAC;oBACf,MAAM,CAAC,OAAO,CAAC,gBAAgB,KAAK,EAAE,CAAC,CAAC;oBACxC,OAAO,EAAE,CAAC;gBACZ,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,kBAAkB,GAAG,GAAG,EAAE;YAC9B,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;YAC9B,MAAM,IAAI,GAAG,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YAC9D,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,GAAG,IAAI,CAAC;gBACf,YAAY,CAAC,OAAO,CAAC,CAAC;gBACtB,MAAM,CAAC,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,IAAI,QAAQ,CAAC,0DAA0D,EAAE,YAAY,CAAC,CAAC,CAAC;gBAC/F,OAAO;YACT,CAAC;YAED,MAAM,QAAQ,GAAG,GAAG,aAAa,kBAAkB,IAAI,UAAU,KAAK,EAAE,CAAC;YAEzE,8DAA8D;YAC9D,MAAM,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;YACxD,OAAO,CAAC,GAAG,CAAC,OAAO,QAAQ,IAAI,CAAC,CAAC;YAEjC,oDAAoD;YACpD,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAE3E,MAAM,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QAC/C,CAAC,CAAC;QAEF,0DAA0D;QAC1D,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;QAE3C,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAC;QAE3C,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAA0B,EAAE,EAAE;YAChD,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBAC9B,sDAAsD;gBACtD,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;YAChC,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,OAAO,GAAG,IAAI,CAAC;oBACf,YAAY,CAAC,OAAO,CAAC,CAAC;oBACtB,MAAM,CAAC,IAAI,QAAQ,CAAC,oCAAoC,GAAG,CAAC,OAAO,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC;gBAC1F,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,MAAM,aAAa,GAAG,+BAA+B,CAAC;AACtD,MAAM,cAAc,GAAG,IAAI,CAAC;AAC5B,MAAM,UAAU,GAAG,OAAO,CAAC,CAAC,YAAY;AACxC,MAAM,cAAc,GAAG,aAAa,CAAC;AAErC,MAAM,CAAC,KAAK,UAAU,KAAK;IACzB,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAErD,qEAAqE;IACrE,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC3C,IAAI,OAAO,GAAG,KAAK,CAAC;QAEpB,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC9B,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO,GAAG,IAAI,CAAC;gBACf,MAAM,CAAC,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,IAAI,QAAQ,CAAC,oCAAoC,EAAE,eAAe,CAAC,CAAC,CAAC;YAC9E,CAAC;QACH,CAAC,EAAE,UAAU,CAAC,CAAC;QAEf,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;YAClD,uEAAuE;YACvE,oEAAoE;YACpE,iEAAiE;YACjE,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;YAClC,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,cAAc,EAAE,CAAC;gBACvD,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBACnB,GAAG,CAAC,GAAG,EAAE,CAAC;gBACV,OAAO;YACT,CAAC;YACD,IAAI,MAAM,IAAI,MAAM,KAAK,cAAc,EAAE,CAAC;gBACxC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBACnB,GAAG,CAAC,GAAG,EAAE,CAAC;gBACV,OAAO;YACT,CAAC;YAED,6BAA6B;YAC7B,GAAG,CAAC,SAAS,CAAC,6BAA6B,EAAE,cAAc,CAAC,CAAC;YAC7D,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,eAAe,CAAC,CAAC;YAC/D,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,cAAc,CAAC,CAAC;YAC9D,GAAG,CAAC,SAAS,CAAC,sCAAsC,EAAE,MAAM,CAAC,CAAC;YAE9D,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC7B,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBACnB,GAAG,CAAC,GAAG,EAAE,CAAC;gBACV,OAAO;YACT,CAAC;YAED,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,GAAG,CAAC,GAAG,KAAK,WAAW,EAAE,CAAC;gBACrD,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBACnB,GAAG,CAAC,GAAG,EAAE,CAAC;gBACV,OAAO;YACT,CAAC;YAED,uCAAuC;YACvC,MAAM,MAAM,GAAa,EAAE,CAAC;YAC5B,IAAI,QAAQ,GAAG,CAAC,CAAC;YACjB,MAAM,aAAa,GAAG,EAAE,GAAG,IAAI,CAAC;YAChC,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;gBAC9B,QAAQ,IAAK,KAAgB,CAAC,MAAM,CAAC;gBACrC,IAAI,QAAQ,GAAG,aAAa,EAAE,CAAC;oBAC7B,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;oBACnB,GAAG,CAAC,GAAG,EAAE,CAAC;oBACV,OAAO;gBACT,CAAC;gBACD,MAAM,CAAC,IAAI,CAAC,KAAe,CAAC,CAAC;YAC/B,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAC1D,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,GAAG,IAAI,CAAC;gBAEhF,mCAAmC;gBACnC,IAAI,aAAa,KAAK,KAAK,EAAE,CAAC;oBAC5B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;oBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC,CAAC,CAAC;oBAC9D,OAAO;gBACT,CAAC;gBAED,IAAI,CAAC,YAAY,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;oBACvD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;oBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC,CAAC,CAAC;oBAC9D,OAAO;gBACT,CAAC;gBAED,MAAM,SAAS,CAAC;oBACd,YAAY;oBACZ,KAAK;oBACL,GAAG;oBACH,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,SAAS;oBAC9C,cAAc;iBACf,CAAC,CAAC;gBAEH,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;gBAE3C,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,OAAO,GAAG,IAAI,CAAC;oBACf,YAAY,CAAC,OAAO,CAAC,CAAC;oBACtB,MAAM,CAAC,KAAK,EAAE,CAAC;oBACf,MAAM,CAAC,OAAO,CAAC,gBAAgB,KAAK,EAAE,CAAC,CAAC;oBACxC,OAAO,EAAE,CAAC;gBACZ,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,kBAAkB,GAAG,GAAG,EAAE;YAC9B,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;YAC9B,MAAM,IAAI,GAAG,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YAC9D,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,GAAG,IAAI,CAAC;gBACf,YAAY,CAAC,OAAO,CAAC,CAAC;gBACtB,MAAM,CAAC,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,IAAI,QAAQ,CAAC,0DAA0D,EAAE,YAAY,CAAC,CAAC,CAAC;gBAC/F,OAAO;YACT,CAAC;YAED,MAAM,QAAQ,GAAG,GAAG,aAAa,kBAAkB,IAAI,UAAU,KAAK,EAAE,CAAC;YAEzE,8DAA8D;YAC9D,MAAM,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;YACxD,OAAO,CAAC,GAAG,CAAC,OAAO,QAAQ,IAAI,CAAC,CAAC;YAEjC,oDAAoD;YACpD,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAE3E,MAAM,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QAC/C,CAAC,CAAC;QAEF,0DAA0D;QAC1D,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;QAE3C,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAC;QAE3C,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAA0B,EAAE,EAAE;YAChD,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBAC9B,sDAAsD;gBACtD,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;YAChC,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,OAAO,GAAG,IAAI,CAAC;oBACf,YAAY,CAAC,OAAO,CAAC,CAAC;oBACtB,MAAM,CAAC,IAAI,QAAQ,CAAC,oCAAoC,GAAG,CAAC,OAAO,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC;gBAC1F,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jamdesk",
3
- "version": "1.0.15",
3
+ "version": "1.0.16",
4
4
  "description": "CLI for Jamdesk — build, preview, and deploy documentation sites from MDX. Dev server with hot reload, 50+ components, OpenAPI support, AI search, and Mintlify migration",
5
5
  "keywords": [
6
6
  "jamdesk",
@@ -3,6 +3,31 @@ import { NextRequest } from 'next/server';
3
3
 
4
4
  export const runtime = 'edge';
5
5
 
6
+ const ACCENT_COLOR = '#8B5CF6';
7
+ const MAX_DESCRIPTION_LENGTH = 120;
8
+ const LONG_TITLE_THRESHOLD = 40;
9
+ const FONT_STACK =
10
+ 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
11
+ const ACCENT_GRADIENT = `linear-gradient(90deg, ${ACCENT_COLOR} 0%, #C4B5FD 50%, #A78BFA 100%)`;
12
+
13
+ function getThemeColors(isDark: boolean) {
14
+ return {
15
+ text: isDark ? '#ffffff' : '#1a1a2e',
16
+ muted: isDark ? '#a0a0b0' : '#666680',
17
+ background: isDark
18
+ ? 'linear-gradient(135deg, #1a1a3e 0%, #0f0f23 100%)'
19
+ : 'linear-gradient(135deg, #f8f8fc 0%, #ffffff 100%)',
20
+ badgeBackground: isDark
21
+ ? 'rgba(139, 92, 246, 0.15)'
22
+ : 'rgba(139, 92, 246, 0.1)',
23
+ };
24
+ }
25
+
26
+ function truncateText(text: string, maxLength: number): string {
27
+ if (text.length <= maxLength) return text;
28
+ return text.substring(0, maxLength) + '...';
29
+ }
30
+
6
31
  /**
7
32
  * OG Image Generator
8
33
  *
@@ -26,18 +51,27 @@ export async function GET(request: NextRequest) {
26
51
  const description = searchParams.get('description') || '';
27
52
  const section = searchParams.get('section') || '';
28
53
  const siteName = searchParams.get('siteName') || 'Documentation';
29
- const logo = searchParams.get('logo') || '';
30
- const theme = searchParams.get('theme') || 'dark';
54
+ const logoUrl = searchParams.get('logo') || '';
55
+ const isDark = (searchParams.get('theme') || 'dark') === 'dark';
31
56
 
32
- const isDark = theme === 'dark';
57
+ // Fetch logo and convert to base64 data URI for Satori compatibility
58
+ // (Satori doesn't support webp and can fail on remote URLs)
59
+ let logo = '';
60
+ if (logoUrl) {
61
+ try {
62
+ const res = await fetch(logoUrl);
63
+ if (res.ok) {
64
+ const contentType = res.headers.get('content-type') || 'image/png';
65
+ const buf = await res.arrayBuffer();
66
+ logo = `data:${contentType};base64,${Buffer.from(buf).toString('base64')}`;
67
+ }
68
+ } catch {
69
+ // Skip logo on fetch failure
70
+ }
71
+ }
33
72
 
34
- // Colors based on theme
35
- const bgColor = isDark ? '#0f0f23' : '#ffffff';
36
- const textColor = isDark ? '#ffffff' : '#1a1a2e';
37
- const mutedColor = isDark ? '#a0a0b0' : '#666680';
38
- const accentColor = '#8B5CF6'; // Jamdesk purple
39
- const gradientStart = isDark ? '#1a1a3e' : '#f8f8fc';
40
- const gradientEnd = isDark ? '#0f0f23' : '#ffffff';
73
+ const colors = getThemeColors(isDark);
74
+ const titleFontSize = title.length > LONG_TITLE_THRESHOLD ? '52px' : '64px';
41
75
 
42
76
  return new ImageResponse(
43
77
  (
@@ -48,15 +82,16 @@ export async function GET(request: NextRequest) {
48
82
  display: 'flex',
49
83
  flexDirection: 'column',
50
84
  padding: '60px',
51
- background: `linear-gradient(135deg, ${gradientStart} 0%, ${gradientEnd} 100%)`,
52
- fontFamily: 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
85
+ background: colors.background,
86
+ fontFamily: FONT_STACK,
53
87
  }}
54
88
  >
55
- {/* Top bar with logo and site name */}
89
+ {/* Logo and site name */}
56
90
  <div
57
91
  style={{
58
92
  display: 'flex',
59
- alignItems: 'center',
93
+ flexDirection: 'column',
94
+ alignItems: 'flex-start',
60
95
  marginBottom: '40px',
61
96
  }}
62
97
  >
@@ -64,10 +99,10 @@ export async function GET(request: NextRequest) {
64
99
  <img
65
100
  src={logo}
66
101
  alt=""
67
- width={40}
68
- height={40}
102
+ width={48}
103
+ height={48}
69
104
  style={{
70
- marginRight: '16px',
105
+ marginBottom: '16px',
71
106
  borderRadius: '8px',
72
107
  }}
73
108
  />
@@ -76,7 +111,7 @@ export async function GET(request: NextRequest) {
76
111
  style={{
77
112
  fontSize: '24px',
78
113
  fontWeight: 600,
79
- color: mutedColor,
114
+ color: colors.muted,
80
115
  textTransform: 'uppercase',
81
116
  letterSpacing: '0.05em',
82
117
  }}
@@ -97,9 +132,9 @@ export async function GET(request: NextRequest) {
97
132
  style={{
98
133
  fontSize: '18px',
99
134
  fontWeight: 500,
100
- color: accentColor,
135
+ color: ACCENT_COLOR,
101
136
  padding: '8px 16px',
102
- background: isDark ? 'rgba(139, 92, 246, 0.15)' : 'rgba(139, 92, 246, 0.1)',
137
+ background: colors.badgeBackground,
103
138
  borderRadius: '20px',
104
139
  }}
105
140
  >
@@ -108,7 +143,7 @@ export async function GET(request: NextRequest) {
108
143
  </div>
109
144
  )}
110
145
 
111
- {/* Main title */}
146
+ {/* Title and description */}
112
147
  <div
113
148
  style={{
114
149
  display: 'flex',
@@ -119,9 +154,9 @@ export async function GET(request: NextRequest) {
119
154
  >
120
155
  <h1
121
156
  style={{
122
- fontSize: title.length > 40 ? '52px' : '64px',
157
+ fontSize: titleFontSize,
123
158
  fontWeight: 700,
124
- color: textColor,
159
+ color: colors.text,
125
160
  lineHeight: 1.2,
126
161
  margin: 0,
127
162
  maxWidth: '900px',
@@ -134,15 +169,13 @@ export async function GET(request: NextRequest) {
134
169
  <p
135
170
  style={{
136
171
  fontSize: '28px',
137
- color: mutedColor,
172
+ color: colors.muted,
138
173
  marginTop: '24px',
139
174
  lineHeight: 1.4,
140
175
  maxWidth: '800px',
141
176
  }}
142
177
  >
143
- {description.length > 120
144
- ? description.substring(0, 120) + '...'
145
- : description}
178
+ {truncateText(description, MAX_DESCRIPTION_LENGTH)}
146
179
  </p>
147
180
  )}
148
181
  </div>
@@ -152,7 +185,7 @@ export async function GET(request: NextRequest) {
152
185
  style={{
153
186
  display: 'flex',
154
187
  height: '6px',
155
- background: `linear-gradient(90deg, ${accentColor} 0%, #C4B5FD 50%, #A78BFA 100%)`,
188
+ background: ACCENT_GRADIENT,
156
189
  borderRadius: '3px',
157
190
  marginTop: '40px',
158
191
  }}
@@ -162,6 +195,9 @@ export async function GET(request: NextRequest) {
162
195
  {
163
196
  width: 1200,
164
197
  height: 630,
198
+ headers: {
199
+ 'Cache-Control': 'public, s-maxage=86400, stale-while-revalidate=604800',
200
+ },
165
201
  }
166
202
  );
167
203
  }
@@ -8,7 +8,7 @@
8
8
  */
9
9
 
10
10
  import type { Metadata } from 'next';
11
- import type { DocsConfig, Logo, LogoConfig, LanguageConfig, LanguageCode } from './docs-types';
11
+ import type { DocsConfig, Logo, LogoConfig, Favicon, FaviconConfig, LanguageConfig, LanguageCode } from './docs-types';
12
12
  import { transformLanguagePath, extractLanguageFromPath, isValidLanguageCode } from './language-utils';
13
13
 
14
14
  /**
@@ -23,6 +23,7 @@ function buildOgImageUrl(
23
23
  description?: string;
24
24
  section?: string;
25
25
  logo?: Logo;
26
+ favicon?: Favicon;
26
27
  theme?: 'light' | 'dark';
27
28
  }
28
29
  ): string {
@@ -40,16 +41,31 @@ function buildOgImageUrl(
40
41
  params.set('theme', options.theme);
41
42
  }
42
43
 
43
- // Get root URL (strip /docs path if present, since API endpoints are at domain root)
44
+ // For hostAtDocs sites (baseUrl ends with /docs), use the parent domain with
45
+ // /_jd/og path instead of cross-domain /api/og. LinkedIn's crawler fails to
46
+ // fetch OG images from different domains. The /_jd/og path is proxied through
47
+ // the customer's CF Worker/proxy to the ISR app's /api/og via Next.js rewrite.
48
+ const isHostAtDocs = baseUrl.endsWith('/docs');
44
49
  const rootUrl = baseUrl.replace(/\/docs$/, '');
45
50
 
46
51
  // Handle logo - prefer dark variant for OG images (dark background)
47
- if (options?.logo) {
48
- let logoPath: string;
49
- if (typeof options.logo === 'string') {
50
- logoPath = options.logo;
51
- } else {
52
- logoPath = (options.logo as LogoConfig).dark || (options.logo as LogoConfig).light;
52
+ // Satori (@vercel/og) can't render webp, so fall back to favicon if logo is webp
53
+ if (options?.logo || options?.favicon) {
54
+ let logoPath = '';
55
+ if (options?.logo) {
56
+ if (typeof options.logo === 'string') {
57
+ logoPath = options.logo;
58
+ } else {
59
+ logoPath = (options.logo as LogoConfig).dark || (options.logo as LogoConfig).light;
60
+ }
61
+ }
62
+ // Fall back to favicon when logo is webp (Satori can't decode webp)
63
+ if ((!logoPath || logoPath.endsWith('.webp')) && options?.favicon) {
64
+ if (typeof options.favicon === 'string') {
65
+ logoPath = options.favicon;
66
+ } else {
67
+ logoPath = (options.favicon as FaviconConfig).dark || (options.favicon as FaviconConfig).light;
68
+ }
53
69
  }
54
70
  // Make logo URL absolute (use root URL since assets are at domain root)
55
71
  if (logoPath && !logoPath.startsWith('http')) {
@@ -60,7 +76,10 @@ function buildOgImageUrl(
60
76
  }
61
77
  }
62
78
 
63
- return `${rootUrl}/api/og?${params.toString()}`;
79
+ // hostAtDocs: use /_jd/og (proxied to ISR app's /api/og) for same-domain OG images
80
+ // non-hostAtDocs: use /api/og directly (already same-domain)
81
+ const ogPath = isHostAtDocs ? '/_jd/og' : '/api/og';
82
+ return `${rootUrl}${ogPath}?${params.toString()}`;
64
83
  }
65
84
 
66
85
  export interface PageFrontmatter {
@@ -137,7 +156,7 @@ export function buildSeoMetadata(
137
156
  frontmatter: PageFrontmatter,
138
157
  pagePath: string,
139
158
  baseUrl: string,
140
- languages?: LanguageConfig[]
159
+ languages?: LanguageConfig[],
141
160
  ): Partial<Metadata> {
142
161
  const globalMeta = config.seo?.metatags || {};
143
162
  const pageMeta = (frontmatter.seo as Record<string, string>) || {};
@@ -210,6 +229,7 @@ export function buildSeoMetadata(
210
229
  description: frontmatter.description,
211
230
  section: frontmatter.section,
212
231
  logo: config.logo,
232
+ favicon: config.favicon,
213
233
  theme: 'dark', // Dark theme looks better for OG images
214
234
  }
215
235
  );
@@ -220,13 +240,19 @@ export function buildSeoMetadata(
220
240
  url: metatags['og:url'] || pageUrl,
221
241
  siteName: metatags['og:site_name'] || config.name,
222
242
  type: (metatags['og:type'] as 'website' | 'article') || 'website',
223
- images: [ogImageUrl],
243
+ images: [{
244
+ url: ogImageUrl,
245
+ width: 1200,
246
+ height: 630,
247
+ type: 'image/png',
248
+ }],
224
249
  };
225
250
  }
226
251
 
227
252
  // 9. Twitter Cards
228
253
  // Auto-generate Twitter card with OG image
229
- const twitterImageUrl = metatags['twitter:image'] || (metadata.openGraph as { images?: string[] })?.images?.[0];
254
+ const ogImages = (metadata.openGraph as { images?: Array<{ url: string }> })?.images;
255
+ const twitterImageUrl = metatags['twitter:image'] || ogImages?.[0]?.url;
230
256
  metadata.twitter = {
231
257
  card: (metatags['twitter:card'] as 'summary' | 'summary_large_image') || 'summary_large_image',
232
258
  site: metatags['twitter:site'],