@lightcone-ai/daemon 0.9.56 → 0.9.58

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.
@@ -35,11 +35,11 @@ export class XhsAdapter {
35
35
  async checkLoginStatus() {
36
36
  const profileDir = process.env.XHS_PROFILE_DIR ?? '(not set)';
37
37
 
38
- // Step 1: navigate to www first to establish session context (same as login origin)
38
+ // Navigate to www to establish session context and check __INITIAL_STATE__
39
+ // Do NOT navigate to creator here — the 401 redirect can clear cookies
39
40
  await this._cdp.send('Page.navigate', { url: 'https://www.xiaohongshu.com' });
40
41
  await sleep(4000);
41
42
 
42
- // Step 2: check login via window.__INITIAL_STATE__ (auto-agent approach — more reliable than URL check)
43
43
  const stateResult = await this._cdp.send('Runtime.evaluate', {
44
44
  expression: `(function() {
45
45
  try {
@@ -56,30 +56,22 @@ export class XhsAdapter {
56
56
  let stateData = {};
57
57
  try { stateData = JSON.parse(stateStr); } catch {}
58
58
 
59
- const loggedInViaState = !!(stateData.userId || stateData.nickname);
60
- console.error(`[XhsAdapter] __INITIAL_STATE__ check: ${stateStr}`);
61
-
62
- // Step 3: if logged in via state, also verify creator access
63
- let creatorUrl = '';
64
- if (loggedInViaState) {
65
- await this._cdp.send('Page.navigate', { url: 'https://creator.xiaohongshu.com/publish/publish' });
66
- await sleep(5000);
67
- const urlResult = await this._cdp.send('Runtime.evaluate', { expression: 'window.location.href', returnByValue: true });
68
- creatorUrl = urlResult.result?.value ?? '';
69
- }
70
-
71
- const loggedIn = loggedInViaState;
72
- const url = creatorUrl || 'www check only';
73
- console.error(`[XhsAdapter] checkLoginStatus: loggedIn=${loggedIn} creatorUrl=${creatorUrl} profileDir=${profileDir}`);
74
- return { loggedIn, url, profileDir, userId: stateData.userId, nickname: stateData.nickname };
59
+ const loggedIn = !!(stateData.userId || stateData.nickname);
60
+ console.error(`[XhsAdapter] checkLoginStatus: loggedIn=${loggedIn} state=${stateStr}`);
61
+ return { loggedIn, url: 'www.xiaohongshu.com', profileDir, userId: stateData.userId, nickname: stateData.nickname };
75
62
  }
76
63
 
77
64
  async publishImageText({ title, text, tags = [], images = [] }) {
78
65
  const cdp = this._cdp;
79
66
 
67
+ // Warm up session on www first — ensures session context is established
68
+ // before accessing creator subdomain (same flow as a real browser user)
69
+ await cdp.send('Page.navigate', { url: 'https://www.xiaohongshu.com' });
70
+ await sleep(3000);
71
+
80
72
  // Navigate to publish page
81
73
  await cdp.send('Page.navigate', { url: 'https://creator.xiaohongshu.com/publish/publish' });
82
- await sleep(3000);
74
+ await sleep(4000);
83
75
 
84
76
  // Check if we got redirected away (login expired)
85
77
  const urlAfterNav = await this._getUrl();
@@ -146,9 +138,12 @@ export class XhsAdapter {
146
138
  async publishShortVideo({ title, text, tags = [], video, cover }) {
147
139
  const cdp = this._cdp;
148
140
 
149
- await cdp.send('Page.navigate', { url: 'https://creator.xiaohongshu.com/publish/publish?source=video' });
141
+ await cdp.send('Page.navigate', { url: 'https://www.xiaohongshu.com' });
150
142
  await sleep(3000);
151
143
 
144
+ await cdp.send('Page.navigate', { url: 'https://creator.xiaohongshu.com/publish/publish?source=video' });
145
+ await sleep(4000);
146
+
152
147
  const urlAfterNav = await this._getUrl();
153
148
  if (!urlAfterNav.includes('creator.xiaohongshu.com/publish/publish')) {
154
149
  throw new Error(`LOGIN_EXPIRED: 跳转到了 ${urlAfterNav},请重新扫码连接小红书`);
@@ -120,11 +120,13 @@ async function _spawnChrome(profileDir, port) {
120
120
  }
121
121
  } catch {}
122
122
 
123
- const proc = spawn(CHROME_BIN, [
123
+ // On macOS with a display, run non-headless for best site compatibility
124
+ // (headless Chrome has detectable fingerprints that some sites block)
125
+ const isHeadless = process.platform !== 'darwin' || !!process.env.FORCE_HEADLESS;
126
+ const chromeArgs = [
124
127
  `--remote-debugging-port=${port}`,
125
128
  '--no-sandbox',
126
129
  '--disable-dev-shm-usage',
127
- '--headless=new',
128
130
  `--user-data-dir=${profileDir}`,
129
131
  '--window-size=1280,900',
130
132
  '--disable-blink-features=AutomationControlled',
@@ -135,10 +137,13 @@ async function _spawnChrome(profileDir, port) {
135
137
  '--disable-hang-monitor',
136
138
  '--use-mock-keychain',
137
139
  '--password-store=basic',
138
- '--disable-gpu',
139
140
  '--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
140
141
  'about:blank',
141
- ], { stdio: 'ignore', detached: false });
142
+ ];
143
+ if (isHeadless) {
144
+ chromeArgs.splice(3, 0, '--headless=new', '--disable-gpu');
145
+ }
146
+ const proc = spawn(CHROME_BIN, chromeArgs, { stdio: 'ignore', detached: false });
142
147
 
143
148
  proc.on('error', (err) => {
144
149
  console.error(`[ChromePool] Spawn error: ${err.message}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightcone-ai/daemon",
3
- "version": "0.9.56",
3
+ "version": "0.9.58",
4
4
  "type": "module",
5
5
  "main": "src/index.js",
6
6
  "bin": {