@4ier/neo 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +356 -0
- package/extension-dist/background.js +3 -0
- package/extension-dist/content.js +1 -0
- package/extension-dist/inject.js +4 -0
- package/extension-dist/manifest.json +51 -0
- package/package.json +46 -0
- package/tools/neo.cjs +5985 -0
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
(function(){"use strict";const M="__neo_capture_request",q=100*1024;function W(o,a=q){return o.length<=a?o:`${o.slice(0,a)}
|
|
2
|
+
[truncated ${o.length-a} bytes]`}function P(o,a=q){if(o==null)return o;if(typeof o=="string")return W(o,a);if(typeof o=="object")try{const c=JSON.stringify(o);return c&&c.length>a?W(c,a):o}catch{return W(String(o),a)}return W(String(o),a)}const $=/\.(?:js|css|png|jpe?g|gif|webp|ico|svg|woff2?|eot|ttf|otf|map)(?:[?#].*)?$/i,G=["google-analytics","googletagmanager","googlesyndication","doubleclick","sentry.io","hotjar.com","mixpanel.com","segment.com","segment.io","amplitude.com","fullstory.com","intercom.io","crisp.chat","hubspot.com","clarity.ms","newrelic.com","datadoghq.com","bugsnag.com","logrocket.io","heapanalytics.com","posthog.com","connect.facebook.net","bat.bing.com","mc.yandex.ru","splunkcloud.com","adora-cdn.com","transcend-cdn.com","w3-reporting","proxsee.pscp.tv","video.twimg.com","abs.twimg.com","pbs.twimg.com","googlevideo.com","ytimg.com","cdn.jsdelivr.net","cdnjs.cloudflare.com","unpkg.com","fonts.googleapis.com","fonts.gstatic.com","analytics.google.com","stats.g.doubleclick.net","pagead2.googlesyndication.com","adservice.google.com","static.cloudflareinsights.com","rum.browser-intake-datadoghq.com","app.launchdarkly.com","events.launchdarkly.com","api.statsig.com","featuregates.org","hdslb.com","bilivideo.com","bilivideo.cn","biliapi.net","data.bilibili.com","cm.bilibili.com","a-cdn.anthropic.com","a-cdn.claude.ai","statsig.anthropic.com","api.honeycomb.io"],j=new Set(["chrome-extension:","moz-extension:","safari-extension:","data:","blob:"]);function X(o,a={},c){try{const i=new URL(o,c||"http://localhost"),m=i.href.toLowerCase(),T=i.pathname.toLowerCase(),b=i.hostname.toLowerCase();if(j.has(i.protocol)||$.test(T))return!0;const H=`${m} ${b} ${JSON.stringify(a).toLowerCase()}`;return G.some(p=>H.includes(p))}catch{return!0}}function z(o,a,c){try{const i=new URL(a,c||"http://localhost");return`${o} ${i.pathname}`}catch{return`${o} ${a}`}}function g(o,a=q){return o.length<=a?o:`${o.slice(0,a)}
|
|
3
|
+
[truncated ${o.length-a} bytes]`}function I(o,a){const c=g(o);if((a||"").toLowerCase().includes("application/json")||o.startsWith("{")&&o.endsWith("}")||o.startsWith("[")&&o.endsWith("]"))try{return JSON.parse(o)}catch{return c}return c}function J(o){const a={};for(const c of o.split(`\r
|
|
4
|
+
`)){const i=c.indexOf(":");i<=0||(a[c.slice(0,i).trim()]=c.slice(i+1).trim())}return a}function D(o){try{return new URL(o).hostname}catch{return"unknown"}}function Y(o,a){try{return new URL(o,a).toString()}catch{return String(o)}}function K(o){if(o.id)return`#${o.id}`;const a=o.tagName.toLowerCase(),c=o.className&&typeof o.className=="string"?"."+o.className.trim().split(/\s+/).slice(0,2).join("."):"";return a+c}function F(o){return(o||"").trim().slice(0,50)||void 0}const O=new Map,k=6e4,V=3;function Q(o,a){const c=z(o,a,location.href),i=Date.now(),m=O.get(c);if(!m||i-m.lastTime>k){if(O.set(c,{count:1,lastTime:i}),O.size>200)for(const[T,b]of O)i-b.lastTime>k*2&&O.delete(T);return!1}return m.count++,m.lastTime=i,m.count>V}if(!window.__neoInterceptorInstalled){let o=function(e){return K({id:e.id,tagName:e.tagName,className:e.className})},a=function(e){return F(e.textContent)},c=function(){if(!S)return;if(Date.now()-S.timestamp>ee){S=null;return}return{...S,event:S.event}},i=function(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`neo-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`},m=function(e){return Y(e,location.href)},T=function(e,t={}){return X(e,t,location.href)},b=function(e){const t={};if(!e)return t;const n=e instanceof Headers?e.entries():Object.entries(e);for(const[s,u]of n)t[s]=u;return t},H=function(e){if(e!=null){if(typeof e=="string")return g(e);if(e instanceof URLSearchParams)return g(e.toString());if(e instanceof FormData){const t={};return e.forEach((n,s)=>{t[s]=String(n)}),t}if(e instanceof Blob)return`[Blob ${e.size} bytes]`;if(e instanceof ArrayBuffer)try{return g(new TextDecoder().decode(new Uint8Array(e)))}catch{return"[arraybuffer body]"}if(ArrayBuffer.isView(e))try{return g(new TextDecoder().decode(e))}catch{return"[typed array body]"}if(typeof e=="object")try{return P(e)}catch{return"[unserializable body]"}return g(String(e))}},p=function(e){if(!Q(e.method,e.url))try{window.postMessage({type:M,payload:e},"*")}catch{}},Z=function(e){const t=e.getResponseHeader("content-type")||void 0;let n="";try{(e.responseType===""||e.responseType==="text"||e.responseType==="json")&&(n=typeof e.responseText=="string"?e.responseText:"")}catch{n=""}return{statusText:e.status,headers:J(e.getAllResponseHeaders()),body:n?I(n,t):void 0}},A=function(e){return typeof e=="string"?g(e):e instanceof Blob?`[Blob ${e.size} bytes]`:e instanceof ArrayBuffer?`[ArrayBuffer ${e.byteLength} bytes]`:ArrayBuffer.isView(e)?`[TypedArray ${e.byteLength} bytes]`:String(e)},U=function(e){if(e.startsWith("{")&&e.endsWith("}")||e.startsWith("[")&&e.endsWith("]"))try{return JSON.parse(e)}catch{}return e},v=function(e){const t=Date.now();return t-e.msgWindowStart>se&&(e.msgCount=0,e.msgWindowStart=t),e.msgCount++,e.msgCount>ae};window.__neoInterceptorInstalled=!0;let S=null;const ee=2e3;document.addEventListener("click",e=>{const t=e.target;!t||!t.tagName||(S={event:"click",selector:o(t),text:a(t),timestamp:Date.now()})},!0),document.addEventListener("submit",e=>{const t=e.target;t&&(S={event:"submit",selector:o(t),text:void 0,timestamp:Date.now()})},!0);const B=window.fetch.bind(window),N=XMLHttpRequest.prototype,x=N.open,te=N.send,oe=N.setRequestHeader,R="__neo_meta";async function ne(e){if(e instanceof Blob)try{const t=await e.text();return I(t,e.type)}catch{return"[unreadable blob]"}return H(e)}window.fetch=async(...e)=>{const t=e[1],n=e[0],s=Date.now(),u=performance.now(),r=m(n instanceof Request?n.url:n),y=(typeof n!="string"&&!(n instanceof URL)&&(t!=null&&t.method)?t.method:n instanceof Request?n.method:(t==null?void 0:t.method)||"GET").toUpperCase(),f=b(n instanceof Request?n.headers:t==null?void 0:t.headers),l=Object.keys(f).length?f:t!=null&&t.headers?b(t.headers):{};if(T(r,l))return B(n,t);const h=await ne(n instanceof Request?await n.clone().text():t==null?void 0:t.body);try{const d=await B(n,t),w=Math.max(0,Math.round(performance.now()-u));let C;try{const ie=await d.clone().text();C=I(ie,d.headers.get("content-type")||void 0)}catch{C="[unreadable response body]"}const L={id:i(),timestamp:s,domain:D(r),url:r,method:y,requestHeaders:l,requestBody:h,responseStatus:d.status,responseHeaders:b(d.headers),responseBody:C,duration:w,trigger:c(),tabId:-1,tabUrl:location.href,source:"fetch"};return p(L),d}catch(d){const w=Math.max(0,Math.round(performance.now()-u)),C=d instanceof Error?d.message:String(d),L={id:i(),timestamp:s,domain:D(r),url:r,method:y,requestHeaders:l,requestBody:h,responseStatus:0,responseHeaders:{},responseBody:g(C),duration:w,trigger:c(),tabId:-1,tabUrl:location.href,source:"fetch"};throw p(L),d}},x.call,N.open=function(t,n,...s){const u={method:(t==null?void 0:t.toUpperCase())||"GET",url:m(n),headers:{},body:void 0,startedAt:0,startPerf:0,skipped:!1,finished:!1};return this[R]=u,x.apply(this,[t,n,...s])},N.setRequestHeader=function(t,n){const s=this[R];return s&&(s.headers[t]=n),oe.call(this,t,n)},N.send=function(t){const s=this[R]||{method:"GET",url:m(""),headers:{},body:void 0,startedAt:0,startPerf:0,skipped:!1,finished:!1};s.body=H(t),s.startedAt=Date.now(),s.startPerf=performance.now(),s.skipped=T(s.url,s.headers),s.finished=!1,this[R]=s;const u=async()=>{const r=this[R];if(!r||r.finished||r.skipped)return;r.finished=!0;const{statusText:y,headers:f,body:l}=Z(this),h=Math.max(0,Math.round(performance.now()-r.startPerf)),d={id:i(),timestamp:r.startedAt,domain:D(r.url),url:r.url,method:r.method,requestHeaders:r.headers,requestBody:r.body,responseStatus:y,responseHeaders:f,responseBody:l,duration:h,trigger:c(),tabId:-1,tabUrl:location.href,source:"xhr"};p(d)};return this.addEventListener("loadend",()=>{u()}),this.addEventListener("error",()=>{u()}),this.addEventListener("abort",()=>{u()}),te.call(this,t)};const E=window.WebSocket,re="__neo_ws_meta",se=1e4,ae=20;window.WebSocket=function(t,n){const s=n!==void 0?new E(t,n):new E(t),u=typeof t=="string"?t:t.toString(),r={url:u,domain:D(u.replace(/^ws(s)?:\/\//,"http$1://")),connectedAt:Date.now(),msgCount:0,msgWindowStart:Date.now()};s[re]=r,s.addEventListener("open",()=>{const f={id:i(),timestamp:Date.now(),domain:r.domain,url:r.url,method:"WS_OPEN",requestHeaders:{},requestBody:n?{protocols:Array.isArray(n)?n:[n]}:void 0,responseStatus:101,responseHeaders:{},responseBody:void 0,duration:Date.now()-r.connectedAt,tabId:-1,tabUrl:location.href,source:"websocket"};p(f)}),s.addEventListener("message",f=>{if(v(r))return;const l=A(f.data),h={id:i(),timestamp:Date.now(),domain:r.domain,url:r.url,method:"WS_RECV",requestHeaders:{},requestBody:void 0,responseStatus:200,responseHeaders:{},responseBody:U(l),duration:0,tabId:-1,tabUrl:location.href,source:"websocket"};p(h)}),s.addEventListener("close",f=>{const l={id:i(),timestamp:Date.now(),domain:r.domain,url:r.url,method:"WS_CLOSE",requestHeaders:{},requestBody:void 0,responseStatus:f.code,responseHeaders:{},responseBody:f.reason||void 0,duration:Date.now()-r.connectedAt,tabId:-1,tabUrl:location.href,source:"websocket"};p(l)}),s.addEventListener("error",()=>{const f={id:i(),timestamp:Date.now(),domain:r.domain,url:r.url,method:"WS_ERROR",requestHeaders:{},requestBody:void 0,responseStatus:0,responseHeaders:{},responseBody:"[WebSocket error]",duration:Date.now()-r.connectedAt,tabId:-1,tabUrl:location.href,source:"websocket"};p(f)});const y=s.send.bind(s);return s.send=function(l){if(!v(r)){const h=A(l),d={id:i(),timestamp:Date.now(),domain:r.domain,url:r.url,method:"WS_SEND",requestHeaders:{},requestBody:U(h),responseStatus:0,responseHeaders:{},responseBody:void 0,duration:0,tabId:-1,tabUrl:location.href,source:"websocket"};p(d)}return y(l)},s},window.WebSocket.prototype=E.prototype,Object.defineProperties(window.WebSocket,{CONNECTING:{value:E.CONNECTING},OPEN:{value:E.OPEN},CLOSING:{value:E.CLOSING},CLOSED:{value:E.CLOSED}});const _=window.EventSource;_&&(window.EventSource=function(t,n){const s=typeof t=="string"?t:t.toString(),u=n?new _(t,n):new _(t),r=D(s),y=Date.now();let f=0;const l=30;return u.addEventListener("open",()=>{p({id:i(),timestamp:Date.now(),domain:r,url:s,method:"SSE_OPEN",requestHeaders:{},requestBody:n!=null&&n.withCredentials?{withCredentials:!0}:void 0,responseStatus:200,responseHeaders:{},responseBody:void 0,duration:Date.now()-y,tabId:-1,tabUrl:location.href,source:"eventsource"})}),u.addEventListener("message",h=>{if(f++,f>l)return;const d=typeof h.data=="string"?h.data:String(h.data);let w=d;if(d.startsWith("{")||d.startsWith("["))try{w=JSON.parse(d)}catch{}p({id:i(),timestamp:Date.now(),domain:r,url:s,method:"SSE_MSG",requestHeaders:{},requestBody:void 0,responseStatus:200,responseHeaders:{},responseBody:typeof w=="string"?g(w):w,duration:Date.now()-y,tabId:-1,tabUrl:location.href,source:"eventsource"})}),u.addEventListener("error",()=>{p({id:i(),timestamp:Date.now(),domain:r,url:s,method:"SSE_ERROR",requestHeaders:{},requestBody:void 0,responseStatus:0,responseHeaders:{},responseBody:"[EventSource error]",duration:Date.now()-y,tabId:-1,tabUrl:location.href,source:"eventsource"})}),u},window.EventSource.prototype=_.prototype,Object.defineProperties(window.EventSource,{CONNECTING:{value:_.CONNECTING},OPEN:{value:_.OPEN},CLOSED:{value:_.CLOSED}}))}})();
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"manifest_version": 3,
|
|
3
|
+
"name": "Neo",
|
|
4
|
+
"version": "0.4.0",
|
|
5
|
+
"description": "Neo: capture fetch/XHR/WebSocket/SSE traffic with DOM trigger tracking, generate API schemas, execute from CLI.",
|
|
6
|
+
"permissions": [
|
|
7
|
+
"tabs"
|
|
8
|
+
],
|
|
9
|
+
"host_permissions": [
|
|
10
|
+
"<all_urls>"
|
|
11
|
+
],
|
|
12
|
+
"background": {
|
|
13
|
+
"service_worker": "background.js"
|
|
14
|
+
},
|
|
15
|
+
"action": {
|
|
16
|
+
"default_title": "Neo"
|
|
17
|
+
},
|
|
18
|
+
"content_scripts": [
|
|
19
|
+
{
|
|
20
|
+
"matches": [
|
|
21
|
+
"<all_urls>"
|
|
22
|
+
],
|
|
23
|
+
"js": [
|
|
24
|
+
"inject.js"
|
|
25
|
+
],
|
|
26
|
+
"run_at": "document_start",
|
|
27
|
+
"all_frames": true,
|
|
28
|
+
"world": "MAIN"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"matches": [
|
|
32
|
+
"<all_urls>"
|
|
33
|
+
],
|
|
34
|
+
"js": [
|
|
35
|
+
"content.js"
|
|
36
|
+
],
|
|
37
|
+
"run_at": "document_start",
|
|
38
|
+
"all_frames": true
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
"web_accessible_resources": [
|
|
42
|
+
{
|
|
43
|
+
"resources": [
|
|
44
|
+
"inject.js"
|
|
45
|
+
],
|
|
46
|
+
"matches": [
|
|
47
|
+
"<all_urls>"
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@4ier/neo",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Turn any website into an AI-callable API. Passive traffic capture, API schema generation, and execution.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "NEO_ENTRY=background vite build && NEO_ENTRY=content vite build && NEO_ENTRY=inject vite build",
|
|
8
|
+
"test": "node tools/neo.test.cjs"
|
|
9
|
+
},
|
|
10
|
+
"bin": {
|
|
11
|
+
"neo": "tools/neo.cjs"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"tools/neo.cjs",
|
|
15
|
+
"extension-dist/background.js",
|
|
16
|
+
"extension-dist/content.js",
|
|
17
|
+
"extension-dist/inject.js",
|
|
18
|
+
"extension-dist/manifest.json"
|
|
19
|
+
],
|
|
20
|
+
"keywords": [
|
|
21
|
+
"browser",
|
|
22
|
+
"api",
|
|
23
|
+
"chrome",
|
|
24
|
+
"cdp",
|
|
25
|
+
"automation",
|
|
26
|
+
"web-scraping",
|
|
27
|
+
"ai-agent",
|
|
28
|
+
"openclaw"
|
|
29
|
+
],
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/4ier/neo.git"
|
|
33
|
+
},
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"author": "4ier",
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"ws": "^8.19.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/chrome": "^0.0.303",
|
|
41
|
+
"@types/node": "^22.10.5",
|
|
42
|
+
"dexie": "^4.0.11",
|
|
43
|
+
"typescript": "^5.8.2",
|
|
44
|
+
"vite": "^6.0.0"
|
|
45
|
+
}
|
|
46
|
+
}
|