publishport-opencli 1.0.7 → 1.0.9

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.
@@ -1,22 +1,83 @@
1
- import{cli as e}from"@jackwener/opencli/registry";e({site:"facebook",name:"search",access:"read",description:"Search Facebook for people, pages, or posts",domain:"www.facebook.com",args:[{name:"query",required:!0,positional:!0,help:"Search query"},{name:"limit",type:"int",default:10,help:"Number of results"}],columns:["index","title","text","url"],pipeline:[{navigate:"https://www.facebook.com"},{navigate:{url:"https://www.facebook.com/search/top?q=${{ args.query | urlencode }}",settleMs:4000}},{evaluate:`(async () => {
2
- const limit = \${{ args.limit }};
3
- // Search results are typically in role="article" or role="listitem"
4
- let items = document.querySelectorAll('[role="article"]');
5
- if (items.length === 0) {
6
- items = document.querySelectorAll('[role="listitem"]');
7
- }
8
- return Array.from(items)
9
- .filter(el => el.textContent.trim().length > 20)
10
- .slice(0, limit)
11
- .map((el, i) => {
12
- const link = el.querySelector('a[href*="facebook.com/"]');
13
- const heading = el.querySelector('h2, h3, h4, strong');
14
- return {
15
- index: i + 1,
16
- title: heading ? heading.textContent.trim().substring(0, 80) : '',
17
- text: el.textContent.trim().replace(/\\s+/g, ' ').substring(0, 150),
18
- url: link ? link.href.split('?')[0] : '',
19
- };
20
- });
21
- })()
22
- `}]});
1
+ import{ArgumentError as V,AuthRequiredError as j,CommandExecutionError as P,EmptyResultError as B}from"@jackwener/opencli/errors";import{cli as Q,Strategy as T}from"@jackwener/opencli/registry";const X="https://www.facebook.com",W=50;function Y(z){const D=Number(z);if(!Number.isInteger(D)||D<1||D>W)throw new V(`facebook search --limit must be an integer between 1 and ${W}`);return D}function Z(z){const D=String(z??"").trim();if(!D)throw new V("facebook search requires a non-empty query");return D}function F(z){if(z&&typeof z==="object"&&"data"in z)return z.data;return z}function $(z){return`(() => {
2
+ const limit = ${z};
3
+
4
+ function clean(value) {
5
+ return String(value || '')
6
+ .replace(/[\\u200b-\\u200f\\u202a-\\u202e\\u2060\\ufeff]/g, '')
7
+ .replace(/\\s+/g, ' ')
8
+ .trim();
9
+ }
10
+
11
+ // FB anti-scrape obfuscation: long spaceless digit tokens and spaced
12
+ // single-char strings ("a b c d e"). Real titles never look like this.
13
+ function isObfuscated(text) {
14
+ if (!text) return true;
15
+ if (/^\\d{8,}$/.test(text)) return true;
16
+ if (/^(?:\\S ){4,}\\S$/.test(text) && text.replace(/\\s/g, '').length <= 12) return true;
17
+ return false;
18
+ }
19
+
20
+ function isEntityHref(href) {
21
+ if (!href) return false;
22
+ let u;
23
+ try { u = new URL(href, 'https://www.facebook.com'); } catch (e) { return false; }
24
+ // drop hidden-domain .com spam — real results stay on facebook.com
25
+ if (!/(^|\\.)facebook\\.com$/i.test(u.hostname)) return false;
26
+ const p = u.pathname;
27
+ if (/^\\/search(\\/|$)/i.test(p)) return false; // decoy links back to search (incl. bare /search)
28
+ // chrome / non-result destinations that the catch-all below would keep
29
+ if (/^\\/(login|checkpoint|help|policies|privacy|settings|bookmarks|messages|notifications|marketplace|gaming|friends|requests|saved|me)\\b/i.test(p)) return false;
30
+ return /^\\/(profile\\.php|groups\\/|events\\/|watch\\/|reel\\/|pages\\/|permalink\\.php|story\\.php|[^/]+\\/posts\\/|[^/]+\\/videos\\/|[A-Za-z0-9.\\-]{2,}\\/?$)/i.test(p);
31
+ }
32
+
33
+ function isAuthPage() {
34
+ const path = window.location && window.location.pathname ? window.location.pathname : '';
35
+ const body = clean(document.body && document.body.textContent);
36
+ return /^\\/(login|checkpoint)(\\/|$|\\.php)/.test(path)
37
+ || /^(Log in to Facebook|Facebook登录|登录 Facebook)/i.test(body)
38
+ || /You must log in to continue/i.test(body);
39
+ }
40
+
41
+ if (isAuthPage()) return { status: 'auth', rows: [], diagnostics: {} };
42
+
43
+ const feed = document.querySelector('[role="feed"]')
44
+ || document.querySelector('[role="main"]')
45
+ || document.body;
46
+ const anchors = Array.from(feed.querySelectorAll('a[href]'));
47
+ const seen = new Set();
48
+ const rows = [];
49
+ for (const a of anchors) {
50
+ const rawHref = a.href || a.getAttribute('href') || '';
51
+ if (!isEntityHref(rawHref)) continue;
52
+ let key;
53
+ try { const u = new URL(rawHref, 'https://www.facebook.com'); key = u.origin + u.pathname; }
54
+ catch (e) { key = rawHref.split('?')[0].split('#')[0]; }
55
+ if (seen.has(key)) continue;
56
+
57
+ const title = clean(a.textContent).substring(0, 80);
58
+ if (!title || isObfuscated(title)) continue;
59
+
60
+ // climb a few levels for the surrounding card text
61
+ let card = a;
62
+ for (let i = 0; i < 4 && card.parentElement; i += 1) {
63
+ card = card.parentElement;
64
+ if (clean(card.textContent).length > title.length + 20) break;
65
+ }
66
+ const text = clean(card.textContent).substring(0, 150);
67
+ if (isObfuscated(text)) continue;
68
+
69
+ seen.add(key);
70
+ rows.push({ index: rows.length + 1, title, text, url: key });
71
+ if (rows.length >= limit) break;
72
+ }
73
+
74
+ return {
75
+ status: rows.length ? 'ok' : 'no_rows',
76
+ rows,
77
+ diagnostics: {
78
+ feedFound: !!document.querySelector('[role="feed"]'),
79
+ anchorCount: anchors.length,
80
+ mainTextLength: clean((document.querySelector('[role="main"]') || {}).textContent).length,
81
+ },
82
+ };
83
+ })()`}async function H(z,D){const U=Z(D.query),f=Y(D.limit??10);try{await z.goto(X);await z.goto(`https://www.facebook.com/search/top?q=${encodeURIComponent(U)}`,{settleMs:4000})}catch(J){throw new P(`Failed to open facebook search: ${J instanceof Error?J.message:J}`,"Check that facebook.com is reachable and the browser extension is connected.")}let G;try{G=F(await z.evaluate($(f)))}catch(J){throw new P(`Failed to read facebook search results: ${J instanceof Error?J.message:J}`,"Facebook may not have rendered or the search markup may have changed.")}if(!G||typeof G!=="object"||!Array.isArray(G.rows))throw new P("facebook search returned malformed extraction payload");if(G.status==="auth")throw new j("www.facebook.com","Open Chrome and log in to Facebook before retrying.");if(G.rows.length>0)return G.rows;const N=G.diagnostics||{};if(N.anchorCount||N.mainTextLength>200)throw new P("facebook search page rendered but no entity results could be extracted",`Diagnostics: feed=${!!N.feedFound}, anchors=${N.anchorCount||0}, mainTextLength=${N.mainTextLength||0}.`);throw new B("facebook search",`No Facebook results were visible for "${U}".`)}const K={site:"facebook",name:"search",access:"read",description:"Search Facebook for people, pages, or posts",domain:"www.facebook.com",strategy:T.COOKIE,browser:!0,navigateBefore:!1,args:[{name:"query",required:!0,positional:!0,help:"Search query"},{name:"limit",type:"int",default:10,help:"Number of results"}],columns:["index","title","text","url"],func:H};Q(K);export const __test__={buildSearchExtractScript:$,command:K,searchFacebook:H,requireLimit:Y,requireQuery:Z};
@@ -1,4 +1,4 @@
1
- import*as L from"node:crypto";import*as Y from"node:fs";import*as C from"node:os";import*as H from"node:path";import{spawnSync as A}from"node:child_process";import{CommandExecutionError as K}from"@jackwener/opencli/errors";import{instagramPrivateApiFetch as S}from"./protocol-capture.js";import{buildReadInstagramRuntimeInfoJs as h}from"./runtime-info.js";export{buildReadInstagramRuntimeInfoJs,extractInstagramRuntimeInfo,resolveInstagramRuntimeInfo}from"./runtime-info.js";const M=0.8,D=1.91,T=0.5625,z=0.75,k="FFFFFF",l="https://www.instagram.com/",u="/api/v1/|/graphql/",v=2,w=2,I=20,d=2000,g=15000,o="19ce5f445dbfd9d29c59dc2a78c616a7fc090a8e018b9267bc4240a30244c53b",n="4",r={manufacturer:"samsung",model:"SM-G930F",android_version:24,android_release:"7.0"};export function derivePrivateApiContextFromCapture(Q){for(let X=Q.length-1;X>=0;X-=1){const Z=Q[X]?.requestHeaders??{},$={asbdId:String(Z["X-ASBD-ID"]||""),csrfToken:String(Z["X-CSRFToken"]||""),igAppId:String(Z["X-IG-App-ID"]||""),igWwwClaim:String(Z["X-IG-WWW-Claim"]||""),instagramAjax:String(Z["X-Instagram-AJAX"]||""),webSessionId:String(Z["X-Web-Session-ID"]||"")};if($.asbdId&&$.csrfToken&&$.igAppId&&$.igWwwClaim&&$.instagramAjax&&$.webSessionId)return $}return null}function p(Q){const X={};for(let Z=Q.length-1;Z>=0;Z-=1){const $=Q[Z]?.requestHeaders??{};if(!X.asbdId&&$["X-ASBD-ID"])X.asbdId=String($["X-ASBD-ID"]);if(!X.csrfToken&&$["X-CSRFToken"])X.csrfToken=String($["X-CSRFToken"]);if(!X.igAppId&&$["X-IG-App-ID"])X.igAppId=String($["X-IG-App-ID"]);if(!X.igWwwClaim&&$["X-IG-WWW-Claim"])X.igWwwClaim=String($["X-IG-WWW-Claim"]);if(!X.instagramAjax&&$["X-Instagram-AJAX"])X.instagramAjax=String($["X-Instagram-AJAX"]);if(!X.webSessionId&&$["X-Web-Session-ID"])X.webSessionId=String($["X-Web-Session-ID"])}return X}export function deriveInstagramJazoest(Q){if(!Q)return"";return`2${Array.from(Q).reduce((Z,$)=>Z+$.charCodeAt(0),0)}`}function i(Q){return new Promise((X)=>setTimeout(X,Q))}function x(Q){const X=Q instanceof Error?Q.message:String(Q);return/fetch failed|network|socket hang up|econnreset|etimedout/i.test(X)}function s(Q,X){return Q.find((Z)=>Z.name===X)?.value||""}export async function resolveInstagramPrivatePublishConfig(Q){let X;for(let Z=0;Z<v;Z+=1)try{if(typeof Q.startNetworkCapture==="function")await Q.startNetworkCapture(u);await Q.goto(`${l}?__opencli_private_probe=${Date.now()}`);await Q.wait({time:2});const[$,q,F]=await Promise.all([Q.getCookies({domain:"instagram.com"}),Q.evaluate(h()),typeof Q.readNetworkCapture==="function"?Q.readNetworkCapture():Promise.resolve([])]),N=Array.isArray(F)?F:[],W=derivePrivateApiContextFromCapture(N)??p(N),O=q?.csrfToken||s($,"csrftoken")||W.csrfToken||"",V=q?.appId||W.igAppId||"",G=q?.instagramAjax||W.instagramAjax||"";if(!O)throw new K("Instagram private route could not derive CSRF token from browser session");if(!V)throw new K("Instagram private route could not derive X-IG-App-ID from instagram runtime");if(!G)throw new K("Instagram private route could not derive X-Instagram-AJAX from instagram runtime");const J=W.asbdId||"",B=W.igWwwClaim||"",R=W.webSessionId||"";return{apiContext:{asbdId:J,csrfToken:O,igAppId:V,igWwwClaim:B,instagramAjax:G,webSessionId:R},jazoest:deriveInstagramJazoest(O)}}catch($){X=$;if(!x($)||Z>=v-1)throw $}throw X instanceof Error?X:Error(String(X))}export function buildConfigureBody(Q){const X=new URLSearchParams;X.set("archive_only","false");X.set("caption",Q.caption);X.set("clips_share_preview_to_feed","1");X.set("disable_comments","0");X.set("disable_oa_reuse","false");X.set("igtv_share_preview_to_feed","1");X.set("is_meta_only_post","0");X.set("is_unified_video","1");X.set("like_and_view_counts_disabled","0");X.set("media_share_flow","creation_flow");X.set("share_to_facebook","");X.set("share_to_fb_destination_type","USER");X.set("source_type","library");X.set("upload_id",Q.uploadId);X.set("video_subtitles_enabled","0");X.set("jazoest",Q.jazoest);return X.toString()}export function buildConfigureSidecarPayload(Q){return{archive_only:!1,caption:Q.caption,children_metadata:Q.uploadIds.map((X)=>({upload_id:X})),client_sidecar_id:Q.clientSidecarId,disable_comments:"0",is_meta_only_post:!1,is_open_to_public_submission:!1,like_and_view_counts_disabled:0,media_share_flow:"creation_flow",share_to_facebook:"",share_to_fb_destination_type:"USER",source_type:"library",jazoest:Q.jazoest}}function a(Q){switch(H.extname(Q).toLowerCase()){case".png":return"image/png";case".webp":return"image/webp";case".jpg":case".jpeg":default:return"image/jpeg"}}function e(Q){if(Q.length<24)return null;if(Q.subarray(0,8).toString("hex").toUpperCase()!=="89504E470D0A1A0A")return null;if(Q.subarray(12,16).toString("ascii")!=="IHDR")return null;return{width:Q.readUInt32BE(16),height:Q.readUInt32BE(20)}}function t(Q){if(Q.length<4||Q[0]!==255||Q[1]!==216)return null;let X=2;while(X+9<Q.length){if(Q[X]!==255){X+=1;continue}const Z=Q[X+1];X+=2;if(Z===216||Z===217)continue;if(X+2>Q.length)break;const $=Q.readUInt16BE(X);if($<2||X+$>Q.length)break;if(Z>=192&&Z<=207&&![196,200,204].includes(Z)&&$>=7)return{height:Q.readUInt16BE(X+3),width:Q.readUInt16BE(X+5)};X+=$}return null}function QQ(Q){if(Q.length<30)return null;if(Q.subarray(0,4).toString("ascii")!=="RIFF"||Q.subarray(8,12).toString("ascii")!=="WEBP")return null;const X=Q.subarray(12,16).toString("ascii");if(X==="VP8X"&&Q.length>=30)return{width:1+Q.readUIntLE(24,3),height:1+Q.readUIntLE(27,3)};if(X==="VP8 "&&Q.length>=30)return{width:Q.readUInt16LE(26)&16383,height:Q.readUInt16LE(28)&16383};if(X==="VP8L"&&Q.length>=25){const Z=Q.readUInt32LE(21);return{width:(Z&16383)+1,height:(Z>>14&16383)+1}}return null}function XQ(Q,X){const Z=H.extname(Q).toLowerCase(),$=Z===".png"?e(X):Z===".webp"?QQ(X):t(X);if(!$)throw new K(`Failed to read image dimensions for ${Q}`);return $}export function readImageAsset(Q){const X=Y.readFileSync(Q),{width:Z,height:$}=XQ(Q,X);return{filePath:Q,fileName:H.basename(Q),mimeType:a(Q),width:Z,height:$,byteLength:X.length,bytes:X}}export function isInstagramFeedAspectRatioAllowed(Q,X){const Z=Q/Math.max(X,1);return Z>=M-0.001&&Z<=D+0.001}export function getInstagramFeedNormalizedDimensions(Q,X){const Z=Q/Math.max(X,1);if(Z<M)return{width:Math.ceil(X*M),height:X};if(Z>D)return{width:Q,height:Math.ceil(Q/D)};return null}export function isInstagramStoryAspectRatioAllowed(Q,X){const Z=Q/Math.max(X,1);return Z>=T-0.001&&Z<=z+0.001}export function getInstagramStoryNormalizedDimensions(Q,X){const Z=Q/Math.max(X,1);if(Z<T)return{width:Math.ceil(X*T),height:X};if(Z>z)return{width:Q,height:Math.ceil(Q/z)};return null}function P(Q){const X=H.parse(Q);return H.join(C.tmpdir(),`opencli-instagram-private-${X.name}-${L.randomUUID()}${X.ext||".png"}`)}export function prepareImageAssetForPrivateUpload(Q){const X=readImageAsset(Q),Z=getInstagramFeedNormalizedDimensions(X.width,X.height);if(!Z)return X;if(process.platform!=="darwin")throw new K(`Instagram private publish does not support auto-normalizing ${X.fileName} on ${process.platform}`,`Use images within ${M.toFixed(2)}-${D.toFixed(2)} aspect ratio, or use the UI route`);const $=P(Q),q=A("sips",["--padToHeightWidth",String(Z.height),String(Z.width),"--padColor",k,Q,"--out",$],{encoding:"utf8"});if(q.error||q.status!==0||!Y.existsSync($)){const F=[q.error?.message,q.stderr,q.stdout].map((N)=>String(N||"").trim()).filter(Boolean).join(" ");throw new K(`Instagram private publish failed to normalize ${X.fileName}`,F||"sips padToHeightWidth failed")}return{...readImageAsset($),cleanupPath:$}}export function prepareImageAssetForPrivateStoryUpload(Q){const X=readImageAsset(Q),Z=getInstagramStoryNormalizedDimensions(X.width,X.height);if(!Z)return X;if(process.platform!=="darwin")throw new K(`Instagram private story publish does not support auto-normalizing ${X.fileName} on ${process.platform}`,`Use images within ${T.toFixed(2)}-${z.toFixed(2)} aspect ratio, or use the UI route`);const $=P(Q),q=A("sips",["--padToHeightWidth",String(Z.height),String(Z.width),"--padColor",k,Q,"--out",$],{encoding:"utf8"});if(q.error||q.status!==0||!Y.existsSync($)){const F=[q.error?.message,q.stderr,q.stdout].map((N)=>String(N||"").trim()).filter(Boolean).join(" ");throw new K(`Instagram private story publish failed to normalize ${X.fileName}`,F||"sips padToHeightWidth failed")}return{...readImageAsset($),cleanupPath:$}}function E(Q,X,Z){const $=H.join(C.tmpdir(),`opencli-instagram-${L.randomUUID()}.swift`);Y.writeFileSync($,Q);try{const q=A("swift",[$,...X],{encoding:"utf8"});if(q.error||q.status!==0){const F=[q.error?.message,q.stderr,q.stdout].map((N)=>String(N||"").trim()).filter(Boolean).join(" ");throw new K(`Instagram private publish failed to ${Z}`,F||"swift helper failed")}return JSON.parse(String(q.stdout||"{}"))}catch(q){if(q instanceof K)throw q;throw new K(`Instagram private publish failed to ${Z}`,q instanceof Error?q.message:String(q))}finally{Y.rmSync($,{force:!0})}}function ZQ(Q){if(process.platform!=="darwin")throw new K(`Instagram private mixed-media publish does not support reading video metadata on ${process.platform}`,"Use macOS for private mixed-media publishing, or rely on the UI fallback");const X=E(`
1
+ import*as B from"node:crypto";import*as U from"node:fs";import*as R from"node:os";import*as V from"node:path";import{spawnSync as z}from"node:child_process";import{CommandExecutionError as K}from"@jackwener/opencli/errors";import{instagramPrivateApiFetch as j}from"./protocol-capture.js";import{buildReadInstagramRuntimeInfoJs as h}from"./runtime-info.js";export{buildReadInstagramRuntimeInfoJs,extractInstagramRuntimeInfo,resolveInstagramRuntimeInfo}from"./runtime-info.js";const C=0.8,M=1.91,D=0.5625,T=0.75,S="FFFFFF",l="https://www.instagram.com/",u="/api/v1/|/graphql/",k=2,v=2,w=20,d=2000,I=15000,n="19ce5f445dbfd9d29c59dc2a78c616a7fc090a8e018b9267bc4240a30244c53b",o="4",p={manufacturer:"samsung",model:"SM-G930F",android_version:24,android_release:"7.0"};export function markPublishOutcomeUncertain(Q){if(Q&&typeof Q==="object")Q.instagramPublishUncertain=!0;return Q}export function isPublishOutcomeUncertain(Q){return Boolean(Q&&typeof Q==="object"&&Q.instagramPublishUncertain)}export function derivePrivateApiContextFromCapture(Q){for(let X=Q.length-1;X>=0;X-=1){const Z=Q[X]?.requestHeaders??{},$={asbdId:String(Z["X-ASBD-ID"]||""),csrfToken:String(Z["X-CSRFToken"]||""),igAppId:String(Z["X-IG-App-ID"]||""),igWwwClaim:String(Z["X-IG-WWW-Claim"]||""),instagramAjax:String(Z["X-Instagram-AJAX"]||""),webSessionId:String(Z["X-Web-Session-ID"]||"")};if($.asbdId&&$.csrfToken&&$.igAppId&&$.igWwwClaim&&$.instagramAjax&&$.webSessionId)return $}return null}function i(Q){const X={};for(let Z=Q.length-1;Z>=0;Z-=1){const $=Q[Z]?.requestHeaders??{};if(!X.asbdId&&$["X-ASBD-ID"])X.asbdId=String($["X-ASBD-ID"]);if(!X.csrfToken&&$["X-CSRFToken"])X.csrfToken=String($["X-CSRFToken"]);if(!X.igAppId&&$["X-IG-App-ID"])X.igAppId=String($["X-IG-App-ID"]);if(!X.igWwwClaim&&$["X-IG-WWW-Claim"])X.igWwwClaim=String($["X-IG-WWW-Claim"]);if(!X.instagramAjax&&$["X-Instagram-AJAX"])X.instagramAjax=String($["X-Instagram-AJAX"]);if(!X.webSessionId&&$["X-Web-Session-ID"])X.webSessionId=String($["X-Web-Session-ID"])}return X}export function deriveInstagramJazoest(Q){if(!Q)return"";return`2${Array.from(Q).reduce((Z,$)=>Z+$.charCodeAt(0),0)}`}function r(Q){return new Promise((X)=>setTimeout(X,Q))}function g(Q){const X=Q instanceof Error?Q.message:String(Q);return/fetch failed|network|socket hang up|econnreset|etimedout/i.test(X)}function s(Q,X){return Q.find((Z)=>Z.name===X)?.value||""}export async function resolveInstagramPrivatePublishConfig(Q){let X;for(let Z=0;Z<k;Z+=1)try{if(typeof Q.startNetworkCapture==="function")await Q.startNetworkCapture(u);await Q.goto(`${l}?__opencli_private_probe=${Date.now()}`);await Q.wait({time:2});const[$,q,F]=await Promise.all([Q.getCookies({domain:"instagram.com"}),Q.evaluate(h()),typeof Q.readNetworkCapture==="function"?Q.readNetworkCapture():Promise.resolve([])]),O=Array.isArray(F)?F:[],G=derivePrivateApiContextFromCapture(O)??i(O),N=q?.csrfToken||s($,"csrftoken")||G.csrfToken||"",J=q?.appId||G.igAppId||"",W=q?.instagramAjax||G.instagramAjax||"";if(!N)throw new K("Instagram private route could not derive CSRF token from browser session");if(!J)throw new K("Instagram private route could not derive X-IG-App-ID from instagram runtime");if(!W)throw new K("Instagram private route could not derive X-Instagram-AJAX from instagram runtime");const H=G.asbdId||"",Y=G.igWwwClaim||"",y=G.webSessionId||"";return{apiContext:{asbdId:H,csrfToken:N,igAppId:J,igWwwClaim:Y,instagramAjax:W,webSessionId:y},jazoest:deriveInstagramJazoest(N)}}catch($){X=$;if(!g($)||Z>=k-1)throw $}throw X instanceof Error?X:Error(String(X))}export function buildConfigureBody(Q){const X=new URLSearchParams;X.set("archive_only","false");X.set("caption",Q.caption);X.set("clips_share_preview_to_feed","1");X.set("disable_comments","0");X.set("disable_oa_reuse","false");X.set("igtv_share_preview_to_feed","1");X.set("is_meta_only_post","0");X.set("is_unified_video","1");X.set("like_and_view_counts_disabled","0");X.set("media_share_flow","creation_flow");X.set("share_to_facebook","");X.set("share_to_fb_destination_type","USER");X.set("source_type","library");X.set("upload_id",Q.uploadId);X.set("video_subtitles_enabled","0");X.set("jazoest",Q.jazoest);return X.toString()}export function buildConfigureSidecarPayload(Q){return{archive_only:!1,caption:Q.caption,children_metadata:Q.uploadIds.map((X)=>({upload_id:X})),client_sidecar_id:Q.clientSidecarId,disable_comments:"0",is_meta_only_post:!1,is_open_to_public_submission:!1,like_and_view_counts_disabled:0,media_share_flow:"creation_flow",share_to_facebook:"",share_to_fb_destination_type:"USER",source_type:"library",jazoest:Q.jazoest}}function a(Q){switch(V.extname(Q).toLowerCase()){case".png":return"image/png";case".webp":return"image/webp";case".jpg":case".jpeg":default:return"image/jpeg"}}function t(Q){if(Q.length<24)return null;if(Q.subarray(0,8).toString("hex").toUpperCase()!=="89504E470D0A1A0A")return null;if(Q.subarray(12,16).toString("ascii")!=="IHDR")return null;return{width:Q.readUInt32BE(16),height:Q.readUInt32BE(20)}}function e(Q){if(Q.length<4||Q[0]!==255||Q[1]!==216)return null;let X=2;while(X+9<Q.length){if(Q[X]!==255){X+=1;continue}const Z=Q[X+1];X+=2;if(Z===216||Z===217)continue;if(X+2>Q.length)break;const $=Q.readUInt16BE(X);if($<2||X+$>Q.length)break;if(Z>=192&&Z<=207&&![196,200,204].includes(Z)&&$>=7)return{height:Q.readUInt16BE(X+3),width:Q.readUInt16BE(X+5)};X+=$}return null}function QQ(Q){if(Q.length<30)return null;if(Q.subarray(0,4).toString("ascii")!=="RIFF"||Q.subarray(8,12).toString("ascii")!=="WEBP")return null;const X=Q.subarray(12,16).toString("ascii");if(X==="VP8X"&&Q.length>=30)return{width:1+Q.readUIntLE(24,3),height:1+Q.readUIntLE(27,3)};if(X==="VP8 "&&Q.length>=30)return{width:Q.readUInt16LE(26)&16383,height:Q.readUInt16LE(28)&16383};if(X==="VP8L"&&Q.length>=25){const Z=Q.readUInt32LE(21);return{width:(Z&16383)+1,height:(Z>>14&16383)+1}}return null}function XQ(Q,X){const Z=V.extname(Q).toLowerCase(),$=Z===".png"?t(X):Z===".webp"?QQ(X):e(X);if(!$)throw new K(`Failed to read image dimensions for ${Q}`);return $}export function readImageAsset(Q){const X=U.readFileSync(Q),{width:Z,height:$}=XQ(Q,X);return{filePath:Q,fileName:V.basename(Q),mimeType:a(Q),width:Z,height:$,byteLength:X.length,bytes:X}}export function isInstagramFeedAspectRatioAllowed(Q,X){const Z=Q/Math.max(X,1);return Z>=C-0.001&&Z<=M+0.001}export function getInstagramFeedNormalizedDimensions(Q,X){const Z=Q/Math.max(X,1);if(Z<C)return{width:Math.ceil(X*C),height:X};if(Z>M)return{width:Q,height:Math.ceil(Q/M)};return null}export function isInstagramStoryAspectRatioAllowed(Q,X){const Z=Q/Math.max(X,1);return Z>=D-0.001&&Z<=T+0.001}export function getInstagramStoryNormalizedDimensions(Q,X){const Z=Q/Math.max(X,1);if(Z<D)return{width:Math.ceil(X*D),height:X};if(Z>T)return{width:Q,height:Math.ceil(Q/T)};return null}function x(Q){const X=V.parse(Q);return V.join(R.tmpdir(),`opencli-instagram-private-${X.name}-${B.randomUUID()}${X.ext||".png"}`)}export function prepareImageAssetForPrivateUpload(Q){const X=readImageAsset(Q),Z=getInstagramFeedNormalizedDimensions(X.width,X.height);if(!Z)return X;if(process.platform!=="darwin")throw new K(`Instagram private publish does not support auto-normalizing ${X.fileName} on ${process.platform}`,`Use images within ${C.toFixed(2)}-${M.toFixed(2)} aspect ratio, or use the UI route`);const $=x(Q),q=z("sips",["--padToHeightWidth",String(Z.height),String(Z.width),"--padColor",S,Q,"--out",$],{encoding:"utf8"});if(q.error||q.status!==0||!U.existsSync($)){const F=[q.error?.message,q.stderr,q.stdout].map((O)=>String(O||"").trim()).filter(Boolean).join(" ");throw new K(`Instagram private publish failed to normalize ${X.fileName}`,F||"sips padToHeightWidth failed")}return{...readImageAsset($),cleanupPath:$}}export function prepareImageAssetForPrivateStoryUpload(Q){const X=readImageAsset(Q),Z=getInstagramStoryNormalizedDimensions(X.width,X.height);if(!Z)return X;if(process.platform!=="darwin")throw new K(`Instagram private story publish does not support auto-normalizing ${X.fileName} on ${process.platform}`,`Use images within ${D.toFixed(2)}-${T.toFixed(2)} aspect ratio, or use the UI route`);const $=x(Q),q=z("sips",["--padToHeightWidth",String(Z.height),String(Z.width),"--padColor",S,Q,"--out",$],{encoding:"utf8"});if(q.error||q.status!==0||!U.existsSync($)){const F=[q.error?.message,q.stderr,q.stdout].map((O)=>String(O||"").trim()).filter(Boolean).join(" ");throw new K(`Instagram private story publish failed to normalize ${X.fileName}`,F||"sips padToHeightWidth failed")}return{...readImageAsset($),cleanupPath:$}}function A(Q,X,Z){const $=V.join(R.tmpdir(),`opencli-instagram-${B.randomUUID()}.swift`);U.writeFileSync($,Q);try{const q=z("swift",[$,...X],{encoding:"utf8"});if(q.error||q.status!==0){const F=[q.error?.message,q.stderr,q.stdout].map((O)=>String(O||"").trim()).filter(Boolean).join(" ");throw new K(`Instagram private publish failed to ${Z}`,F||"swift helper failed")}return JSON.parse(String(q.stdout||"{}"))}catch(q){if(q instanceof K)throw q;throw new K(`Instagram private publish failed to ${Z}`,q instanceof Error?q.message:String(q))}finally{U.rmSync($,{force:!0})}}function ZQ(Q){if(process.platform!=="darwin")throw new K(`Instagram private mixed-media publish does not support reading video metadata on ${process.platform}`,"Use macOS for private mixed-media publishing, or rely on the UI fallback");const X=A(`
2
2
  import AVFoundation
3
3
  import Foundation
4
4
 
@@ -20,7 +20,7 @@ let payload: [String: Int] = [
20
20
  ]
21
21
  let data = try JSONSerialization.data(withJSONObject: payload, options: [])
22
22
  FileHandle.standardOutput.write(data)
23
- `,[Q],"read video metadata");if(!X.width||!X.height||!X.durationMs)throw new K(`Instagram private publish failed to read video metadata for ${Q}`);return{width:X.width,height:X.height,durationMs:X.durationMs}}function $Q(Q){const X=H.parse(Q);return H.join(C.tmpdir(),`opencli-instagram-private-video-cover-${X.name}-${L.randomUUID()}.jpg`)}function qQ(Q){const X=H.parse(Q);return H.join(C.tmpdir(),`opencli-instagram-story-video-${X.name}-${L.randomUUID()}${X.ext||".mp4"}`)}function FQ(Q){if(process.platform!=="darwin")throw new K(`Instagram private mixed-media publish does not support generating video covers on ${process.platform}`,"Use macOS for private mixed-media publishing, or rely on the UI fallback");const X=$Q(Q);E(`
23
+ `,[Q],"read video metadata");if(!X.width||!X.height||!X.durationMs)throw new K(`Instagram private publish failed to read video metadata for ${Q}`);return{width:X.width,height:X.height,durationMs:X.durationMs}}function $Q(Q){const X=V.parse(Q);return V.join(R.tmpdir(),`opencli-instagram-private-video-cover-${X.name}-${B.randomUUID()}.jpg`)}function qQ(Q){const X=V.parse(Q);return V.join(R.tmpdir(),`opencli-instagram-story-video-${X.name}-${B.randomUUID()}${X.ext||".mp4"}`)}function FQ(Q){if(process.platform!=="darwin")throw new K(`Instagram private mixed-media publish does not support generating video covers on ${process.platform}`,"Use macOS for private mixed-media publishing, or rely on the UI fallback");const X=$Q(Q);A(`
24
24
  import AVFoundation
25
25
  import AppKit
26
26
  import Foundation
@@ -40,7 +40,7 @@ try data.write(to: URL(fileURLWithPath: outputPath))
40
40
  let payload = ["ok": true]
41
41
  let json = try JSONSerialization.data(withJSONObject: payload, options: [])
42
42
  FileHandle.standardOutput.write(json)
43
- `,[Q,X],"generate video cover");return{...readImageAsset(X),cleanupPath:X}}export function readVideoAsset(Q){const X=Y.readFileSync(Q),Z=ZQ(Q),$=FQ(Q);return{filePath:Q,fileName:H.basename(Q),mimeType:"video/mp4",width:Z.width,height:Z.height,durationMs:Z.durationMs,byteLength:X.length,bytes:X,coverImage:$,cleanupPaths:$.cleanupPath?[$.cleanupPath]:[]}}function KQ(Q,X){if(process.platform!=="darwin")throw new K(`Instagram private story publish does not support trimming long videos on ${process.platform}`,"Use macOS for private story video publishing, or trim the video to 15 seconds first");const Z=qQ(Q);E(`
43
+ `,[Q,X],"generate video cover");return{...readImageAsset(X),cleanupPath:X}}export function readVideoAsset(Q){const X=U.readFileSync(Q),Z=ZQ(Q),$=FQ(Q);return{filePath:Q,fileName:V.basename(Q),mimeType:"video/mp4",width:Z.width,height:Z.height,durationMs:Z.durationMs,byteLength:X.length,bytes:X,coverImage:$,cleanupPaths:$.cleanupPath?[$.cleanupPath]:[]}}function KQ(Q,X){if(process.platform!=="darwin")throw new K(`Instagram private story publish does not support trimming long videos on ${process.platform}`,"Use macOS for private story video publishing, or trim the video to 15 seconds first");const Z=qQ(Q);A(`
44
44
  import AVFoundation
45
45
  import Foundation
46
46
 
@@ -72,4 +72,4 @@ if exportSession.status != .completed {
72
72
  let payload = ["ok": true]
73
73
  let json = try JSONSerialization.data(withJSONObject: payload, options: [])
74
74
  FileHandle.standardOutput.write(json)
75
- `,[Q,Z,String(X)],"trim story video");return Z}function NQ(Q){const X=readVideoAsset(Q);if(X.durationMs<=g)return X;const Z=KQ(Q,g),$=readVideoAsset(Z);return{...$,cleanupPaths:[...$.cleanupPaths||[],Z]}}function b(Q){const X=Q();return X>10000000000?Math.floor(X/1000):Math.floor(X)}export function buildConfigureToStoryPhotoPayload(Q){const X=Q.now??(()=>Date.now()),Z=b(X);return{source_type:"4",upload_id:Q.uploadId,story_media_creation_date:String(Z-17),client_shared_at:String(Z-5),client_timestamp:String(Z),configure_mode:1,edits:{crop_original_size:[Q.width,Q.height],crop_center:[0,0],crop_zoom:1.3333334},extra:{source_width:Q.width,source_height:Q.height},jazoest:Q.jazoest}}export function buildConfigureToStoryVideoPayload(Q){const X=Q.now??(()=>Date.now()),Z=b(X),$=Number((Q.durationMs/1000).toFixed(3));return{source_type:"4",upload_id:Q.uploadId,story_media_creation_date:String(Z-17),client_shared_at:String(Z-5),client_timestamp:String(Z),configure_mode:1,poster_frame_index:0,length:$,audio_muted:!1,filter_type:"0",video_result:"deprecated",extra:{source_width:Q.width,source_height:Q.height},jazoest:Q.jazoest}}function BQ(Q){const X=new URLSearchParams;for(const[Z,$]of Object.entries(Q)){if($===void 0||$===null)continue;if(typeof $==="object"){X.set(Z,JSON.stringify($));continue}X.set(Z,String($))}return X.toString()}function m(Q){const X=JSON.stringify(Q),Z=L.createHmac("sha256",o).update(X).digest("hex"),$=new URLSearchParams;$.set("ig_sig_key_version",n);$.set("signed_body",`${Z}.${X}`);return $.toString()}function U(Q){return Object.fromEntries(Object.entries({"X-ASBD-ID":Q.asbdId,"X-CSRFToken":Q.csrfToken,"X-IG-App-ID":Q.igAppId,"X-IG-WWW-Claim":Q.igWwwClaim,"X-Instagram-AJAX":Q.instagramAjax,"X-Web-Session-ID":Q.webSessionId}).filter(([,X])=>!!X))}function OQ(Q,X,Z){return{...U(Z),Accept:"*/*","Content-Type":Q.mimeType,Offset:"0","X-Entity-Length":String(Q.byteLength),"X-Entity-Name":`fb_uploader_${X}`,"X-Entity-Type":Q.mimeType,"X-Instagram-Rupload-Params":JSON.stringify({media_type:1,upload_id:X,upload_media_height:Q.height,upload_media_width:Q.width})}}function f(Q){const X=Math.min(Q.width,Q.height),Z=Number((Q.durationMs/1000).toFixed(3));return{crop_height:X,crop_width:X,crop_x1:Math.max(0,Math.floor((Q.width-X)/2)),crop_y1:Math.max(0,Math.floor((Q.height-X)/2)),mute:!1,trim_end:Z,trim_start:0}}function WQ(Q,X,Z){return{...U(Z),Accept:"*/*",Offset:"0","X-Entity-Length":String(Q.byteLength),"X-Entity-Name":`fb_uploader_${X}`,"X-Instagram-Rupload-Params":JSON.stringify({"client-passthrough":"1",is_unified_video:"0",is_sidecar:"1",media_type:2,for_album:!1,video_format:"",upload_id:X,upload_media_duration_ms:Q.durationMs,upload_media_height:Q.height,upload_media_width:Q.width,video_transform:null,video_edit_params:f(Q)})}}function GQ(Q,X,Z){return{...U(Z),Accept:"*/*",Offset:"0","X-Entity-Length":String(Q.byteLength),"X-Entity-Name":`fb_uploader_${X}`,"X-Instagram-Rupload-Params":JSON.stringify({"client-passthrough":"1",media_type:2,upload_id:X,upload_media_duration_ms:Q.durationMs,upload_media_height:Q.height,upload_media_width:Q.width,video_transform:null,video_edit_params:f(Q)})}}function HQ(Q,X,Z){return{...U(Z),Accept:"*/*","Content-Type":Q.coverImage.mimeType,Offset:"0","X-Entity-Length":String(Q.coverImage.byteLength),"X-Entity-Name":`fb_uploader_${X}`,"X-Entity-Type":Q.coverImage.mimeType,"X-Instagram-Rupload-Params":JSON.stringify({media_type:2,upload_id:X,upload_media_height:Q.height,upload_media_width:Q.width})}}async function _(Q,X){const Z=await Q.text();let $;try{$=Z?JSON.parse(Z):{}}catch{throw new K(`Instagram private publish ${X} returned invalid JSON`)}if(!Q.ok){const q=Z?` ${Z.slice(0,500)}`:"";throw new K(`Instagram private publish ${X} failed: ${Q.status}${q}`)}return $}async function j(Q,X,Z){let $;for(let q=0;q<w;q+=1)try{return await Q(X,Z)}catch(F){$=F;if(!x(F)||q>=w-1)throw F}throw $ instanceof Error?$:Error(String($))}async function JQ(Q){if(Q.type==="video")return{type:"video",asset:readVideoAsset(Q.filePath)};return{type:"image",asset:prepareImageAssetForPrivateUpload(Q.filePath)}}function c(Q){for(const X of Q){if(X.type==="image"){if(X.asset.cleanupPath)Y.rmSync(X.asset.cleanupPath,{force:!0});continue}for(const Z of X.asset.cleanupPaths||[])Y.rmSync(Z,{force:!0});if(X.asset.coverImage.cleanupPath)Y.rmSync(X.asset.coverImage.cleanupPath,{force:!0})}}async function y(Q,X,Z,$,q="feed"){if(X.type==="image"){const V=await j(Q,`https://i.instagram.com/rupload_igphoto/fb_uploader_${Z}`,{method:"POST",headers:OQ(X.asset,Z,$),body:X.asset.bytes}),G=await _(V,"upload");if(String(G?.status||"")!=="ok")throw new K(`Instagram private publish upload failed for ${X.asset.fileName}`);return}const F=await j(Q,`https://i.instagram.com/rupload_igvideo/fb_uploader_${Z}`,{method:"POST",headers:q==="story"?GQ(X.asset,Z,$):WQ(X.asset,Z,$),body:X.asset.bytes}),N=await _(F,"video upload");if(String(N?.status||"")!=="ok")throw new K(`Instagram private publish video upload failed for ${X.asset.fileName}`);const W=await j(Q,`https://i.instagram.com/rupload_igphoto/fb_uploader_${Z}`,{method:"POST",headers:HQ(X.asset,Z,$),body:X.asset.coverImage.bytes}),O=await _(W,"video cover upload");if(String(O?.status||"")!=="ok")throw new K(`Instagram private publish video cover upload failed for ${X.asset.fileName}`)}async function VQ(Q){const X=Q.waitMs??i,Z={method:"POST",headers:{...U(Q.apiContext),"Content-Type":"application/json"},body:JSON.stringify(Q.payload)};for(let $=0;$<I;$+=1){const q=await Q.fetcher("https://www.instagram.com/api/v1/media/configure_sidecar/",Z),F=await q.text();let N={};try{N=F?JSON.parse(F):{}}catch{throw new K("Instagram private publish configure_sidecar returned invalid JSON")}if(!q.ok){const O=F?` ${F.slice(0,500)}`:"";throw new K(`Instagram private publish configure_sidecar failed: ${q.status}${O}`)}const W=String(N?.message||"");if(q.status===202||/transcode not finished yet/i.test(W)){if($>=I-1)throw new K("Instagram private publish configure_sidecar timed out waiting for video transcode",F.slice(0,500));await X(d);continue}if(String(N?.status||"").toLowerCase()==="fail")throw new K("Instagram private publish configure_sidecar failed",W||F.slice(0,500));return{code:N?.media?.code}}throw new K("Instagram private publish configure_sidecar failed")}export async function publishMediaViaPrivateApi(Q){const X=Q.now??(()=>Date.now()),Z=String(X()),$=Q.mediaItems.length>1?Q.mediaItems.map((W,O)=>String(X()+O+1)):[String(X())],q=Q.fetcher??((W,O)=>S(Q.page,W,O)),F=Q.prepareMediaAsset??JQ,N=await Promise.all(Q.mediaItems.map((W)=>F(W)));try{for(let O=0;O<N.length;O+=1){const V=N[O],G=$[O];await y(q,V,G,Q.apiContext)}if($.length===1){if(N[0]?.type!=="image")throw new K("Instagram private publish only supports single-video uploads through instagram reel");const O=await q("https://www.instagram.com/api/v1/media/configure/",{method:"POST",headers:{...U(Q.apiContext),"Content-Type":"application/x-www-form-urlencoded"},body:buildConfigureBody({uploadId:$[0],caption:Q.caption,jazoest:Q.jazoest})});return{code:(await _(O,"configure"))?.media?.code,uploadIds:$}}return{code:(await VQ({fetcher:q,payload:buildConfigureSidecarPayload({uploadIds:$,caption:Q.caption,clientSidecarId:Z,jazoest:Q.jazoest}),apiContext:Q.apiContext,waitMs:Q.waitMs})).code,uploadIds:$}}finally{c(N)}}export async function publishImagesViaPrivateApi(Q){return publishMediaViaPrivateApi({page:Q.page,mediaItems:Q.imagePaths.map((X)=>({type:"image",filePath:X})),caption:Q.caption,apiContext:Q.apiContext,jazoest:Q.jazoest,now:Q.now,fetcher:Q.fetcher,waitMs:Q.waitMs,prepareMediaAsset:Q.prepareAsset?async(X)=>({type:"image",asset:await Q.prepareAsset(X.filePath)}):void 0})}export async function publishStoryViaPrivateApi(Q){const X=Q.now??(()=>Date.now()),Z=String(X()),$=Q.fetcher??((G,J)=>S(Q.page,G,J)),F=await(Q.prepareMediaAsset??(async(G)=>G.type==="video"?{type:"video",asset:NQ(G.filePath)}:{type:"image",asset:prepareImageAssetForPrivateStoryUpload(G.filePath)}))(Q.mediaItem),N=Q.currentUserId||("getCookies"in Q.page?String((await(Q.page.getCookies?.({domain:"instagram.com"})??Promise.resolve([]))).find((G)=>G.name==="ds_user_id")?.value||""):"");if(!N)throw new K("Instagram story publish could not derive current user id from browser session");const W={_csrftoken:Q.apiContext.csrfToken,_uid:N,_uuid:L.randomUUID(),device:r},O=(G,J)=>m({...buildConfigureToStoryPhotoPayload({uploadId:Z,width:G,height:J,now:X,jazoest:Q.jazoest}),...W}),V=(G,J,B)=>m({...buildConfigureToStoryVideoPayload({uploadId:Z,width:G,height:J,durationMs:B,now:X,jazoest:Q.jazoest}),...W});try{await y($,F,Z,Q.apiContext,"story");if(F.type==="image"){const B=await $("https://i.instagram.com/api/v1/media/configure_to_story/",{method:"POST",headers:{...U(Q.apiContext),"Content-Type":"application/x-www-form-urlencoded"},body:O(F.asset.width,F.asset.height)}),R=await _(B,"configure_to_story");return{mediaPk:String(R?.media?.pk||R?.media?.id||"").split("_")[0]||void 0,uploadId:Z}}await _(await $("https://i.instagram.com/api/v1/media/configure_to_story/",{method:"POST",headers:{...U(Q.apiContext),"Content-Type":"application/x-www-form-urlencoded"},body:O(F.asset.width,F.asset.height)}),"configure_to_story cover");const G=await $("https://i.instagram.com/api/v1/media/configure_to_story/?video=1",{method:"POST",headers:{...U(Q.apiContext),"Content-Type":"application/x-www-form-urlencoded"},body:V(F.asset.width,F.asset.height,F.asset.durationMs)}),J=await _(G,"configure_to_story");return{mediaPk:String(J?.media?.pk||J?.media?.id||"").split("_")[0]||void 0,uploadId:Z}}finally{c([F])}}
75
+ `,[Q,Z,String(X)],"trim story video");return Z}function NQ(Q){const X=readVideoAsset(Q);if(X.durationMs<=I)return X;const Z=KQ(Q,I),$=readVideoAsset(Z);return{...$,cleanupPaths:[...$.cleanupPaths||[],Z]}}function P(Q){const X=Q();return X>10000000000?Math.floor(X/1000):Math.floor(X)}export function buildConfigureToStoryPhotoPayload(Q){const X=Q.now??(()=>Date.now()),Z=P(X);return{source_type:"4",upload_id:Q.uploadId,story_media_creation_date:String(Z-17),client_shared_at:String(Z-5),client_timestamp:String(Z),configure_mode:1,edits:{crop_original_size:[Q.width,Q.height],crop_center:[0,0],crop_zoom:1.3333334},extra:{source_width:Q.width,source_height:Q.height},jazoest:Q.jazoest}}export function buildConfigureToStoryVideoPayload(Q){const X=Q.now??(()=>Date.now()),Z=P(X),$=Number((Q.durationMs/1000).toFixed(3));return{source_type:"4",upload_id:Q.uploadId,story_media_creation_date:String(Z-17),client_shared_at:String(Z-5),client_timestamp:String(Z),configure_mode:1,poster_frame_index:0,length:$,audio_muted:!1,filter_type:"0",video_result:"deprecated",extra:{source_width:Q.width,source_height:Q.height},jazoest:Q.jazoest}}function BQ(Q){const X=new URLSearchParams;for(const[Z,$]of Object.entries(Q)){if($===void 0||$===null)continue;if(typeof $==="object"){X.set(Z,JSON.stringify($));continue}X.set(Z,String($))}return X.toString()}function b(Q){const X=JSON.stringify(Q),Z=B.createHmac("sha256",n).update(X).digest("hex"),$=new URLSearchParams;$.set("ig_sig_key_version",o);$.set("signed_body",`${Z}.${X}`);return $.toString()}function _(Q){return Object.fromEntries(Object.entries({"X-ASBD-ID":Q.asbdId,"X-CSRFToken":Q.csrfToken,"X-IG-App-ID":Q.igAppId,"X-IG-WWW-Claim":Q.igWwwClaim,"X-Instagram-AJAX":Q.instagramAjax,"X-Web-Session-ID":Q.webSessionId}).filter(([,X])=>!!X))}function OQ(Q,X,Z){return{..._(Z),Accept:"*/*","Content-Type":Q.mimeType,Offset:"0","X-Entity-Length":String(Q.byteLength),"X-Entity-Name":`fb_uploader_${X}`,"X-Entity-Type":Q.mimeType,"X-Instagram-Rupload-Params":JSON.stringify({media_type:1,upload_id:X,upload_media_height:Q.height,upload_media_width:Q.width})}}function m(Q){const X=Math.min(Q.width,Q.height),Z=Number((Q.durationMs/1000).toFixed(3));return{crop_height:X,crop_width:X,crop_x1:Math.max(0,Math.floor((Q.width-X)/2)),crop_y1:Math.max(0,Math.floor((Q.height-X)/2)),mute:!1,trim_end:Z,trim_start:0}}function WQ(Q,X,Z){return{..._(Z),Accept:"*/*",Offset:"0","X-Entity-Length":String(Q.byteLength),"X-Entity-Name":`fb_uploader_${X}`,"X-Instagram-Rupload-Params":JSON.stringify({"client-passthrough":"1",is_unified_video:"0",is_sidecar:"1",media_type:2,for_album:!1,video_format:"",upload_id:X,upload_media_duration_ms:Q.durationMs,upload_media_height:Q.height,upload_media_width:Q.width,video_transform:null,video_edit_params:m(Q)})}}function GQ(Q,X,Z){return{..._(Z),Accept:"*/*",Offset:"0","X-Entity-Length":String(Q.byteLength),"X-Entity-Name":`fb_uploader_${X}`,"X-Instagram-Rupload-Params":JSON.stringify({"client-passthrough":"1",media_type:2,upload_id:X,upload_media_duration_ms:Q.durationMs,upload_media_height:Q.height,upload_media_width:Q.width,video_transform:null,video_edit_params:m(Q)})}}function HQ(Q,X,Z){return{..._(Z),Accept:"*/*","Content-Type":Q.coverImage.mimeType,Offset:"0","X-Entity-Length":String(Q.coverImage.byteLength),"X-Entity-Name":`fb_uploader_${X}`,"X-Entity-Type":Q.coverImage.mimeType,"X-Instagram-Rupload-Params":JSON.stringify({media_type:2,upload_id:X,upload_media_height:Q.height,upload_media_width:Q.width})}}async function L(Q,X){const Z=await Q.text();let $;try{$=Z?JSON.parse(Z):{}}catch{throw new K(`Instagram private publish ${X} returned invalid JSON`)}if(!Q.ok){const q=Z?` ${Z.slice(0,500)}`:"";throw new K(`Instagram private publish ${X} failed: ${Q.status}${q}`)}return $}async function E(Q,X,Z){let $;for(let q=0;q<v;q+=1)try{return await Q(X,Z)}catch(F){$=F;if(!g(F)||q>=v-1)throw F}throw $ instanceof Error?$:Error(String($))}async function JQ(Q){if(Q.type==="video")return{type:"video",asset:readVideoAsset(Q.filePath)};return{type:"image",asset:prepareImageAssetForPrivateUpload(Q.filePath)}}function f(Q){for(const X of Q){if(X.type==="image"){if(X.asset.cleanupPath)U.rmSync(X.asset.cleanupPath,{force:!0});continue}for(const Z of X.asset.cleanupPaths||[])U.rmSync(Z,{force:!0});if(X.asset.coverImage.cleanupPath)U.rmSync(X.asset.coverImage.cleanupPath,{force:!0})}}async function c(Q,X,Z,$,q="feed"){if(X.type==="image"){const J=await E(Q,`https://i.instagram.com/rupload_igphoto/fb_uploader_${Z}`,{method:"POST",headers:OQ(X.asset,Z,$),body:X.asset.bytes}),W=await L(J,"upload");if(String(W?.status||"")!=="ok")throw new K(`Instagram private publish upload failed for ${X.asset.fileName}`);return}const F=await E(Q,`https://i.instagram.com/rupload_igvideo/fb_uploader_${Z}`,{method:"POST",headers:q==="story"?GQ(X.asset,Z,$):WQ(X.asset,Z,$),body:X.asset.bytes}),O=await L(F,"video upload");if(String(O?.status||"")!=="ok")throw new K(`Instagram private publish video upload failed for ${X.asset.fileName}`);const G=await E(Q,`https://i.instagram.com/rupload_igphoto/fb_uploader_${Z}`,{method:"POST",headers:HQ(X.asset,Z,$),body:X.asset.coverImage.bytes}),N=await L(G,"video cover upload");if(String(N?.status||"")!=="ok")throw new K(`Instagram private publish video cover upload failed for ${X.asset.fileName}`)}async function VQ(Q){const X=Q.waitMs??r,Z={method:"POST",headers:{..._(Q.apiContext),"Content-Type":"application/json"},body:JSON.stringify(Q.payload)};for(let $=0;$<w;$+=1){let q,F;try{q=await Q.fetcher("https://www.instagram.com/api/v1/media/configure_sidecar/",Z);F=await q.text()}catch(N){throw markPublishOutcomeUncertain(N instanceof Error?N:new K(`Instagram private publish configure_sidecar request failed: ${String(N)}`))}let O={};try{O=F?JSON.parse(F):{}}catch{throw markPublishOutcomeUncertain(new K("Instagram private publish configure_sidecar returned invalid JSON"))}if(!q.ok){const N=F?` ${F.slice(0,500)}`:"";throw markPublishOutcomeUncertain(new K(`Instagram private publish configure_sidecar failed: ${q.status}${N}`))}const G=String(O?.message||"");if(q.status===202||/transcode not finished yet/i.test(G)){if($>=w-1)throw markPublishOutcomeUncertain(new K("Instagram private publish configure_sidecar timed out waiting for video transcode",F.slice(0,500)));await X(d);continue}if(String(O?.status||"").toLowerCase()==="fail")throw new K("Instagram private publish configure_sidecar failed",G||F.slice(0,500));return{code:O?.media?.code}}throw new K("Instagram private publish configure_sidecar failed")}export async function publishMediaViaPrivateApi(Q){const X=Q.now??(()=>Date.now()),Z=String(X()),$=Q.mediaItems.length>1?Q.mediaItems.map((G,N)=>String(X()+N+1)):[String(X())],q=Q.fetcher??((G,N)=>j(Q.page,G,N)),F=Q.prepareMediaAsset??JQ,O=await Promise.all(Q.mediaItems.map((G)=>F(G)));try{for(let N=0;N<O.length;N+=1){const J=O[N],W=$[N];await c(q,J,W,Q.apiContext)}if($.length===1){if(O[0]?.type!=="image")throw new K("Instagram private publish only supports single-video uploads through instagram reel");let N;try{const J=await q("https://www.instagram.com/api/v1/media/configure/",{method:"POST",headers:{..._(Q.apiContext),"Content-Type":"application/x-www-form-urlencoded"},body:buildConfigureBody({uploadId:$[0],caption:Q.caption,jazoest:Q.jazoest})});N=await L(J,"configure")}catch(J){throw markPublishOutcomeUncertain(J instanceof Error?J:new K(`Instagram private publish configure request failed: ${String(J)}`))}return{code:N?.media?.code,uploadIds:$}}return{code:(await VQ({fetcher:q,payload:buildConfigureSidecarPayload({uploadIds:$,caption:Q.caption,clientSidecarId:Z,jazoest:Q.jazoest}),apiContext:Q.apiContext,waitMs:Q.waitMs})).code,uploadIds:$}}finally{f(O)}}export async function publishImagesViaPrivateApi(Q){return publishMediaViaPrivateApi({page:Q.page,mediaItems:Q.imagePaths.map((X)=>({type:"image",filePath:X})),caption:Q.caption,apiContext:Q.apiContext,jazoest:Q.jazoest,now:Q.now,fetcher:Q.fetcher,waitMs:Q.waitMs,prepareMediaAsset:Q.prepareAsset?async(X)=>({type:"image",asset:await Q.prepareAsset(X.filePath)}):void 0})}export async function publishStoryViaPrivateApi(Q){const X=Q.now??(()=>Date.now()),Z=String(X()),$=Q.fetcher??((W,H)=>j(Q.page,W,H)),F=await(Q.prepareMediaAsset??(async(W)=>W.type==="video"?{type:"video",asset:NQ(W.filePath)}:{type:"image",asset:prepareImageAssetForPrivateStoryUpload(W.filePath)}))(Q.mediaItem),O=Q.currentUserId||("getCookies"in Q.page?String((await(Q.page.getCookies?.({domain:"instagram.com"})??Promise.resolve([]))).find((W)=>W.name==="ds_user_id")?.value||""):"");if(!O)throw new K("Instagram story publish could not derive current user id from browser session");const G={_csrftoken:Q.apiContext.csrfToken,_uid:O,_uuid:B.randomUUID(),device:p},N=(W,H)=>b({...buildConfigureToStoryPhotoPayload({uploadId:Z,width:W,height:H,now:X,jazoest:Q.jazoest}),...G}),J=(W,H,Y)=>b({...buildConfigureToStoryVideoPayload({uploadId:Z,width:W,height:H,durationMs:Y,now:X,jazoest:Q.jazoest}),...G});try{await c($,F,Z,Q.apiContext,"story");if(F.type==="image"){let H;try{const Y=await $("https://i.instagram.com/api/v1/media/configure_to_story/",{method:"POST",headers:{..._(Q.apiContext),"Content-Type":"application/x-www-form-urlencoded"},body:N(F.asset.width,F.asset.height)});H=await L(Y,"configure_to_story")}catch(Y){throw markPublishOutcomeUncertain(Y instanceof Error?Y:new K(`Instagram private publish configure_to_story request failed: ${String(Y)}`))}return{mediaPk:String(H?.media?.pk||H?.media?.id||"").split("_")[0]||void 0,uploadId:Z}}let W;try{await L(await $("https://i.instagram.com/api/v1/media/configure_to_story/",{method:"POST",headers:{..._(Q.apiContext),"Content-Type":"application/x-www-form-urlencoded"},body:N(F.asset.width,F.asset.height)}),"configure_to_story cover");const H=await $("https://i.instagram.com/api/v1/media/configure_to_story/?video=1",{method:"POST",headers:{..._(Q.apiContext),"Content-Type":"application/x-www-form-urlencoded"},body:J(F.asset.width,F.asset.height,F.asset.durationMs)});W=await L(H,"configure_to_story")}catch(H){throw markPublishOutcomeUncertain(H instanceof Error?H:new K(`Instagram private publish configure_to_story request failed: ${String(H)}`))}return{mediaPk:String(W?.media?.pk||W?.media?.id||"").split("_")[0]||void 0,uploadId:Z}}finally{f([F])}}
@@ -1,4 +1,4 @@
1
- import*as w from"node:fs";import*as W from"node:path";import{cli as s,Strategy as n}from"@jackwener/opencli/registry";import{ArgumentError as V,AuthRequiredError as R,CommandExecutionError as Y}from"@jackwener/opencli/errors";import{installInstagramProtocolCapture as u,readInstagramProtocolCapture as i}from"./_shared/protocol-capture.js";import{publishMediaViaPrivateApi as r,publishImagesViaPrivateApi as p,resolveInstagramPrivatePublishConfig as a}from"./_shared/private-publish.js";import{resolveInstagramRuntimeInfo as t}from"./_shared/runtime-info.js";import{throwIfFileAccessDenied as e}from"../_shared/video-publish.js";const z="https://www.instagram.com/",jj=new Set([".jpg",".jpeg",".png",".webp"]),Gj=new Set([".mp4"]),C=10,Nj="/tmp/instagram_post_protocol_trace.json";async function b(j,G=!1){if(G){await j.goto(`${z}?__opencli_reset=${Date.now()}`);await j.wait({time:1})}await j.goto(z)}export function buildEnsureComposerOpenJs(){return`
1
+ import*as b from"node:fs";import*as W from"node:path";import{cli as r,Strategy as p}from"@jackwener/opencli/registry";import{ArgumentError as z,AuthRequiredError as R,CommandExecutionError as Y}from"@jackwener/opencli/errors";import{installInstagramProtocolCapture as a,readInstagramProtocolCapture as t}from"./_shared/protocol-capture.js";import{publishMediaViaPrivateApi as e,publishImagesViaPrivateApi as jj,resolveInstagramPrivatePublishConfig as Gj,isPublishOutcomeUncertain as Nj}from"./_shared/private-publish.js";import{resolveInstagramRuntimeInfo as Oj}from"./_shared/runtime-info.js";import{throwIfFileAccessDenied as Qj}from"../_shared/video-publish.js";const K="https://www.instagram.com/",Xj=new Set([".jpg",".jpeg",".png",".webp"]),Yj=new Set([".mp4"]),C=10,Zj="/tmp/instagram_post_protocol_trace.json";async function k(j,G=!1){if(G){await j.goto(`${K}?__opencli_reset=${Date.now()}`);await j.wait({time:1})}await j.goto(K)}export function buildEnsureComposerOpenJs(){return`
2
2
  (() => {
3
3
  const path = window.location?.pathname || '';
4
4
  const onLoginRoute = /\\/accounts\\/login\\/?/.test(path);
@@ -61,7 +61,7 @@ import*as w from"node:fs";import*as W from"node:path";import{cli as s,Strategy a
61
61
  const settled = !shared && !composerOpen && !/sharing/.test(visibleText);
62
62
  return { ok: shared, failed, settled, url: /\\/p\\//.test(url) ? url : '' };
63
63
  })()
64
- `}function Oj(j){if(!j)throw new Y("Browser session required for instagram post");return j}function Qj(j){if(!j.length)throw new V('Argument "media" is required.',"Provide --media /path/to/file.jpg or --media /path/a.jpg,/path/b.mp4");if(j.length>C)throw new V(`Too many media items: ${j.length}`,`Instagram carousel posts support at most ${C} items`);return j.map((N)=>{const O=W.resolve(String(N||"").trim());if(!O)throw new V("Media path cannot be empty");if(!w.existsSync(O))throw new V(`Media file not found: ${O}`);const Q=W.extname(O).toLowerCase();if(jj.has(Q))return{type:"image",filePath:O};if(Gj.has(Q))return{type:"video",filePath:O};throw new V(`Unsupported media format: ${Q}`,"Supported formats: images (.jpg, .jpeg, .png, .webp) and videos (.mp4)")})}function Xj(j){const G=String(j.media??"").trim();return Qj(G.split(",").map((N)=>N.trim()).filter(Boolean))}function Yj(j){if(j.media===void 0)throw new V('Argument "media" is required.',"Provide --media /path/to/file.jpg or --media /path/a.jpg,/path/b.mp4")}function Zj(j){if(!(j instanceof Y))return!1;return j.message.startsWith("Instagram private publish")||j.message.startsWith("Instagram private route")}function f(j,G){return[{status:"✅ Posted",detail:Vj(j),url:G}]}function _j(j,G){const N=j instanceof Error?j.message:String(j),O=G instanceof Error?G.message:String(G);return`Private route failed first: ${N}. UI fallback then failed: ${O}`}async function $j(j){const G=await a(j.page),N=j.mediaItems.every((Q)=>Q.type==="image")?await p({page:j.page,imagePaths:j.mediaItems.map((Q)=>Q.filePath),caption:j.content,apiContext:G.apiContext,jazoest:G.jazoest}):await r({page:j.page,mediaItems:j.mediaItems,caption:j.content,apiContext:G.apiContext,jazoest:G.jazoest}),O=N.code?new URL(`/p/${N.code}/`,z).toString():await g(j.page,j.existingPostPaths);return f(j.mediaItems,O)}async function qj(j){let G,N=null;for(let O=0;O<j.commandAttemptBudget;O++){let Q=!1;try{await b(j.page,j.forceFreshStart||O>0);await j.installProtocolCapture();await j.page.wait({time:2});await A(j.page);await x(j.page);const X=await h(j.page,j.mediaItems);if(j.preUploadDelaySeconds>0)await j.page.wait({time:j.preUploadDelaySeconds});let Z=!1,_=null;for(const q of X){let J=q;for(let B=0;B<j.uploadAttemptBudget;B++){await Lj(j.page,j.mediaItems,J);const K=await P(j.page,j.previewProbeWindowSeconds);if(K.state==="preview"){Z=!0;break}if(K.state==="failed"){_=F(K.detail);for(let T=0;T<j.inlineUploadRetryBudget;T++){if(!await Rj(j.page))break;await j.page.wait({time:3});const D=await P(j.page,Math.max(3,Math.floor(j.previewProbeWindowSeconds/2)));if(D.state==="preview"){Z=!0;break}if(D.state!=="failed")break}if(Z)break;await Wj(j.page);await A(j.page);if(B<j.uploadAttemptBudget-1){try{await j.drainProtocolCapture();await b(j.page,!0);await j.installProtocolCapture();await j.page.wait({time:2});await A(j.page);await x(j.page);J=await E(j.page,J,j.mediaItems);if(j.preUploadDelaySeconds>0)await j.page.wait({time:j.preUploadDelaySeconds})}catch{throw _}await j.page.wait({time:1.5});continue}break}break}if(Z)break}if(!Z){if(_)throw _;await xj(j.page,j.finalPreviewWaitSeconds)}try{await wj(j.page)}catch(q){await Cj(j.page,q)}if(j.content){await kj(j.page,j.content);await fj(j.page,j.content)}if(j.preShareDelaySeconds>0)await j.page.wait({time:j.preShareDelaySeconds});await v(j.page,["Share","分享"],"caption");Q=!0;let $="";try{$=await c(j.page)}catch(q){if(q instanceof Y&&q.message==="Instagram post share failed"&&await yj(j.page)){await j.page.wait({time:Math.max(2,j.preShareDelaySeconds)});$=await c(j.page)}else throw q}await j.drainProtocolCapture();if(!$)$=await g(j.page,j.existingPostPaths);return f(j.mediaItems,$)}catch(X){G=X;if(X instanceof Y&&X.message!=="Failed to open Instagram post composer")N=X;if(X instanceof R)throw X;if(Q)throw X;if(!(X instanceof Y)||O===j.commandAttemptBudget-1){if(X instanceof Y&&X.message==="Failed to open Instagram post composer"&&N)throw N;throw X}let Z=!1;if(j.mediaItems.length>=10&&j.page.closeWindow)try{await j.drainProtocolCapture();await j.page.closeWindow();Z=!0}catch{}if(!Z){await A(j.page);await j.page.wait({time:1})}}}throw G instanceof Error?G:new Y("Instagram post failed")}async function x(j){const G=await j.evaluate(buildEnsureComposerOpenJs());if(!G?.ok){if(G?.reason==="auth")throw new R("www.instagram.com","Instagram login required before posting");throw new Y("Failed to open Instagram post composer")}}async function A(j){for(let G=0;G<4;G++){if(!(await j.evaluate(`
64
+ `}function _j(j){if(!j)throw new Y("Browser session required for instagram post");return j}function $j(j){if(!j.length)throw new z('Argument "media" is required.',"Provide --media /path/to/file.jpg or --media /path/a.jpg,/path/b.mp4");if(j.length>C)throw new z(`Too many media items: ${j.length}`,`Instagram carousel posts support at most ${C} items`);return j.map((N)=>{const O=W.resolve(String(N||"").trim());if(!O)throw new z("Media path cannot be empty");if(!b.existsSync(O))throw new z(`Media file not found: ${O}`);const Q=W.extname(O).toLowerCase();if(Xj.has(Q))return{type:"image",filePath:O};if(Yj.has(Q))return{type:"video",filePath:O};throw new z(`Unsupported media format: ${Q}`,"Supported formats: images (.jpg, .jpeg, .png, .webp) and videos (.mp4)")})}function qj(j){const G=String(j.media??"").trim();return $j(G.split(",").map((N)=>N.trim()).filter(Boolean))}function Hj(j){if(j.media===void 0)throw new z('Argument "media" is required.',"Provide --media /path/to/file.jpg or --media /path/a.jpg,/path/b.mp4")}function Jj(j){if(!(j instanceof Y))return!1;return j.message.startsWith("Instagram private publish")||j.message.startsWith("Instagram private route")}function x(j,G){return[{status:"✅ Posted",detail:Mj(j),url:G}]}function Tj(j,G){const N=j instanceof Error?j.message:String(j),O=G instanceof Error?G.message:String(G);return`Private route failed first: ${N}. UI fallback then failed: ${O}`}async function Vj(j){const G=await Gj(j.page),N=j.mediaItems.every((Q)=>Q.type==="image")?await jj({page:j.page,imagePaths:j.mediaItems.map((Q)=>Q.filePath),caption:j.content,apiContext:G.apiContext,jazoest:G.jazoest}):await e({page:j.page,mediaItems:j.mediaItems,caption:j.content,apiContext:G.apiContext,jazoest:G.jazoest}),O=N.code?new URL(`/p/${N.code}/`,K).toString():j.canDiffProfile?await w(j.page,j.existingPostPaths):"";return x(j.mediaItems,O)}async function zj(j){let G,N=null;for(let O=0;O<j.commandAttemptBudget;O++){let Q=!1;try{await k(j.page,j.forceFreshStart||O>0);await j.installProtocolCapture();await j.page.wait({time:2});await A(j.page);await y(j.page);const X=await v(j.page,j.mediaItems);if(j.preUploadDelaySeconds>0)await j.page.wait({time:j.preUploadDelaySeconds});let _=!1,Z=null;for(const q of X){let T=q;for(let L=0;L<j.uploadAttemptBudget;L++){await Aj(j.page,j.mediaItems,T);const B=await c(j.page,j.previewProbeWindowSeconds);if(B.state==="preview"){_=!0;break}if(B.state==="failed"){Z=D(B.detail);for(let F=0;F<j.inlineUploadRetryBudget;F++){if(!await Cj(j.page))break;await j.page.wait({time:3});const V=await c(j.page,Math.max(3,Math.floor(j.previewProbeWindowSeconds/2)));if(V.state==="preview"){_=!0;break}if(V.state!=="failed")break}if(_)break;await bj(j.page);await A(j.page);if(L<j.uploadAttemptBudget-1){try{await j.drainProtocolCapture();await k(j.page,!0);await j.installProtocolCapture();await j.page.wait({time:2});await A(j.page);await y(j.page);T=await I(j.page,T,j.mediaItems);if(j.preUploadDelaySeconds>0)await j.page.wait({time:j.preUploadDelaySeconds})}catch{throw Z}await j.page.wait({time:1.5});continue}break}break}if(_)break}if(!_){if(Z)throw Z;await kj(j.page,j.finalPreviewWaitSeconds)}try{await hj(j.page)}catch(q){await Ej(j.page,q)}if(j.content){await Sj(j.page,j.content);await vj(j.page,j.content)}if(j.preShareDelaySeconds>0)await j.page.wait({time:j.preShareDelaySeconds});await d(j.page,["Share","分享"],"caption");Q=!0;let $="";try{$=await g(j.page)}catch(q){if(q instanceof Y&&q.message==="Instagram post share failed"&&await Uj(j.page)){await j.page.wait({time:Math.max(2,j.preShareDelaySeconds)});$=await g(j.page)}else throw q}await j.drainProtocolCapture();if(!$&&j.canDiffProfile)$=await w(j.page,j.existingPostPaths);return x(j.mediaItems,$)}catch(X){G=X;if(X instanceof Y&&X.message!=="Failed to open Instagram post composer")N=X;if(X instanceof R)throw X;if(Q){let Z="";if(j.canDiffProfile)try{Z=await w(j.page,j.existingPostPaths)}catch{}if(Z)return x(j.mediaItems,Z);const $=X instanceof Error?X.message:String(X);throw new Y(`Instagram share was clicked but the outcome could not be confirmed: ${$}`,"The post may already be live. Do NOT rerun this command blindly — open the profile (or rerun after checking) and confirm no new post exists first; retrying on a false failure creates a duplicate post.")}if(!(X instanceof Y)||O===j.commandAttemptBudget-1){if(X instanceof Y&&X.message==="Failed to open Instagram post composer"&&N)throw N;throw X}let _=!1;if(j.mediaItems.length>=10&&j.page.closeWindow)try{await j.drainProtocolCapture();await j.page.closeWindow();_=!0}catch{}if(!_){await A(j.page);await j.page.wait({time:1})}}}throw G instanceof Error?G:new Y("Instagram post failed")}async function y(j){const G=await j.evaluate(buildEnsureComposerOpenJs());if(!G?.ok){if(G?.reason==="auth")throw new R("www.instagram.com","Instagram login required before posting");throw new Y("Failed to open Instagram post composer")}}async function A(j){for(let G=0;G<4;G++){if(!(await j.evaluate(`
65
65
  (() => {
66
66
  const isVisible = (el) => {
67
67
  if (!(el instanceof HTMLElement)) return false;
@@ -105,7 +105,7 @@ import*as w from"node:fs";import*as W from"node:path";import{cli as s,Strategy a
105
105
 
106
106
  return { ok: false };
107
107
  })()
108
- `))?.ok)return;await j.wait({time:0.5})}}async function k(j,G){const N=G.some((Q)=>Q.type==="video"),O=await j.evaluate(`
108
+ `))?.ok)return;await j.wait({time:0.5})}}async function U(j,G){const N=G.some((Q)=>Q.type==="video"),O=await j.evaluate(`
109
109
  ((includesVideo) => {
110
110
  const isVisible = (el) => {
111
111
  if (!(el instanceof HTMLElement)) return false;
@@ -165,12 +165,12 @@ import*as w from"node:fs";import*as W from"node:path";import{cli as s,Strategy a
165
165
  });
166
166
  return { ok: true, selectors };
167
167
  })(${JSON.stringify(N)})
168
- `);if(!O?.ok||!O.selectors?.length)throw new Y("Instagram upload input not found","Open the new-post composer in a logged-in browser session and retry");return O.selectors}async function h(j,G){try{return await k(j,G)}catch(N){if(!(N instanceof Y)||!N.message.includes("upload input not found"))throw N;await x(j);await j.wait({time:1.5});try{return await k(j,G)}catch(O){if(!(O instanceof Y)||!O.message.includes("upload input not found"))throw O;await b(j,!0);await j.wait({time:2});await A(j);await x(j);await j.wait({time:2});return k(j,G)}}}function Hj(j){const G=j.match(/data-opencli-ig-upload-index="(\d+)"/);if(!G)return null;const N=Number.parseInt(G[1]||"",10);return Number.isNaN(N)?null:N}async function E(j,G,N){const O=await h(j,N),Q=Hj(G);if(Q!==null&&O[Q])return O[Q];return O[0]||G}async function Jj(j,G,N){const O=G.map(($)=>{const q=W.extname($).toLowerCase(),J=q===".png"?"image/png":q===".webp"?"image/webp":"image/jpeg";return{name:W.basename($),type:J,base64:w.readFileSync($).toString("base64")}}),Q=`__opencliInstagramUpload_${Date.now()}_${Math.random().toString(36).slice(2)}`,X=262144;await j.evaluate(`
168
+ `);if(!O?.ok||!O.selectors?.length)throw new Y("Instagram upload input not found","Open the new-post composer in a logged-in browser session and retry");return O.selectors}async function v(j,G){try{return await U(j,G)}catch(N){if(!(N instanceof Y)||!N.message.includes("upload input not found"))throw N;await y(j);await j.wait({time:1.5});try{return await U(j,G)}catch(O){if(!(O instanceof Y)||!O.message.includes("upload input not found"))throw O;await k(j,!0);await j.wait({time:2});await A(j);await y(j);await j.wait({time:2});return U(j,G)}}}function Kj(j){const G=j.match(/data-opencli-ig-upload-index="(\d+)"/);if(!G)return null;const N=Number.parseInt(G[1]||"",10);return Number.isNaN(N)?null:N}async function I(j,G,N){const O=await v(j,N),Q=Kj(G);if(Q!==null&&O[Q])return O[Q];return O[0]||G}async function Lj(j,G,N){const O=G.map(($)=>{const q=W.extname($).toLowerCase(),T=q===".png"?"image/png":q===".webp"?"image/webp":"image/jpeg";return{name:W.basename($),type:T,base64:b.readFileSync($).toString("base64")}}),Q=`__opencliInstagramUpload_${Date.now()}_${Math.random().toString(36).slice(2)}`,X=262144;await j.evaluate(`
169
169
  (() => {
170
170
  window[${JSON.stringify(Q)}] = [];
171
171
  return { ok: true };
172
172
  })()
173
- `);const Z=JSON.stringify(O);for(let $=0;$<Z.length;$+=X){const q=Z.slice($,$+X);await j.evaluate(`
173
+ `);const _=JSON.stringify(O);for(let $=0;$<_.length;$+=X){const q=_.slice($,$+X);await j.evaluate(`
174
174
  (() => {
175
175
  const key = ${JSON.stringify(Q)};
176
176
  const chunk = ${JSON.stringify(q)};
@@ -179,7 +179,7 @@ import*as w from"node:fs";import*as W from"node:path";import{cli as s,Strategy a
179
179
  window[key] = parts;
180
180
  return { ok: true, count: parts.length };
181
181
  })()
182
- `)}const _=await j.evaluate(`
182
+ `)}const Z=await j.evaluate(`
183
183
  (() => {
184
184
  const selector = ${JSON.stringify(N)};
185
185
  const key = ${JSON.stringify(Q)};
@@ -212,7 +212,7 @@ import*as w from"node:fs";import*as W from"node:path";import{cli as s,Strategy a
212
212
  return { ok: false, error: String(error) };
213
213
  }
214
214
  })()
215
- `);if(!_?.ok)throw new Y(_?.error||"Instagram fallback file injection failed")}async function Tj(j,G){await j.evaluate(`
215
+ `);if(!Z?.ok)throw new Y(Z?.error||"Instagram fallback file injection failed")}async function Bj(j,G){await j.evaluate(`
216
216
  (() => {
217
217
  const input = document.querySelector(${JSON.stringify(G)});
218
218
  if (!(input instanceof HTMLInputElement)) return { ok: false };
@@ -255,7 +255,7 @@ import*as w from"node:fs";import*as W from"node:path";import{cli as s,Strategy a
255
255
  if (failed) return { state: 'failed', detail: dialogText || 'Something went wrong' };
256
256
  return { state: 'pending', detail: dialogText || '' };
257
257
  })()
258
- `}async function M(j){const G=await j.evaluate(buildInspectUploadStageJs());if(G?.state)return G;if(G?.ok===!0)return{state:"preview",detail:G.detail};return{state:"pending",detail:G?.detail}}function F(j){return new Y("Instagram image upload failed",j?`Instagram rejected the upload: ${j}`:"Instagram rejected the upload before the preview stage")}async function Lj(j,G,N){const O=G.map((X)=>X.filePath);if(!j.setFileInput)throw new Y("Instagram posting requires Browser Bridge file upload support","Use Browser Bridge or another browser mode that supports setFileInput");let Q=N;for(let X=0;X<2;X++)try{await j.setFileInput(O,Q);await Tj(j,Q);return}catch(Z){const _=Z instanceof Error?Z.message:String(Z);if((_.includes("No element found matching selector")||_.includes("Could not find node with given id")||_.includes("No node with given id found"))&&X===0){Q=await E(j,Q,G);continue}if(!_.includes("Unknown action")&&!_.includes("set-file-input")&&!_.includes("not supported")&&!_.includes("Not allowed"))throw Z;if(G.some((q)=>q.type==="video")){e(Z);throw new Y("Instagram mixed-media posting requires Browser Bridge file upload support","Use Browser Bridge or another browser mode that supports setFileInput for image/video uploads")}await Jj(j,O,Q);return}}function Vj(j){if(j.every((G)=>G.type==="image"))return j.length===1?"Single image post shared successfully":`${j.length}-image carousel post shared successfully`;return j.length===1?"Single mixed-media post shared successfully":`${j.length}-item mixed-media carousel post shared successfully`}function zj(j){if(j.length>=10)return 6;if(j.length>=5)return 4;return 3}function Bj(j){if(j.length>=10)return 3;if(j.length>=5)return 1.5;return 0}function Kj(j){if(j.length>=10)return 3;if(j.length>=5)return 3;return 2}function Dj(j){if(j.length>=10)return 6;if(j.length>=5)return 6;return 4}function Aj(j){if(j.length>=10)return 12;if(j.length>=5)return 16;return 12}function Mj(j){if(j.length>=10)return 4;if(j.length>=5)return 3;return 0}function Fj(j){if(j.length>=10)return 3;if(j.length>=5)return 2;return 1}async function Wj(j){return!!(await j.evaluate(`
258
+ `}async function M(j){const G=await j.evaluate(buildInspectUploadStageJs());if(G?.state)return G;if(G?.ok===!0)return{state:"preview",detail:G.detail};return{state:"pending",detail:G?.detail}}function D(j){return new Y("Instagram image upload failed",j?`Instagram rejected the upload: ${j}`:"Instagram rejected the upload before the preview stage")}async function Aj(j,G,N){const O=G.map((X)=>X.filePath);if(!j.setFileInput)throw new Y("Instagram posting requires Browser Bridge file upload support","Use Browser Bridge or another browser mode that supports setFileInput");let Q=N;for(let X=0;X<2;X++)try{await j.setFileInput(O,Q);await Bj(j,Q);return}catch(_){const Z=_ instanceof Error?_.message:String(_);if((Z.includes("No element found matching selector")||Z.includes("Could not find node with given id")||Z.includes("No node with given id found"))&&X===0){Q=await I(j,Q,G);continue}if(!Z.includes("Unknown action")&&!Z.includes("set-file-input")&&!Z.includes("not supported")&&!Z.includes("Not allowed"))throw _;if(G.some((q)=>q.type==="video")){Qj(_);throw new Y("Instagram mixed-media posting requires Browser Bridge file upload support","Use Browser Bridge or another browser mode that supports setFileInput for image/video uploads")}await Lj(j,O,Q);return}}function Mj(j){if(j.every((G)=>G.type==="image"))return j.length===1?"Single image post shared successfully":`${j.length}-image carousel post shared successfully`;return j.length===1?"Single mixed-media post shared successfully":`${j.length}-item mixed-media carousel post shared successfully`}function Dj(j){if(j.length>=10)return 6;if(j.length>=5)return 4;return 3}function Fj(j){if(j.length>=10)return 3;if(j.length>=5)return 1.5;return 0}function Wj(j){if(j.length>=10)return 3;if(j.length>=5)return 3;return 2}function Rj(j){if(j.length>=10)return 6;if(j.length>=5)return 6;return 4}function xj(j){if(j.length>=10)return 12;if(j.length>=5)return 16;return 12}function yj(j){if(j.length>=10)return 4;if(j.length>=5)return 3;return 0}function wj(j){if(j.length>=10)return 3;if(j.length>=5)return 2;return 1}async function bj(j){return!!(await j.evaluate(`
259
259
  (() => {
260
260
  const isVisible = (el) => {
261
261
  if (!(el instanceof HTMLElement)) return false;
@@ -278,7 +278,7 @@ import*as w from"node:fs";import*as W from"node:path";import{cli as s,Strategy a
278
278
  }
279
279
  return { ok: false };
280
280
  })()
281
- `))?.ok}async function Rj(j){return!!(await j.evaluate(`
281
+ `))?.ok}async function Cj(j){return!!(await j.evaluate(`
282
282
  (() => {
283
283
  const isVisible = (el) => {
284
284
  if (!(el instanceof HTMLElement)) return false;
@@ -312,7 +312,7 @@ import*as w from"node:fs";import*as W from"node:path";import{cli as s,Strategy a
312
312
  }
313
313
  return { ok: false };
314
314
  })()
315
- `))?.ok}async function xj(j,G=12){const N=Math.max(1,Math.ceil(G));for(let O=0;O<N;O++){const Q=await M(j);if(Q.state==="preview")return;if(Q.state==="failed"){await j.screenshot({path:"/tmp/instagram_post_preview_debug.png"});throw F("Inspect /tmp/instagram_post_preview_debug.png. "+(Q.detail||""))}if(O<N-1)await j.wait({time:1})}await j.screenshot({path:"/tmp/instagram_post_preview_debug.png"});throw new Y("Instagram image preview did not appear after upload","The selected file input may not match the active composer; inspect /tmp/instagram_post_preview_debug.png")}async function P(j,G=4){const N=Math.max(1,Math.ceil(G*2));for(let O=0;O<N;O++){const Q=await M(j);if(Q.state!=="pending")return Q;if(O<N-1)await j.wait({time:0.5})}return{state:"pending"}}export function buildClickActionJs(j,G="any"){return`
315
+ `))?.ok}async function kj(j,G=12){const N=Math.max(1,Math.ceil(G));for(let O=0;O<N;O++){const Q=await M(j);if(Q.state==="preview")return;if(Q.state==="failed"){await j.screenshot({path:"/tmp/instagram_post_preview_debug.png"});throw D("Inspect /tmp/instagram_post_preview_debug.png. "+(Q.detail||""))}if(O<N-1)await j.wait({time:1})}await j.screenshot({path:"/tmp/instagram_post_preview_debug.png"});throw new Y("Instagram image preview did not appear after upload","The selected file input may not match the active composer; inspect /tmp/instagram_post_preview_debug.png")}async function c(j,G=4){const N=Math.max(1,Math.ceil(G*2));for(let O=0;O<N;O++){const Q=await M(j);if(Q.state!=="pending")return Q;if(O<N-1)await j.wait({time:0.5})}return{state:"pending"}}export function buildClickActionJs(j,G="any"){return`
316
316
  ((labels, scope) => {
317
317
  const isVisible = (el) => {
318
318
  if (!(el instanceof HTMLElement)) return false;
@@ -367,7 +367,7 @@ import*as w from"node:fs";import*as W from"node:path";import{cli as s,Strategy a
367
367
  }
368
368
  return { ok: false };
369
369
  })(${JSON.stringify(j)}, ${JSON.stringify(G)})
370
- `}async function v(j,G,N="any"){const O=await j.evaluate(buildClickActionJs(G,N));if(!O?.ok)throw new Y(`Instagram action button not found: ${G.join(" / ")}`);return O.label||G[0]}async function yj(j){return!!(await j.evaluate(`
370
+ `}async function d(j,G,N="any"){const O=await j.evaluate(buildClickActionJs(G,N));if(!O?.ok)throw new Y(`Instagram action button not found: ${G.join(" / ")}`);return O.label||G[0]}async function Uj(j){return!!(await j.evaluate(`
371
371
  (() => {
372
372
  const isVisible = (el) => {
373
373
  if (!(el instanceof HTMLElement)) return false;
@@ -405,12 +405,12 @@ import*as w from"node:fs";import*as W from"node:path";import{cli as s,Strategy a
405
405
 
406
406
  return { ok: false };
407
407
  })()
408
- `))?.ok}async function S(j){return!!(await j.evaluate(`
408
+ `))?.ok}async function l(j){return!!(await j.evaluate(`
409
409
  (() => {
410
410
  const editable = document.querySelector('textarea, [contenteditable="true"]');
411
411
  return { ok: !!editable };
412
412
  })()
413
- `))?.ok}async function I(j){return!!(await j.evaluate(`
413
+ `))?.ok}async function m(j){return!!(await j.evaluate(`
414
414
  (() => {
415
415
  const editable = document.querySelector('textarea, [contenteditable="true"]');
416
416
  const dialogText = Array.from(document.querySelectorAll('[role="dialog"]'))
@@ -424,7 +424,7 @@ import*as w from"node:fs";import*as W from"node:path";import{cli as s,Strategy a
424
424
  || dialogText.includes('advanced settings'),
425
425
  };
426
426
  })()
427
- `))?.ok}async function wj(j){for(let G=0;G<3;G++){if(await I(j))return;try{await v(j,["Next","下一步"],"media")}catch(O){if(O instanceof Y){await j.wait({time:1.5});if(await I(j))return;const Q=await M(j);if(Q.state==="failed")throw F(Q.detail);if(G<2)continue}throw O}await j.wait({time:1.5});if(await S(j))return;const N=await M(j);if(N.state==="failed")throw F(N.detail)}await j.screenshot({path:"/tmp/instagram_post_caption_debug.png"});throw new Y("Instagram caption editor did not appear","Instagram may have changed the publish flow; inspect /tmp/instagram_post_caption_debug.png")}async function dj(j){if(!await S(j)){await j.screenshot({path:"/tmp/instagram_post_caption_debug.png"});throw new Y("Instagram caption editor did not appear","Instagram may have changed the publish flow; inspect /tmp/instagram_post_caption_debug.png")}}async function Cj(j,G){const N=await M(j);if(N.state==="failed")throw F(N.detail);throw G}async function bj(j){return!!(await j.evaluate(`
427
+ `))?.ok}async function hj(j){for(let G=0;G<3;G++){if(await m(j))return;try{await d(j,["Next","下一步"],"media")}catch(O){if(O instanceof Y){await j.wait({time:1.5});if(await m(j))return;const Q=await M(j);if(Q.state==="failed")throw D(Q.detail);if(G<2)continue}throw O}await j.wait({time:1.5});if(await l(j))return;const N=await M(j);if(N.state==="failed")throw D(N.detail)}await j.screenshot({path:"/tmp/instagram_post_caption_debug.png"});throw new Y("Instagram caption editor did not appear","Instagram may have changed the publish flow; inspect /tmp/instagram_post_caption_debug.png")}async function sj(j){if(!await l(j)){await j.screenshot({path:"/tmp/instagram_post_caption_debug.png"});throw new Y("Instagram caption editor did not appear","Instagram may have changed the publish flow; inspect /tmp/instagram_post_caption_debug.png")}}async function Ej(j,G){const N=await M(j);if(N.state==="failed")throw D(N.detail);throw G}async function fj(j){return!!(await j.evaluate(`
428
428
  (() => {
429
429
  const textarea = document.querySelector('[aria-label="Write a caption..."], textarea');
430
430
  if (textarea instanceof HTMLTextAreaElement) {
@@ -484,7 +484,7 @@ import*as w from"node:fs";import*as W from"node:path";import{cli as s,Strategy a
484
484
 
485
485
  return { ok: true, kind: 'contenteditable' };
486
486
  })()
487
- `))?.ok}async function kj(j,G){if(j.insertText&&await bj(j))try{await j.insertText(G);await j.wait({time:0.3});await j.evaluate(`
487
+ `))?.ok}async function Sj(j,G){if(j.insertText&&await fj(j))try{await j.insertText(G);await j.wait({time:0.3});await j.evaluate(`
488
488
  (() => {
489
489
  const textarea = document.querySelector('[aria-label="Write a caption..."], textarea');
490
490
  if (textarea instanceof HTMLTextAreaElement) {
@@ -596,7 +596,7 @@ import*as w from"node:fs";import*as W from"node:path";import{cli as s,Strategy a
596
596
 
597
597
  return { ok: false };
598
598
  })(${JSON.stringify(G)})
599
- `))?.ok)throw new Y("Failed to fill Instagram caption")}async function Uj(j,G){return!!(await j.evaluate(`
599
+ `))?.ok)throw new Y("Failed to fill Instagram caption")}async function Pj(j,G){return!!(await j.evaluate(`
600
600
  ((content) => {
601
601
  const normalized = content.trim();
602
602
  const readLexicalText = (node) => {
@@ -650,7 +650,7 @@ import*as w from"node:fs";import*as W from"node:path";import{cli as s,Strategy a
650
650
 
651
651
  return { ok: false };
652
652
  })(${JSON.stringify(G)})
653
- `))?.ok}async function fj(j,G){for(let N=0;N<6;N++){if(await Uj(j,G))return;if(N<5)await j.wait({time:0.5})}await j.screenshot({path:"/tmp/instagram_post_caption_fill_debug.png"});throw new Y("Instagram caption did not stick before sharing","Inspect /tmp/instagram_post_caption_fill_debug.png for the caption editor state")}async function c(j){let G=0;for(let N=0;N<90;N++){const O=await j.evaluate(buildPublishStatusProbeJs());if(O?.failed){await j.screenshot({path:"/tmp/instagram_post_share_debug.png"});throw new Y("Instagram post share failed","Inspect /tmp/instagram_post_share_debug.png for the share failure state")}if(O?.ok)return O.url||"";if(O?.settled){G+=1;if(G>=3)return""}else G=0;if(N<89)await j.wait({time:1})}await j.screenshot({path:"/tmp/instagram_post_share_debug.png"});throw new Y("Instagram post share confirmation did not appear","Inspect /tmp/instagram_post_share_debug.png for the final publish state")}async function d(j){return(await j.getCookies({domain:"instagram.com"})).find((N)=>N.name==="ds_user_id")?.value||""}async function l(j,G=""){if(G){const O=await t(j),Q=await j.evaluate(`
653
+ `))?.ok}async function vj(j,G){for(let N=0;N<6;N++){if(await Pj(j,G))return;if(N<5)await j.wait({time:0.5})}await j.screenshot({path:"/tmp/instagram_post_caption_fill_debug.png"});throw new Y("Instagram caption did not stick before sharing","Inspect /tmp/instagram_post_caption_fill_debug.png for the caption editor state")}async function g(j){let G=0;for(let N=0;N<90;N++){const O=await j.evaluate(buildPublishStatusProbeJs());if(O?.failed){await j.screenshot({path:"/tmp/instagram_post_share_debug.png"});throw new Y("Instagram post share failed","Inspect /tmp/instagram_post_share_debug.png for the share failure state")}if(O?.ok)return O.url||"";if(O?.settled){G+=1;if(G>=3)return""}else G=0;if(N<89)await j.wait({time:1})}await j.screenshot({path:"/tmp/instagram_post_share_debug.png"});throw new Y("Instagram post share confirmation did not appear","Inspect /tmp/instagram_post_share_debug.png for the final publish state")}async function o(j){return(await j.getCookies({domain:"instagram.com"})).find((N)=>N.name==="ds_user_id")?.value||""}async function s(j,G=""){if(G){const O=await Oj(j),Q=await j.evaluate(`
654
654
  (async () => {
655
655
  const userId = ${JSON.stringify(G)};
656
656
  const appId = ${JSON.stringify(O.appId||"")};
@@ -670,7 +670,7 @@ import*as w from"node:fs";import*as W from"node:path";import{cli as s,Strategy a
670
670
  return { ok: false };
671
671
  }
672
672
  })()
673
- `);if(Q?.ok&&Q.username)return new URL(`/${Q.username}/`,z).toString()}const N=await j.evaluate(`
673
+ `);if(Q?.ok&&Q.username)return new URL(`/${Q.username}/`,K).toString()}const N=await j.evaluate(`
674
674
  (() => {
675
675
  const isVisible = (el) => {
676
676
  if (!(el instanceof HTMLElement)) return false;
@@ -695,7 +695,7 @@ import*as w from"node:fs";import*as W from"node:path";import{cli as s,Strategy a
695
695
  const path = explicitProfile;
696
696
  return { ok: !!path, path };
697
697
  })()
698
- `);if(!N?.ok||!N.path)return"";return new URL(N.path,z).toString()}async function m(j){const G=await j.evaluate(`
698
+ `);if(!N?.ok||!N.path)return"";return new URL(N.path,K).toString()}async function n(j){const G=await j.evaluate(`
699
699
  (() => {
700
700
  const isVisible = (el) => {
701
701
  if (!(el instanceof HTMLElement)) return false;
@@ -715,4 +715,4 @@ import*as w from"node:fs";import*as W from"node:path";import{cli as s,Strategy a
715
715
 
716
716
  return { ok: hrefs.length > 0, hrefs };
717
717
  })()
718
- `);return Array.isArray(G?.hrefs)?G.hrefs.filter(Boolean):[]}async function hj(j){const G=await d(j);if(!G)return new Set;const N=await l(j,G);if(!N)return new Set;try{await j.goto(N);await j.wait({time:3});return new Set(await m(j))}catch{return new Set}}async function g(j,G){const N=await j.getCurrentUrl?.();if(N&&/\/p\//.test(N))return N;const O=await d(j),Q=await l(j,O);if(!Q)return"";await j.goto(Q);await j.wait({time:4});for(let X=0;X<8;X++){const _=(await m(j)).find(($)=>!G.has($))||"";if(_)return new URL(_,z).toString();if(X<7)await j.wait({time:1})}return""}s({site:"instagram",name:"post",access:"write",description:"Post an Instagram feed image or mixed-media carousel",domain:"www.instagram.com",strategy:n.UI,browser:!0,args:[{name:"media",required:!1,valueRequired:!0,help:`Comma-separated media paths (images/videos, up to ${C})`},{name:"content",positional:!0,required:!1,help:"Caption text"},{name:"timeout",type:"int",required:!1,default:300,help:"Max seconds for the overall command (default: 300)"}],columns:["status","detail","url"],validateArgs:Yj,func:async(j,G)=>{const N=Oj(j),O=Xj(G),Q=String(G.content??"").trim(),X=await hj(N),Z=zj(O),_=Bj(O),$=Kj(O),q=Dj(O),J=Aj(O),B=Mj(O),K=Fj(O),T=process.env.OPENCLI_INSTAGRAM_CAPTURE==="1",y=[],D=[],o=async()=>{if(!T)return;await u(N)},U=async()=>{if(!T)return;const H=await i(N);if(H.data.length)y.push(...H.data);if(H.errors.length)D.push(...H.errors)};try{try{return await $j({page:N,mediaItems:O,content:Q,existingPostPaths:X})}catch(H){if(H instanceof R||!Zj(H))throw H;try{return await qj({page:N,mediaItems:O,content:Q,existingPostPaths:X,commandAttemptBudget:Z,preUploadDelaySeconds:_,uploadAttemptBudget:$,previewProbeWindowSeconds:q,finalPreviewWaitSeconds:J,preShareDelaySeconds:B,inlineUploadRetryBudget:K,installProtocolCapture:o,drainProtocolCapture:U,forceFreshStart:!0})}catch(L){if(L instanceof R)throw L;if(L instanceof Y)throw new Y(L.message,_j(H,L));throw L}}}finally{if(T){try{await U()}catch{}w.writeFileSync(Nj,JSON.stringify({data:y,errors:D},null,2))}}}});
718
+ `);return Array.isArray(G?.hrefs)?G.hrefs.filter(Boolean):[]}async function Ij(j){const G=await o(j);if(!G)return null;const N=await s(j,G);if(!N)return null;try{await j.goto(N);await j.wait({time:3});return new Set(await n(j))}catch{return null}}async function w(j,G){const N=await j.getCurrentUrl?.();if(N&&/\/p\//.test(N))return N;const O=await o(j),Q=await s(j,O);if(!Q)return"";await j.goto(Q);await j.wait({time:4});for(let X=0;X<8;X++){const Z=(await n(j)).find(($)=>!G.has($))||"";if(Z)return new URL(Z,K).toString();if(X<7)await j.wait({time:1})}return""}r({site:"instagram",name:"post",access:"write",description:"Post an Instagram feed image or mixed-media carousel",domain:"www.instagram.com",strategy:p.UI,browser:!0,args:[{name:"media",required:!1,valueRequired:!0,help:`Comma-separated media paths (images/videos, up to ${C})`},{name:"content",positional:!0,required:!1,help:"Caption text"},{name:"timeout",type:"int",required:!1,default:300,help:"Max seconds for the overall command (default: 300)"}],columns:["status","detail","url"],validateArgs:Hj,func:async(j,G)=>{const N=_j(j),O=qj(G),Q=String(G.content??"").trim(),X=await Ij(N),_=X!==null,Z=X??new Set,$=Dj(O),q=Fj(O),T=Wj(O),L=Rj(O),B=xj(O),F=yj(O),h=wj(O),V=process.env.OPENCLI_INSTAGRAM_CAPTURE==="1",E=[],f=[],u=async()=>{if(!V)return;await a(N)},S=async()=>{if(!V)return;const H=await t(N);if(H.data.length)E.push(...H.data);if(H.errors.length)f.push(...H.errors)};try{try{return await Vj({page:N,mediaItems:O,content:Q,existingPostPaths:Z,canDiffProfile:_})}catch(H){if(H instanceof R)throw H;if(Nj(H)){let J="",P=!1;if(_)try{J=await w(N,Z);P=!0}catch{}if(J)return x(O,J);if(!P){const i=H instanceof Error?H.message:String(H);throw new Y(`Instagram publish outcome uncertain: ${i}`,"The post may already be live. Do NOT rerun this command blindly — check the profile for a new post first; retrying on a false failure creates a duplicate post.")}}if(!Jj(H))throw H;try{return await zj({page:N,mediaItems:O,content:Q,existingPostPaths:Z,canDiffProfile:_,commandAttemptBudget:$,preUploadDelaySeconds:q,uploadAttemptBudget:T,previewProbeWindowSeconds:L,finalPreviewWaitSeconds:B,preShareDelaySeconds:F,inlineUploadRetryBudget:h,installProtocolCapture:u,drainProtocolCapture:S,forceFreshStart:!0})}catch(J){if(J instanceof R)throw J;if(J instanceof Y)throw new Y(J.message,Tj(H,J));throw J}}}finally{if(V){try{await S()}catch{}b.writeFileSync(Zj,JSON.stringify({data:E,errors:f},null,2))}}}});
@@ -0,0 +1 @@
1
+ import{ArgumentError as J}from"@jackwener/opencli/errors";import{cli as K,Strategy as Q}from"@jackwener/opencli/registry";import{HOME_URL as T,mtopRequest as V}from"./mtop.js";function F(C,D){const x=String(C??"").trim();if(!x)return 1;if(!/^\d+$/.test(x)||Number(x)<1)throw new J(`xianyu collect ${D} must be a positive integer`);return Number(x)}K({site:"xianyu",name:"collect",access:"read",description:"列出我收藏的商品(分页)",domain:"www.goofish.com",strategy:Q.COOKIE,navigateBefore:!1,browser:!0,args:[{name:"page",type:"int",default:1,help:"页码,从 1 开始"},{name:"page_size",type:"int",default:20,help:"每页条数"}],columns:["item_id","title","price","seller_nick","want_cnt","status_str"],func:async(C,D)=>{const x=F(D.page,"page"),I=F(D.page_size,"page_size");await C.goto(T);await C.wait(1);const B=await V(C,"collect",{api:"mtop.taobao.idle.web.favor.item.list",data:{pageNumber:x,pageSize:I},version:"1.0"}),G=(Array.isArray(B.items)?B.items:Array.isArray(B.itemList)?B.itemList:Array.isArray(B.list)?B.list:[]).filter((h)=>h&&typeof h==="object").map((h)=>({item_id:String(h.itemId||h.id||""),title:h.title||"",price:String(h.price||h.soldPrice||""),main_pic:h.picUrl||h.mainPic||"",seller_id:String(h.sellerId||h.userId||""),seller_nick:h.sellerNick||h.userNick||"",want_cnt:Number(h.wantCnt||0),status_str:h.itemStatusStr||""}));return G.length?G:[{item_id:"",title:"(无收藏)",price:"",seller_nick:"",want_cnt:0,status_str:""}]}});export const __test__={normalizePage:F};
@@ -0,0 +1 @@
1
+ import{cli as D,Strategy as F}from"@jackwener/opencli/registry";import{HOME_URL as G,mtopRequest as I}from"./mtop.js";D({site:"xianyu",name:"location",access:"read",description:"获取账号默认发布地址",domain:"www.goofish.com",strategy:F.COOKIE,navigateBefore:!1,browser:!0,args:[{name:"longitude",type:"float",default:121.4737,help:"经度(默认上海)"},{name:"latitude",type:"float",default:31.2304,help:"纬度(默认上海)"}],columns:["prov","city","area","poi","division_id"],func:async(h,z)=>{const B=Number(z.longitude??121.4737),C=Number(z.latitude??31.2304);await h.goto(G);await h.wait(1);const x=await I(h,"location",{api:"mtop.taobao.idle.local.poi.get",data:{longitude:B,latitude:C},version:"1.0"}),A=Array.isArray(x.commonAddresses)?x.commonAddresses:[],f=x.selectedPoi||(A.length?A[0]:null);if(!f)return[{prov:"",city:"",area:"",poi:"",division_id:""}];return[{prov:f.prov||"",city:f.city||"",area:f.area||"",poi:f.poi||"",division_id:String(f.divisionId||"")}]}});export const __test__={};
@@ -0,0 +1 @@
1
+ import{ArgumentError as P,CommandExecutionError as j}from"@jackwener/opencli/errors";import{cli as Z,Strategy as $}from"@jackwener/opencli/registry";import{HOME_URL as f,mtopRequest as W}from"./mtop.js";import{normalizeNumericId as A}from"./utils.js";function C(F,B){const G=String(F??"").trim();if(!G)return 1;if(!/^\d+$/.test(G)||Number(G)<1)throw new P(`xianyu ${B} must be a positive integer`);return Number(G)}function H(F){const B=F.cardData||{},G=B.priceInfo||{},J=B.picInfo||{},K=B.detailParams||{};return{item_id:String(B.id||K.itemId||""),title:B.title||K.title||"",price:G.price||K.soldPrice||"",status:B.itemStatus,main_pic:J.picUrl||K.picUrl||"",post_info:K.postInfo||""}}Z({site:"xianyu",name:"mine",access:"read",description:"列出当前账号在售/已发布商品(分页)",domain:"www.goofish.com",strategy:$.COOKIE,navigateBefore:!1,browser:!0,args:[{name:"page",type:"int",default:1,help:"页码,从 1 开始"},{name:"page_size",type:"int",default:20,help:"每页条数"}],columns:["item_id","title","price","status","main_pic"],func:async(F,B)=>{const G=C(B.page,"page"),J=C(B.page_size,"page_size");await F.goto(f);await F.wait(1);const K=await W(F,"item mine",{api:"mtop.idle.web.user.page.head",data:{self:!0},version:"1.0"}),Q=String((K.base||K.baseInfo||{}).kcUserId||"").trim();if(!Q)throw new j("无法解析当前账号 userId,请确认已登录闲鱼");const V=await W(F,"item mine",{api:"mtop.idle.web.xyh.item.list",data:{userId:Q,pageNumber:G,pageSize:J},version:"1.0"}),X=(Array.isArray(V.cardList)?V.cardList:Array.isArray(V.itemList)?V.itemList:[]).filter((Y)=>Y&&typeof Y==="object").map(H);return X.length?X:[{item_id:"",title:"(无在售商品)",price:"",status:"",main_pic:""}]}});Z({site:"xianyu",name:"polish",access:"write",description:"擦亮商品(刷新曝光排序,不改内容)",domain:"www.goofish.com",strategy:$.COOKIE,navigateBefore:!1,browser:!0,args:[{name:"item_id",required:!0,positional:!0,help:"商品 itemId"}],columns:["item_id","ok","already_polished"],func:async(F,B)=>{const G=A(B.item_id,"item_id","1017530128619");await F.goto(f);await F.wait(1);let J;try{J=await W(F,"item polish",{api:"mtop.taobao.idle.item.polish",data:{itemId:G},version:"1.0"})}catch(K){const Q=String(K?.message||K);if(/POLISH_AGAIN|已经擦亮/.test(Q))return[{item_id:G,ok:!0,already_polished:!0,note:"今天已擦亮过,明天再来"}];throw K}return[{item_id:G,ok:!0,already_polished:!1,data:J}]}});Z({site:"xianyu",name:"delete",access:"write",description:"下架/删除商品",domain:"www.goofish.com",strategy:$.COOKIE,navigateBefore:!1,browser:!0,args:[{name:"item_id",required:!0,positional:!0,help:"商品 itemId"}],columns:["item_id","ok"],func:async(F,B)=>{const G=A(B.item_id,"item_id","1017530128619");await F.goto(f);await F.wait(1);const J=await W(F,"item delete",{api:"com.taobao.idle.item.delete",data:{itemId:G},version:"1.1"});return[{item_id:G,ok:!0,data:J}]}});Z({site:"xianyu",name:"edit",access:"write",description:"编辑商品(标题/详情/价格/划线价/库存,按需传)",domain:"www.goofish.com",strategy:$.COOKIE,navigateBefore:!1,browser:!0,args:[{name:"item_id",required:!0,positional:!0,help:"商品 itemId"},{name:"title",help:"新标题"},{name:"desc",help:"新详情描述"},{name:"price",type:"float",help:"新价格(元)"},{name:"original_price",type:"float",help:"新划线价(元),传 0 清除"},{name:"quantity",type:"int",help:"新库存数量"}],columns:["item_id","ok"],func:async(F,B)=>{const G=A(B.item_id,"item_id","1017530128619"),J=(T)=>T!=null&&String(T).trim()!=="";if(![B.title,B.desc,B.price,B.original_price,B.quantity].some(J))throw new P("至少传一个待改字段:--title / --desc / --price / --original-price / --quantity");await F.goto(f);await F.wait(1);const K=await W(F,"item edit",{api:"mtop.idle.pc.idleitem.editDetail",data:{itemId:G},version:"1.0"});if(!K||!Object.keys(K).length)throw new j(`editDetail 返回为空:itemId=${G}(可能已下架 / 不属于当前账号 / 风控)`);const Q={...K,itemId:G};if(J(B.title)||J(B.desc)){const T={...K.itemTextDTO||{}};if(J(B.title))T.title=String(B.title);if(J(B.desc))T.desc=String(B.desc);if(T.titleDescSeparate==null)T.titleDescSeparate=!0;Q.itemTextDTO=T}if(J(B.price)||J(B.original_price)){const T={...K.itemPriceDTO||{}},X=Number(B.price),Y=Number(B.original_price);if(J(B.price)&&X>0)T.priceInCent=String(Math.round(X*100));if(J(B.original_price))if(Y>0)T.origPriceInCent=String(Math.round(Y*100));else delete T.origPriceInCent;Q.itemPriceDTO=T}if(J(B.quantity))Q.quantity=String(Number(B.quantity));if(Q.uniqueCode==null)Q.uniqueCode=String(Date.now()*1000);if(Q.sourceId==null)Q.sourceId="pcMainPublish";if(Q.bizcode==null)Q.bizcode="pcMainPublish";if(Q.publishScene==null)Q.publishScene="pcMainPublish";const V=await W(F,"item edit",{api:"mtop.idle.pc.idleitem.edit",data:Q,version:"1.0"});return[{item_id:G,ok:!0,data:V}]}});export const __test__={normalizeMyItem:H,normalizePage:C};
@@ -0,0 +1,47 @@
1
+ import{AuthRequiredError as P,CommandExecutionError as $,EmptyResultError as N,selectorError as j}from"@jackwener/opencli/errors";export const HOME_URL="https://www.goofish.com";const Q=["RGV587_ERROR","FAIL_SYS_USER_VALIDATE","哎哟喂","/punish"],V=["FAIL_SYS_SESSION_EXPIRED","FAIL_SYS_TOKEN_EXOIRED","FAIL_SYS_TOKEN_EMPTY","FAIL_SYS_ILLEGAL_ACCESS","令牌过期","NEED_LOGIN"];function X(B,z,F){return`
2
+ (async () => {
3
+ const clean = (v) => String(v ?? '').replace(/\\s+/g, ' ').trim();
4
+ const extractRetCode = (ret) => clean(Array.isArray(ret) ? ret[0] : '').split('::')[0] || '';
5
+ const waitFor = async (pred, t = 6000) => {
6
+ const s = Date.now();
7
+ while (Date.now() - s < t) { if (pred()) return true; await new Promise((r) => setTimeout(r, 150)); }
8
+ return false;
9
+ };
10
+ const bodyText = document.body?.innerText || '';
11
+ if (/请先登录|扫码登录|登录后/.test(bodyText)) return { error: 'auth-required' };
12
+ if (/验证码|安全验证|异常访问/.test(bodyText)) return { error: 'blocked' };
13
+ await waitFor(() => window.lib?.mtop?.request);
14
+ if (typeof window.lib?.mtop?.request !== 'function') return { error: 'mtop-not-ready' };
15
+ let response;
16
+ try {
17
+ response = await window.lib.mtop.request({
18
+ api: ${JSON.stringify(B)},
19
+ data: ${JSON.stringify(z)},
20
+ type: 'POST',
21
+ v: ${JSON.stringify(String(F))},
22
+ dataType: 'json',
23
+ needLogin: false,
24
+ needLoginPC: false,
25
+ sessionOption: 'AutoLoginOnly',
26
+ ecode: 0,
27
+ });
28
+ } catch (error) {
29
+ const ret = error?.ret || [];
30
+ return {
31
+ error: 'mtop-request-failed',
32
+ error_code: extractRetCode(ret),
33
+ error_message: clean(Array.isArray(ret) ? ret.join(' | ') : error?.message || error),
34
+ };
35
+ }
36
+ const retCode = extractRetCode(response?.ret || []);
37
+ if (retCode && retCode !== 'SUCCESS') {
38
+ return {
39
+ error: 'mtop-response-error',
40
+ error_code: retCode,
41
+ error_message: clean((response?.ret || []).join(' | ')),
42
+ ret: response?.ret || [],
43
+ };
44
+ }
45
+ return { ok: true, ret: response?.ret || [], data: response?.data || {} };
46
+ })()
47
+ `}function Z(B,z){if(z?.error==="auth-required")throw new P("www.goofish.com",`闲鱼 ${B} 需要已登录的浏览器会话`);if(z?.error==="blocked")throw new N(`xianyu ${B}`,"闲鱼页面被验证码 / 安全验证拦截,请人工处理后重试");if(z?.error==="mtop-not-ready")throw j("window.lib.mtop","闲鱼页面未完成初始化,无法调用 mtop 接口");const F=String(z?.error_code||""),J=String(z?.error_message||""),L=`${F} ${J}`;if(V.some((G)=>L.includes(G)))throw new P("www.goofish.com",`闲鱼 ${B} 登录态失效:${J||F}`);if(Q.some((G)=>L.includes(G)))throw new N(`xianyu ${B}`,`闲鱼 ${B} 触发风控:${J||F},请人工处理`);if(z?.error)throw new $(`闲鱼 ${B} 接口调用失败:${J||F||z.error}`)}export async function mtopRequest(B,z,{api:F,data:J,version:L="1.0"}){const G=await B.evaluate(X(F,J,L));Z(z,G);if(!G||typeof G!=="object")throw new N(`xianyu ${z}`,"闲鱼接口未返回有效数据");return G.data||{}}export function retOk(B){return Array.isArray(B)&&B.some((z)=>String(z).includes("SUCCESS"))}export const __test__={buildMtopEvaluate:X,classifyAndThrow:Z,RISK_KEYWORDS:Q,AUTH_KEYWORDS:V};
@@ -0,0 +1 @@
1
+ import{ArgumentError as M}from"@jackwener/opencli/errors";import{cli as $,Strategy as C}from"@jackwener/opencli/registry";import{HOME_URL as h,mtopRequest as f}from"./mtop.js";import{normalizeNumericId as Y}from"./utils.js";const j=["ALL","WAITING_PAY","WAITING_SEND","WAITING_RECEIVE","WAITING_RATE","SUCCESS","REFUND"];function q(x){const B=String(x||"ALL").trim().toUpperCase();if(!j.includes(B))throw new M(`xianyu order --status must be one of: ${j.join(", ")}`);return B}function L(x,B){const F=String(x??"").trim();if(!F)return 1;if(!/^\d+$/.test(F)||Number(F)<1)throw new M(`xianyu order ${B} must be a positive integer`);return Number(F)}$({site:"xianyu",name:"order",access:"read",description:"列出卖家已售订单(可按状态筛选)",domain:"www.goofish.com",strategy:C.COOKIE,navigateBefore:!1,browser:!0,args:[{name:"page",type:"int",default:1,help:"页码,从 1 开始"},{name:"page_size",type:"int",default:20,help:"每页条数"},{name:"status",default:"ALL",help:`订单状态筛选:${j.join(" / ")}`}],columns:["order_id","item_id","buyer_nick","status_str","total_price","create_time"],func:async(x,B)=>{const F=L(B.page,"page"),Q=L(B.page_size,"page_size"),J=q(B.status);await x.goto(h);await x.wait(1);const X=(await f(x,"order list",{api:"mtop.taobao.idle.trade.merchant.sold.get",data:{pageNumber:F,rowsPerPage:Q,orderIds:"",queryCode:J,orderSearchParam:"{}"},version:"1.0"})).module||{},W=(Array.isArray(X.items)?X.items:[]).map((K)=>{const G=K.order||K.orderInfo||K,Z=K.buyer||K.buyerInfo||{},H=K.item||K.itemInfo||{};return{order_id:String(G.orderId||G.bizOrderId||G.id||""),item_id:String(H.itemId||H.id||""),item_title:H.title||"",buyer_id:String(Z.userId||Z.buyerId||""),buyer_nick:Z.nick||Z.userNick||"",status:G.status??G.orderStatus??"",status_str:G.statusStr||G.orderStatusStr||"",total_price:String(G.totalPrice||G.actualPrice||""),create_time:String(G.createTime||G.gmtCreate||"")}});return W.length?W:[{order_id:"",status_str:"(无已售订单)",total_price:"",buyer_nick:"",item_id:"",create_time:""}]}});$({site:"xianyu",name:"order-get",access:"read",description:"查询单个闲鱼订单详情",domain:"www.goofish.com",strategy:C.COOKIE,navigateBefore:!1,browser:!0,args:[{name:"order_id",required:!0,positional:!0,help:"订单号 orderId"},{name:"role",default:"seller",help:"视角:seller / buyer"}],columns:["order_id","item_id","status_str","total_price","buyer_nick"],func:async(x,B)=>{const F=Y(B.order_id,"order_id","2800000000000000000"),Q=String(B.role||"seller").trim()==="buyer"?"buyer":"seller";await x.goto(h);await x.wait(1);const J=await f(x,"order get",{api:"mtop.idle.web.trade.order.detail",data:{orderId:F,role:Q},version:"1.0"}),V=J.itemInfoDTO||{},X=J.buyerInfoDTO||{},D=J.sellerInfoDTO||{},W=J.priceInfoDTO||{},K=J.logisticsInfoDTO||{},G=J.statusInfoDTO||{};return[{order_id:F,role:Q,item_id:String(V.itemId||""),title:V.title||"",main_pic:V.picUrl||"",quantity:Number(V.quantity||1),buyer_id:String(X.buyerId||""),buyer_nick:X.userNick||"",seller_id:String(D.sellerId||""),seller_nick:D.userNick||"",total_price:String(W.totalPrice||""),auction_price:String(W.auctionPrice||""),post_fee:String(W.postFee||""),status:G.orderStatus,status_str:G.orderStatusStr||"",logistic_no:K.logisticsNo||"",logistic_company:K.logisticsCompany||""}]}});$({site:"xianyu",name:"order-ship-dummy",access:"write",description:"虚拟发货(仅虚拟商品,无需物流单号)",domain:"www.goofish.com",strategy:C.COOKIE,navigateBefore:!1,browser:!0,args:[{name:"order_id",required:!0,positional:!0,help:"订单号 orderId"},{name:"text",default:"",help:"发货附言(可选)"}],columns:["order_id","ok"],func:async(x,B)=>{const F=Y(B.order_id,"order_id","2800000000000000000");await x.goto(h);await x.wait(1);const Q=await f(x,"order ship-dummy",{api:"mtop.taobao.idle.logistic.consign.dummy",data:{orderId:F,tradeText:String(B.text||""),picList:[],newUnconsign:!0},version:"1.0"});return[{order_id:F,ok:!0,data:Q}]}});$({site:"xianyu",name:"order-ship-freeshipping",access:"write",description:"包邮发货(拼团活动专用)",domain:"www.goofish.com",strategy:C.COOKIE,navigateBefore:!1,browser:!0,args:[{name:"order_id",required:!0,positional:!0,help:"订单号 bizOrderId"},{name:"item_id",required:!0,help:"商品 itemId"},{name:"buyer_id",required:!0,help:"买家 userId"}],columns:["order_id","ok"],func:async(x,B)=>{const F=Y(B.order_id,"order_id","2800000000000000000"),Q=Y(B.item_id,"item_id","1017530128619"),J=Y(B.buyer_id,"buyer_id","2208502750464");await x.goto(h);await x.wait(1);const V=await f(x,"order ship-freeshipping",{api:"mtop.idle.groupon.activity.seller.freeshipping",data:{bizOrderId:F,itemId:Number(Q),buyerId:Number(J)},version:"1.0"});return[{order_id:F,ok:!0,data:V}]}});export const __test__={normalizeStatus:q,normalizePage:L,ORDER_STATUS:j};
@@ -0,0 +1 @@
1
+ import{ArgumentError as h}from"@jackwener/opencli/errors";import{cli as Q,Strategy as V}from"@jackwener/opencli/registry";import{HOME_URL as W,mtopRequest as X}from"./mtop.js";import{normalizeNumericId as Y}from"./utils.js";Q({site:"xianyu",name:"rate",access:"read",description:"拉某用户收到的信用评价列表",domain:"www.goofish.com",strategy:V.COOKIE,navigateBefore:!1,browser:!0,args:[{name:"user_id",required:!0,positional:!0,help:"被评价用户 userId(明文数字 uid)"},{name:"page",type:"int",default:1,help:"页码,从 1 开始"},{name:"page_size",type:"int",default:20,help:"每页条数"}],columns:["rate_id","rater_nick","rate_content","create_time"],func:async(A,B)=>{const G=Y(B.user_id,"user_id","2208502750464"),J=Math.max(1,Number(B.page)||1),K=Math.max(1,Number(B.page_size)||20);await A.goto(W);await A.wait(1);const C=await X(A,"rate",{api:"mtop.idle.web.trade.rate.list",data:{rateType:0,ratedUid:G,raterType:0,rowsPerPage:K,pageNumber:J,foldFlag:0,fishAdCode:"",extraTag:""},version:"1.0"}),D=(Array.isArray(C.cardList)?C.cardList:[]).filter((x)=>x&&typeof x==="object").map((x)=>{const v=x.cardData||x;return{rate_id:String(v.rateId||v.id||""),rater_id:String(v.raterUid||v.userId||""),rater_nick:v.raterNick||v.userNick||v.nick||"",rate_content:v.content||v.rateContent||"",rate_type:v.rateType??v.attitude??"",item_id:String(v.itemId||""),item_title:v.itemTitle||"",create_time:String(v.gmtCreate||v.createTime||v.rateTime||""),reply:v.reply||v.sellerReply||""}});return D.length?D:[{rate_id:"",rater_nick:"(该用户暂无评价或评价不可见)",rate_content:"",create_time:""}]}});export const __test__={};
@@ -0,0 +1 @@
1
+ import{cli as P,Strategy as Q}from"@jackwener/opencli/registry";import{HOME_URL as V,mtopRequest as W}from"./mtop.js";import{normalizeNumericId as X}from"./utils.js";P({site:"xianyu",name:"user",access:"read",description:"查询闲鱼用户主页信息(不传 user_id 看自己)",domain:"www.goofish.com",strategy:Q.COOKIE,navigateBefore:!1,browser:!0,args:[{name:"user_id",positional:!0,help:"目标用户 userId;留空看自己"}],columns:["user_id","nick","city","credit_level","fans_count","follow_count"],func:async(A,B)=>{const G=B.user_id!=null&&String(B.user_id).trim()!=="",J=G?X(B.user_id,"user_id","2208502750464"):"";await A.goto(V);await A.wait(1);const C=await W(A,"user",{api:"mtop.idle.web.user.page.head",data:G?{userId:J,self:!1}:{self:!0},version:"1.0"}),x=C.baseInfo||C.base||{},D=C.module||{},v=D.base||{},F=D.social||{},K=(D.tabs||{}).rate||{};return[{user_id:String(x.kcUserId||x.userId||J||""),nick:v.displayName||x.userNick||"",avatar:v.avatar&&v.avatar.avatar||v.avatar||"",location:v.ipLocation||"",signature:v.introduction||"",followers:Number(F.followers||0),following:Number(F.following||0),follow_status:F.followStatus??"",rate_count:Number(K.number||0),tags:x.tags||{}}]}});export const __test__={};