@genne/genne-cli 0.0.0-stage → 0.1.34
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 +27 -2
- package/package.json +28 -4
- package/skills/genne-cli/SKILL.md +67 -0
- package/src/api.js +1 -0
- package/src/cli.js +7 -0
- package/src/commands/access.js +1 -0
- package/src/commands/companies.js +1 -0
- package/src/commands/content.js +2 -0
- package/src/commands/crm.js +4 -0
- package/src/commands/desktop-integrations.js +1 -0
- package/src/commands/driver-routes.js +1 -0
- package/src/commands/driver.js +1 -0
- package/src/commands/feedback.js +3 -0
- package/src/commands/financial.js +1 -0
- package/src/commands/gr.js +1 -0
- package/src/commands/identity.js +1 -0
- package/src/commands/logistics.js +1 -0
- package/src/commands/notifications.js +2 -0
- package/src/commands/operational-input.js +1 -0
- package/src/commands/operations-config.js +1 -0
- package/src/commands/orders.js +1 -0
- package/src/commands/routes.js +1 -0
- package/src/commands/support.js +2 -0
- package/src/commands/tower.js +1 -0
- package/src/commands/users.js +1 -0
- package/src/core-fetch.js +1 -0
- package/src/device-login.js +1 -0
- package/src/global.js +5 -0
- package/src/help.js +1 -0
- package/src/local-file.js +1 -0
- package/src/mcp-administration.js +1 -0
- package/src/mcp-desktop-operations.js +1 -0
- package/src/mcp-logistics.js +1 -0
- package/src/mcp-operational.js +1 -0
- package/src/mcp-routes-tower.js +1 -0
- package/src/mcp-support-feedback.js +1 -0
- package/src/mcp.js +2 -0
- package/src/operations.js +1 -0
- package/src/private-file.js +1 -0
- package/src/remote-auth-store.js +31 -0
- package/src/remote-auth.js +1 -0
- package/src/remote-core.js +1 -0
- package/src/remote-http.js +1 -0
- package/src/remote-mcp.js +1 -0
- package/src/remote-server.js +2 -0
- package/src/request-scope.js +1 -0
- package/src/session.js +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var C=Object.defineProperty;var d=(o,t)=>C(o,"name",{value:t,configurable:!0});import{createApi as b,fail as i,uuid as p}from"./api.js";import{usersCommand as _}from"./commands/users.js";import{identityCommand as v}from"./commands/identity.js";import{accessCommand as w}from"./commands/access.js";import{driverCommand as R}from"./commands/driver.js";import{supportCommand as A}from"./commands/support.js";import{feedbackCommand as E}from"./commands/feedback.js";import{crmCommand as y}from"./commands/crm.js";import{notificationsCommand as S}from"./commands/notifications.js";import{contentCommand as T}from"./commands/content.js";import{companiesCommand as U}from"./commands/companies.js";import{grCommand as G}from"./commands/gr.js";import{ordersCommand as N}from"./commands/orders.js";import{driverRoutesCommand as O}from"./commands/driver-routes.js";import{logisticsCommand as P}from"./commands/logistics.js";import{operationsConfigCommand as I}from"./commands/operations-config.js";import{financialCommand as j}from"./commands/financial.js";import{routesCommand as q}from"./commands/routes.js";import{towerCommand as x}from"./commands/tower.js";import{commandHelp as F}from"./help.js";import{environmentCommand as H}from"./session.js";async function ro(o,{env:t=process.env,input:a,confirm:f}={}){if(o.length===0||o[0]==="help"||o.at(-1)==="--help"){const e=o[0]==="help"?o.slice(1).filter(n=>n!=="--help"):o.at(-1)==="--help"?o.slice(0,-1):[];return F(e)??i("USAGE",`Comando n\xE3o encontrado: ${e.join(" ")}. Use genne help.`,2)}if(o.length===2&&o[0]==="env"&&o[1]==="show")return H(t,["show"]);o.length===1&&o[0]==="logout"&&(o=["session","logout"]);const u=o.length===3&&o[0]==="users"&&o[1]==="driver"&&o[2]==="register",h=o.length===3&&o[0]==="auth"&&o[1]==="membership-invitations"&&o[2]==="accept",s=o[0]==="password"&&["forgot","reset"].includes(o[1])||u||h,c=o.length===4&&o[0]==="shipper"&&o[1]==="route"&&o[2]==="show";c&&p(o[3]);const r=b(t,{allowAnonymous:s});let m=null;s||(m=(await r("GET","/auth/me")).data,(!m||typeof m!="object"||typeof m.role!="string")&&i("RESPONSE","Resposta inv\xE1lida da API"));const l={api:r,user:m,uuid:p,fail:i,input:a??(()=>i("INPUT","Forne\xE7a JSON em stdin")),confirm:f??(()=>i("CONFIRM","Confirma\xE7\xE3o interativa necess\xE1ria")),requireRole(e){m?.role!==e&&i("HTTP_403","Acesso negado",403)}};if(o.length===1&&o[0]==="whoami"){const e=m.business_membership,n=e?.business_account_id&&["shipper","carrier"].includes(m.role)?{id:e.business_account_id,name:e.business_account?.name??null,membership_id:e.id,membership_role:e.membership_role}:null;return{data:{name:m.name,email:m.email,role:m.role,...n?{business_account:n}:{}}}}if(c)return l.requireRole("shipper"),r("GET",`/shipper/operational-routes/${p(o[3])}`);for(const e of[_,R,O,v,w,A,E,y,S,T,U,G,N,I,j,P,x,q]){const n=await e(o,l);if(n!==null)return n}i("USAGE","Comando desconhecido. Use genne help.",2)}d(ro,"runOperation");export{ro as runOperation};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var a=Object.defineProperty;var i=(e,r)=>a(e,"name",{value:r,configurable:!0});import{constants as t}from"node:fs";import{open as s}from"node:fs/promises";function c(e,r=!1){return(r?e.isDirectory():e.isFile())&&!e.isSymbolicLink()&&!(e.mode&63)&&(!process.getuid||e.uid===process.getuid())}i(c,"ownedFile");async function w(e){let r;try{r=await s(e,t.O_RDONLY|t.O_NOFOLLOW)}catch(o){throw o?.code==="ENOENT"?Object.assign(new Error("missing private file"),{code:"ENOENT"}):Object.assign(new Error("insecure private file"),{code:"INSECURE"})}try{if(!c(await r.stat()))throw Object.assign(new Error("insecure private file"),{code:"INSECURE"});return await r.readFile()}finally{await r.close()}}i(w,"readOwnedFile");export{c as ownedFile,w as readOwnedFile};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
var I=Object.defineProperty;var s=(n,T)=>I(n,"name",{value:T,configurable:!0});import{createCipheriv as U,createDecipheriv as f,randomBytes as m}from"node:crypto";import{constants as c}from"node:fs";import{lstat as k,mkdir as D,open as L}from"node:fs/promises";import{dirname as l}from"node:path";import{DatabaseSync as X}from"node:sqlite";function A(n,T=!1){if((T?!n.isDirectory():!n.isFile())||n.isSymbolicLink()||n.mode&63||process.getuid&&n.uid!==process.getuid())throw new Error("Insecure remote auth storage")}s(A,"secure");async function M(n,T){if(!Buffer.isBuffer(T)||T.length!==32)throw new Error("Remote auth encryption key must be 32 bytes");await D(l(n),{recursive:!0,mode:448});const g=await L(l(n),c.O_RDONLY|c.O_DIRECTORY|c.O_NOFOLLOW).catch(()=>{throw new Error("Insecure remote auth storage")});try{A(await g.stat(),!0)}finally{await g.close()}try{await(await L(n,c.O_RDWR|c.O_CREAT|c.O_EXCL|c.O_NOFOLLOW,384)).close()}catch(e){if(e.code!=="EEXIST")throw new Error("Insecure remote auth storage")}const _=await L(n,c.O_RDWR|c.O_NOFOLLOW).catch(()=>{throw new Error("Insecure remote auth storage")});let r;try{A(await _.stat()),r=new X(n);const e=await k(n),t=await _.stat();if(e.isSymbolicLink()||e.dev!==t.dev||e.ino!==t.ino)throw new Error("Insecure remote auth storage")}catch(e){throw r?.close(),e?.message==="Insecure remote auth storage",e}finally{await _.close()}r.exec("PRAGMA busy_timeout = 5000; PRAGMA journal_mode = WAL; PRAGMA foreign_keys = ON"),r.exec(`
|
|
2
|
+
CREATE TABLE IF NOT EXISTS authorizations (
|
|
3
|
+
id TEXT PRIMARY KEY, client_id TEXT NOT NULL, redirect_uri TEXT NOT NULL,
|
|
4
|
+
resource TEXT NOT NULL, scope TEXT NOT NULL, state TEXT NOT NULL,
|
|
5
|
+
challenge TEXT NOT NULL, expires_at INTEGER NOT NULL,
|
|
6
|
+
status TEXT NOT NULL, binding_hash TEXT, code_hash TEXT UNIQUE, grant_id TEXT
|
|
7
|
+
);
|
|
8
|
+
CREATE TABLE IF NOT EXISTS grants (
|
|
9
|
+
id TEXT PRIMARY KEY, client_id TEXT NOT NULL, resource TEXT NOT NULL,
|
|
10
|
+
scope TEXT NOT NULL, user_id TEXT NOT NULL, role TEXT NOT NULL,
|
|
11
|
+
membership_public_id TEXT, session_public_id TEXT NOT NULL,
|
|
12
|
+
core_tokens TEXT NOT NULL, expires_at INTEGER NOT NULL,
|
|
13
|
+
revoked_at INTEGER
|
|
14
|
+
);
|
|
15
|
+
CREATE TABLE IF NOT EXISTS tokens (
|
|
16
|
+
token_hash TEXT PRIMARY KEY, grant_id TEXT NOT NULL REFERENCES grants(id),
|
|
17
|
+
kind TEXT NOT NULL, status TEXT NOT NULL, expires_at INTEGER NOT NULL
|
|
18
|
+
);
|
|
19
|
+
CREATE INDEX IF NOT EXISTS grants_user ON grants(user_id);
|
|
20
|
+
CREATE INDEX IF NOT EXISTS tokens_grant ON tokens(grant_id);
|
|
21
|
+
`);const p=s(e=>{r.exec("BEGIN IMMEDIATE");try{const t=e();return r.exec("COMMIT"),t}catch(t){throw r.exec("ROLLBACK"),t}},"transaction"),h=s(e=>{const t=m(12),i=U("aes-256-gcm",T,t),o=Buffer.concat([i.update(JSON.stringify(e)),i.final()]);return Buffer.concat([t,i.getAuthTag(),o]).toString("base64url")},"seal"),S=s(e=>{const t=Buffer.from(e,"base64url"),i=f("aes-256-gcm",T,t.subarray(0,12));return i.setAuthTag(t.subarray(12,28)),JSON.parse(Buffer.concat([i.update(t.subarray(28)),i.final()]).toString())},"unseal"),N=s(e=>e&&{...e,core_tokens:S(e.core_tokens)},"grant"),O=s(e=>{r.prepare(`DELETE FROM authorizations
|
|
22
|
+
WHERE status IN ('pending', 'denied', 'approved') AND expires_at < ?`).run(e),r.prepare(`DELETE FROM authorizations
|
|
23
|
+
WHERE status = 'consumed' AND grant_id IN (
|
|
24
|
+
SELECT id FROM grants WHERE revoked_at IS NOT NULL OR expires_at < ?
|
|
25
|
+
)`).run(e)},"purgeAuthorizations");return{close:s(()=>r.close(),"close"),purgeAuthorizations:O,putAuthorization:s(e=>r.prepare(`INSERT INTO authorizations VALUES
|
|
26
|
+
(@id,@client_id,@redirect_uri,@resource,@scope,@state,@challenge,@expires_at,'pending',NULL,NULL,NULL)`).run(e),"putAuthorization"),getAuthorization:s(e=>r.prepare("SELECT * FROM authorizations WHERE id = ?").get(e),"getAuthorization"),setBindingHash:s((e,t,i)=>r.prepare(`UPDATE authorizations SET binding_hash = ?
|
|
27
|
+
WHERE id = ? AND status = 'pending' AND expires_at > ?`).run(t,e,i).changes===1,"setBindingHash"),denyAuthorization:s(e=>r.prepare("UPDATE authorizations SET status = 'denied' WHERE id = ? AND status = 'pending'").run(e).changes===1,"denyAuthorization"),approveAuthorization:s((e,t,i,o,d,E)=>p(()=>{const a=r.prepare("SELECT * FROM authorizations WHERE id = ?").get(e);return!a||a.status!=="pending"||a.expires_at<=E||a.binding_hash!==t?!1:(r.prepare(`INSERT INTO grants VALUES
|
|
28
|
+
(@id,@client_id,@resource,@scope,@user_id,@role,@membership_public_id,@session_public_id,@core_tokens,@expires_at,NULL)`).run({...o,core_tokens:h(d)}),r.prepare("UPDATE authorizations SET status = 'approved', code_hash = ?, grant_id = ? WHERE id = ?").run(i,o.id,e),!0)}),"approveAuthorization"),redeemCode:s((e,t,i,o,d,E)=>p(()=>{const a=r.prepare("SELECT * FROM authorizations WHERE code_hash = ?").get(e);return!a||a.client_id!==t||a.redirect_uri!==i||a.resource!==o||a.challenge!==d?null:a.status==="consumed"?(r.prepare("UPDATE grants SET revoked_at = ? WHERE id = ? AND revoked_at IS NULL").run(E,a.grant_id),{error:"reuse",grant_id:a.grant_id}):a.status!=="approved"||a.expires_at<=E?null:(r.prepare("UPDATE authorizations SET status = 'consumed' WHERE id = ?").run(a.id),{authorization:a,grant:N(r.prepare("SELECT * FROM grants WHERE id = ?").get(a.grant_id))})}),"redeemCode"),insertTokens:s((e,t,i,o,d,E)=>p(()=>{const a=r.prepare("SELECT * FROM grants WHERE id = ?").get(e);if(!a||a.revoked_at||a.expires_at<=E)return!1;const u=r.prepare("INSERT INTO tokens VALUES (?, ?, ?, 'active', ?)");return u.run(t,e,"access",o),u.run(i,e,"refresh",d),!0}),"insertTokens"),getAccess:s((e,t)=>{O(t);const i=r.prepare(`SELECT g.* FROM tokens t JOIN grants g ON g.id = t.grant_id
|
|
29
|
+
WHERE t.token_hash = ? AND t.kind = 'access' AND t.status = 'active'
|
|
30
|
+
AND t.expires_at > ? AND g.expires_at > ? AND g.revoked_at IS NULL`).get(e,t,t);return N(i)},"getAccess"),rotateRefresh:s((e,t,i,o,d,E)=>p(()=>{const a=r.prepare("SELECT * FROM tokens WHERE token_hash = ? AND kind = 'refresh'").get(e);if(!a)return{error:"invalid_grant"};if(a.status==="rotated")return r.prepare("UPDATE grants SET revoked_at = ? WHERE id = ? AND revoked_at IS NULL").run(E,a.grant_id),{error:"reuse",grant_id:a.grant_id};const u=r.prepare("SELECT * FROM grants WHERE id = ?").get(a.grant_id);if(a.status!=="active"||a.expires_at<=E||!u||u.revoked_at||u.expires_at<=E)return{error:"invalid_grant"};r.prepare("UPDATE tokens SET status = 'rotated' WHERE token_hash = ?").run(e);const R=r.prepare("INSERT INTO tokens VALUES (?, ?, ?, 'active', ?)");return R.run(t,u.id,"access",o),R.run(i,u.id,"refresh",d),{grant:N(u)}}),"rotateRefresh"),updateCoreTokens:s((e,t)=>r.prepare("UPDATE grants SET core_tokens = ? WHERE id = ? AND revoked_at IS NULL").run(h(t),e).changes===1,"updateCoreTokens"),getGrant:s(e=>N(r.prepare("SELECT * FROM grants WHERE id = ?").get(e)),"getGrant"),listGrants:s(e=>r.prepare(`SELECT id, client_id, resource, scope, role,
|
|
31
|
+
membership_public_id, session_public_id, expires_at, revoked_at FROM grants WHERE user_id = ? ORDER BY rowid DESC`).all(e),"listGrants"),revokeGrant:s((e,t)=>r.prepare("UPDATE grants SET revoked_at = ? WHERE id = ? AND revoked_at IS NULL").run(t,e).changes===1,"revokeGrant")}}s(M,"openRemoteAuthStore");export{M as openRemoteAuthStore};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var T=Object.defineProperty;var u=(i,n)=>T(i,"name",{value:n,configurable:!0});import{createHash as $,randomBytes as O}from"node:crypto";const l=u(i=>$("sha256").update(i).digest("base64url"),"sha"),m=u(()=>O(32).toString("base64url"),"opaque"),U=u((i,n)=>i===n,"same"),o=u(()=>{throw new Error("invalid_grant")},"denied"),x=Object.freeze(["genne.read","genne.write.request"]),S=x.join(" ");function I(i){const n=O(16);n.writeUIntBE(i,0,6),n[6]=n[6]&15|112,n[8]=n[8]&63|128;const _=n.toString("hex");return`${_.slice(0,8)}-${_.slice(8,12)}-${_.slice(12,16)}-${_.slice(16,20)}-${_.slice(20)}`}u(I,"publicId");function C(i){return(!i||i.id===void 0||i.id===null)&&o(),{user_id:String(i.id),role:i.role,membership_public_id:i.business_membership?.id??i.membership?.id??null}}u(C,"identity");function f(i){const n=new URL(i);if(n.protocol!=="https:"||n.username||n.password||n.hash)throw new Error("Invalid OAuth URL");return n.href}u(f,"validHttps");function P(i,n){try{const _=JSON.parse(Buffer.from(i.split(".")[1],"base64url")).exp;return!Number.isInteger(_)||_*1e3<=n+6e4}catch{return!0}}u(P,"expiresSoon");function H({store:i,core:n,resource:_,issuer:y,clientId:b,redirectUris:A,now:c=Date.now}){if(f(_),f(y),!b||!Array.isArray(A)||!A.length)throw new Error("OAuth client not configured");const E=new Set(A.map(f)),w=new Map;function B(t){const e=i.getAuthorization(t);return(!e||e.status!=="pending"||e.expires_at<=c())&&o(),e}u(B,"pending");function G(t){return{authorization_id:t.id,client_id:t.client_id,redirect_uri:t.redirect_uri,resource:t.resource,scope:t.scope,state:t.state,code_challenge:t.challenge,code_challenge_method:"S256",expires_at:t.expires_at,callback_uri:new URL("/oauth/handoff",y).href}}u(G,"handoffBinding");async function z(t){try{let e=t.core_tokens;return P(e.token,c())&&(e=await n.refreshSession(e.refresh_token)),await n.revokeSession(e.token,t.session_public_id),!0}catch{return!1}}u(z,"revokeCoreSession");async function R(t){const r=(w.get(t.id)??Promise.resolve()).catch(()=>{}).then(async()=>{const s=i.getGrant(t.id);(!s||s.revoked_at||s.expires_at<=c()||s.client_id!==b||s.resource!==_||s.scope!==S)&&o();let a=s.core_tokens;if(P(a.token,c()))try{const d=await n.refreshSession(a.refresh_token);a={token:d.token,refresh_token:d.refresh_token},(!a.token||!a.refresh_token||!i.updateCoreTokens(t.id,a))&&o()}catch{i.revokeGrant(t.id,c()),o()}let p;try{p=await n.validateSession(a.token,s.session_public_id)}catch{i.revokeGrant(t.id,c()),o()}return(!U(String(p.user_id),s.user_id)||p.role!==s.role||(p.membership_public_id??null)!==s.membership_public_id||p.session_public_id!==s.session_public_id)&&(i.revokeGrant(t.id,c()),o()),{...s,core_tokens:a}});w.set(t.id,r);try{return await r}finally{w.get(t.id)===r&&w.delete(t.id)}}return u(R,"withCoreSession"),{protectedResourceMetadata:u(()=>({resource:_,authorization_servers:[y],scopes_supported:x}),"protectedResourceMetadata"),authorizationServerMetadata:u(()=>({issuer:y,authorization_endpoint:new URL("/oauth/authorize",y).href,token_endpoint:new URL("/oauth/token",y).href,response_types_supported:["code"],grant_types_supported:["authorization_code","refresh_token"],code_challenge_methods_supported:["S256"],token_endpoint_auth_methods_supported:["none"],scopes_supported:x}),"authorizationServerMetadata"),start(t){if(t.client_id!==b||!E.has(t.redirect_uri)||t.response_type!=="code"||t.resource!==_||t.scope!==S||t.code_challenge_method!=="S256"||!/^[A-Za-z0-9_-]{43,128}$/.test(t.code_challenge??"")||typeof t.state!="string"||t.state.length<8||t.state.length>1024)throw new Error("invalid_request");const e=m();return i.purgeAuthorizations(c()),i.putAuthorization({id:e,client_id:b,redirect_uri:t.redirect_uri,resource:_,scope:S,state:t.state,challenge:t.code_challenge,expires_at:c()+6e5}),{authorizationId:e,expiresIn:600}},handoffRequest(t){const e=B(t),r=G(e),s=l(JSON.stringify(r));return i.setBindingHash(t,s,c())||o(),r},denyAuthorization:u(t=>i.denyAuthorization(t),"denyAuthorization"),async completeHandoff(t,e){const r=i.getAuthorization(t);(!r||r.status!=="pending"||r.expires_at<=c())&&((!r||r.status==="pending")&&e?.token&&e?.session_public_id&&await n.revokeSession(e.token,e.session_public_id).catch(()=>{}),o());const s=G(r),a=l(JSON.stringify(s));if((!(e&&Object.entries(s).every(([h,L])=>e[h]===L))||r.binding_hash!==a||!["approved","denied"].includes(e.decision))&&(e?.token&&e?.session_public_id&&await n.revokeSession(e.token,e.session_public_id).catch(()=>{}),o()),e.decision==="denied"){(e.token||e.refresh_token||e.session_public_id)&&(e.token&&e.session_public_id&&await n.revokeSession(e.token,e.session_public_id).catch(()=>{}),o()),i.denyAuthorization(t)||o();const h=new URL(r.redirect_uri);return h.searchParams.set("error","access_denied"),h.searchParams.set("state",r.state),h.href}const d=I(c());(e.user_id===void 0||e.user_id===null||!["admin","driver","carrier","shipper"].includes(e.role)||["carrier","shipper"].includes(e.role)&&!e.membership_public_id||typeof e.session_public_id!="string"||!e.session_public_id||typeof e.token!="string"||!e.token||typeof e.refresh_token!="string"||!e.refresh_token)&&(e.token&&e.session_public_id&&await n.revokeSession(e.token,e.session_public_id).catch(()=>{}),o());const k=m();let g;try{g=i.approveAuthorization(t,a,l(k),{id:d,client_id:r.client_id,resource:r.resource,scope:r.scope,user_id:String(e.user_id),role:e.role,membership_public_id:e.membership_public_id??null,session_public_id:e.session_public_id,expires_at:c()+30*864e5},{token:e.token,refresh_token:e.refresh_token},c())}catch(h){throw await n.revokeSession(e.token,e.session_public_id).catch(()=>{}),h}g||(await n.revokeSession(e.token,e.session_public_id).catch(()=>{}),o());const v=new URL(r.redirect_uri);return v.searchParams.set("code",k),v.searchParams.set("state",r.state),v.href},async exchangeCode({code:t,code_verifier:e,client_id:r,redirect_uri:s,resource:a,scope:p}){(r!==b||!E.has(s)||a!==_||p!==void 0&&p!==S||typeof t!="string"||t.length!==43||!/^[A-Za-z0-9._~-]{43,128}$/.test(e??""))&&o();const d=i.redeemCode(l(t),r,s,_,l(e),c());if(d?.error==="reuse"){const h=i.getGrant(d.grant_id);h&&await z(h),o()}d||o();const k=await R(d.grant),g=m(),v=m();return i.insertTokens(k.id,l(g),l(v),c()+9e5,k.expires_at,c())||o(),{access_token:g,token_type:"Bearer",expires_in:900,refresh_token:v,scope:k.scope}},async refresh({refresh_token:t,client_id:e,resource:r,scope:s}){(e!==b||r!==_||s!==void 0&&s!==S||typeof t!="string")&&o();const a=m(),p=m(),d=i.rotateRefresh(l(t),l(a),l(p),c()+9e5,c()+30*864e5,c());if(d.error==="reuse"){const g=i.getGrant(d.grant_id);g&&await z(g)}d.error&&o();const k=await R(d.grant);return{access_token:a,token_type:"Bearer",expires_in:900,refresh_token:p,scope:k.scope}},async validateCall(t,e="genne.read"){(typeof t!="string"||t.length!==43)&&o();const r=i.getAccess(l(t),c());(!r||r.client_id!==b||r.resource!==_||r.scope!==S||!x.includes(e))&&o();const s=await R(r);return{grantPublicId:s.id,coreAccessToken:s.core_tokens.token,userId:s.user_id,role:s.role,membershipPublicId:s.membership_public_id,sessionPublicId:s.session_public_id,scopes:s.scope.split(" ")}},async listGrants(t){const e=C(await n.inspectApprover(t));return i.listGrants(e.user_id)},async revokeGrant(t,e){const r=C(await n.inspectApprover(e)),s=i.getGrant(t);return(!s||s.user_id!==r.user_id)&&o(),i.revokeGrant(t,c()),{revoked:!0,coreRevocationConfirmed:await z(s)}}}}u(H,"createRemoteAuth");export{S as REMOTE_SCOPE,x as REMOTE_SCOPES,H as createRemoteAuth};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var w=Object.defineProperty;var t=(h,i)=>w(h,"name",{value:i,configurable:!0});import{currentRequestSignal as m}from"./request-scope.js";function v({origin:h,adapterKey:i,consentOrigin:f,fetchImpl:p=fetch}){const n=new URL(h);if(n.protocol!=="https:"&&!["localhost","127.0.0.1","[::1]"].includes(n.hostname))throw new Error("Core API requires HTTPS");if(n.pathname!=="/"||n.search||n.hash||n.username||n.password||typeof i!="string"||i.length<32)throw new Error("Invalid Core adapter configuration");const a=new URL(f);if(a.protocol!=="https:"||a.pathname!=="/"||a.search||a.hash||a.username||a.password)throw new Error("Invalid Core/Admin consent origin");async function s(e,r,o,u,l=!1){let c;try{c=await p(`${n.origin}/api/v1${r}`,{method:e,redirect:"error",headers:{accept:"application/json",...o?{authorization:`Bearer ${o}`}:{},...l?{"x-genne-mcp-adapter-key":i}:{},...u===void 0?{}:{"content-type":"application/json"}},...u===void 0?{}:{body:JSON.stringify(u)},signal:AbortSignal.any([AbortSignal.timeout(15e3),m()].filter(Boolean))})}catch{throw new Error("Core unavailable")}if(!c.ok)throw Object.assign(new Error("Core denied session"),{status:c.status});if(c.status===204)return{};const d=await c.json().catch(()=>null);if(!d?.data||typeof d.data!="object")throw new Error("Invalid Core response");return d.data}return t(s,"request"),{async registerHandoff(e){const r=await s("POST","/auth/mcp/handoffs","",e,!0),o=new URL(r.authorization_url);if(o.origin!==a.origin||o.username||o.password||o.hash)throw new Error("Invalid Core/Admin consent redirect");return o.href},redeemHandoff:t((e,r)=>s("POST","/auth/mcp/handoffs/redeem","",{authorization_id:e,handoff_code:r},!0),"redeemHandoff"),inspectApprover:t(e=>s("GET","/auth/me",e),"inspectApprover"),validateSession:t((e,r)=>s("GET",`/auth/mcp/sessions/${encodeURIComponent(r)}`,e,void 0,!0),"validateSession"),revokeSession:t((e,r)=>s("POST",`/auth/mcp/sessions/${encodeURIComponent(r)}/revoke`,e,{},!0),"revokeSession"),refreshSession:t(e=>s("POST","/auth/refresh","",{refresh_token:e}),"refreshSession")}}t(v,"createRemoteCore");export{v as createRemoteCore};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var l=Object.defineProperty;var h=(t,n)=>l(t,"name",{value:n,configurable:!0});const p={"content-type":"application/json","cache-control":"no-store"},w=h(async t=>{if(Number(t.headers.get("content-length")??0)>8192)throw new Error("request_too_large");const n=await t.text();if(n.length>8192)throw new Error("request_too_large");return Object.fromEntries(new URLSearchParams(n))},"form"),a=h((t,n=200)=>new Response(JSON.stringify(t),{status:n,headers:p}),"json"),u=h(t=>new Response(null,{status:303,headers:{location:t,"cache-control":"no-store","referrer-policy":"no-referrer"}}),"redirect");function g({auth:t,core:n,mcpHandler:s}){const c=h(d=>/^Bearer (.+)$/.exec(d.headers.get("authorization")??"")?.[1],"browserToken");return h(async function(r){const o=new URL(r.url);try{if(r.method==="GET"&&o.pathname==="/.well-known/oauth-protected-resource")return a(t.protectedResourceMetadata());if(r.method==="GET"&&o.pathname==="/.well-known/oauth-authorization-server")return a(t.authorizationServerMetadata());if(r.method==="GET"&&o.pathname==="/oauth/authorize"){const e=t.start(Object.fromEntries(o.searchParams));try{return u(await n.registerHandoff(t.handoffRequest(e.authorizationId)))}catch(i){throw t.denyAuthorization(e.authorizationId),i}}if(r.method==="GET"&&o.pathname==="/oauth/handoff"){const e=o.searchParams.get("authorization_id")??"",i=o.searchParams.get("handoff_code")??"";if(!/^[A-Za-z0-9_-]{43}$/.test(e)||!/^[A-Za-z0-9_-]{43}$/.test(i))return a({error:"invalid_request"},400);const m=await n.redeemHandoff(e,i);return u(await t.completeHandoff(e,m))}if(r.method==="POST"&&o.pathname==="/oauth/token"){const e=await w(r),i=e.grant_type==="authorization_code"?await t.exchangeCode(e):e.grant_type==="refresh_token"?await t.refresh(e):null;return i?a(i):a({error:"unsupported_grant_type"},400)}if(r.method==="GET"&&o.pathname==="/oauth/grants"){const e=c(r);return e?a({data:await t.listGrants(e)}):a({error:"unauthorized"},401)}const f=/^\/oauth\/grants\/([0-9a-f-]{36})\/revoke$/.exec(o.pathname);if(r.method==="POST"&&f){const e=c(r);return e?a({data:await t.revokeGrant(f[1],e)}):a({error:"unauthorized"},401)}return o.pathname==="/mcp"&&s?s(r):a({error:"not_found"},404)}catch{return o.pathname==="/oauth/token"?a({error:"invalid_grant"},400):a({error:"authorization_failed"},400)}},"handleRemote")}h(g,"createRemoteOAuthHandler");export{g as createRemoteOAuthHandler};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var m=Object.defineProperty;var a=(e,t)=>m(e,"name",{value:t,configurable:!0});import{McpServer as y,WebStandardStreamableHTTPServerTransport as S}from"@modelcontextprotocol/server";import{z as E}from"zod";import{runOperation as O}from"./operations.js";import{REMOTE_SCOPE as R,REMOTE_SCOPES as g}from"./remote-auth.js";function v({coreOrigin:e,coreAccessToken:t}){const r=new y({name:"genne-product-remote",version:"0.1.0"});return r.registerTool("genne_whoami",{description:"Consulta a identidade e o papel ativo da sess\xE3o Genne.",inputSchema:E.object({}),annotations:{readOnlyHint:!0,openWorldHint:!1,destructiveHint:!1}},async()=>{const s=await O(["whoami"],{env:{GENNE_API_URL:e,GENNE_ACCESS_TOKEN:t}});return{content:[{type:"text",text:JSON.stringify(s)}]}}),r}a(v,"createBasicReadServer");function J({auth:e,coreOrigin:t,resource:r,createServerForContext:s=v}){const i=`Bearer resource_metadata="${new URL("/.well-known/oauth-protected-resource",r).href}", scope="${R}"`;return a(async function(p){const u=/^Bearer ([A-Za-z0-9_-]{43})$/.exec(p.headers.get("authorization")??"");if(!u)return new Response(JSON.stringify({error:"unauthorized"}),{status:401,headers:{"content-type":"application/json","www-authenticate":i}});let c;try{c=await e.validateCall(u[1])}catch{return new Response(JSON.stringify({error:"unauthorized"}),{status:401,headers:{"content-type":"application/json","www-authenticate":i}})}const l=s({coreOrigin:t,coreAccessToken:c.coreAccessToken,context:c}),d=new S({enableJsonResponse:!0});await l.connect(d);try{const n=await d.handleRequest(p);if(!n.headers.get("content-type")?.includes("application/json"))return n;const w=await n.text();if(!w)return new Response(null,n);const o=JSON.parse(w);for(const f of Array.isArray(o)?o:[o])for(const h of f.result?.tools??[])h.securitySchemes=[{type:"oauth2",scopes:g}];return new Response(JSON.stringify(o),n)}finally{await l.close()}},"handleMcp")}a(J,"createRemoteMcpHandler");export{v as createBasicReadServer,J as createRemoteMcpHandler};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var B=Object.defineProperty;var i=(t,r)=>B(t,"name",{value:r,configurable:!0});import{createServer as L}from"node:http";import{realpathSync as y}from"node:fs";import{readOwnedFile as U}from"./private-file.js";import{runWithRequestSignal as $}from"./request-scope.js";import{Readable as x}from"node:stream";import{isAbsolute as R}from"node:path";import{fileURLToPath as v}from"node:url";import Y from"../package.json"with{type:"json"};import{openRemoteAuthStore as F}from"./remote-auth-store.js";import{createRemoteAuth as H}from"./remote-auth.js";import{createRemoteCore as k}from"./remote-core.js";import{createRemoteOAuthHandler as W}from"./remote-http.js";import{createRemoteProductMcpHandler as z}from"./mcp.js";const K="genne-mcp-remote",V=Y.version,X=1024*1024,j=16*1024*1024,J=new Set(["localhost","127.0.0.1","[::1]"]),Q=new Set(["/health","/mcp","/oauth/authorize","/oauth/handoff","/oauth/token","/oauth/grants","/.well-known/oauth-protected-resource","/.well-known/oauth-authorization-server"]);class c extends Error{static{i(this,"RemoteConfigError")}constructor(r){super(r),this.name="RemoteConfigError"}}class I extends Error{static{i(this,"RequestTooLargeError")}constructor(){super("request_too_large"),this.name="RequestTooLargeError"}}class d extends Error{static{i(this,"InvalidRequestTargetError")}constructor(){super("invalid_request_target"),this.name="InvalidRequestTargetError"}}const C=i(t=>typeof t=="string"&&t.trim()!=="","hasValue");function p(t,r){if(C(t[r]))return t[r].trim()}i(p,"valueFrom");function E(t,r){const e=p(t,r);if(!e)throw new c(`Missing required configuration: ${r}`);return e}i(E,"requiredValue");function O(t,r,{https:e=!0,root:n=!1,expectedPath:a}={}){let o;try{o=new URL(t)}catch{throw new c(`Invalid ${r}`)}if(e&&o.protocol!=="https:"||!e&&!["https:","http:"].includes(o.protocol)||o.username||o.password||o.search||o.hash||n&&o.pathname!=="/"||a!==void 0&&o.pathname!==a)throw new c(`Invalid ${r}`);return o.href}i(O,"url");function g(t,r,{https:e=!0,allowLocalHttp:n=!1}={}){const a=O(t,r,{https:e&&!n}),o=new URL(a);if(o.pathname!=="/"||o.port&&!/^\d+$/.test(o.port))throw new c(`Invalid ${r}`);if(n&&o.protocol==="http:"&&!J.has(o.hostname))throw new c(`Invalid ${r}`);return o.origin}i(g,"origin");function Z(t){let r;try{r=t.startsWith("[")?JSON.parse(t):t.split(/[\n,]/u).map(n=>n.trim()).filter(Boolean)}catch{throw new c("Invalid GENNE_MCP_REDIRECT_URIS")}if(!Array.isArray(r)||r.length===0||r.some(n=>typeof n!="string"||!n.trim()))throw new c("Invalid GENNE_MCP_REDIRECT_URIS");const e=r.map(n=>O(n.trim(),"GENNE_MCP_REDIRECT_URIS",{https:!0}));if(new Set(e).size!==e.length)throw new c("Duplicate GENNE_MCP_REDIRECT_URIS");return e}i(Z,"redirectUris");function q(t,r){if(!C(t))return[];const e=t.split(/[\n,]/u).map(n=>n.trim()).filter(Boolean);if(e.length===0)throw new c(`Invalid ${r}`);return e.map(n=>g(n,r))}i(q,"origins");function P(t,r,{min:e,max:n}){if(!/^(?:0|[1-9]\d*)$/u.test(t))throw new c(`Invalid ${r}`);const a=Number(t);if(!Number.isSafeInteger(a)||a<e||a>n)throw new c(`Invalid ${r}`);return a}i(P,"integer");function tt(t,r){if(t.length===32)return t;const e=t.toString("utf8").trim();if(/^[0-9a-f]{64}$/iu.test(e))return Buffer.from(e,"hex");try{const n=Buffer.from(e,"base64url");if(n.length===32&&n.toString("base64url")===e.replace(/=+$/u,""))return n}catch{}throw new c(`Invalid ${r}`)}i(tt,"keyFromBytes");async function rt(t,r){try{return await U(t)}catch(e){throw e?.code==="ENOENT"?new c(`Cannot read ${r}`):new c(`Insecure ${r}`)}}i(rt,"secureFile");async function M(t,r,{key:e=!1}={}){const n=E(t,r),a=await rt(n,r),o=Buffer.isBuffer(a)?a:Buffer.from(a,"utf8");if(e)return tt(o,r);const s=o.toString("utf8").trim();if(s.length<32||/[\u0000-\u001f\u007f]/u.test(s))throw new c(`Invalid ${r}`);return s}i(M,"secret");function et(t=process.env){const r=O(E(t,"GENNE_MCP_RESOURCE"),"GENNE_MCP_RESOURCE",{expectedPath:"/mcp"}),e=g(E(t,"GENNE_MCP_ISSUER"),"GENNE_MCP_ISSUER"),n=g(E(t,"GENNE_MCP_CORE_ORIGIN"),"GENNE_MCP_CORE_ORIGIN",{allowLocalHttp:!0}),a=g(E(t,"GENNE_MCP_ADMIN_ORIGIN"),"GENNE_MCP_ADMIN_ORIGIN"),o=E(t,"GENNE_MCP_CLIENT_ID");if(!/^[A-Za-z0-9._~-]{1,128}$/u.test(o))throw new c("Invalid GENNE_MCP_CLIENT_ID");const s=Z(E(t,"GENNE_MCP_REDIRECT_URIS")),u=E(t,"GENNE_MCP_ADAPTER_KEY_FILE"),f=E(t,"GENNE_MCP_STORE_KEY_FILE");if(!R(u)||!R(f))throw new c("Secret file paths must be absolute");const l=E(t,"GENNE_MCP_STORE_PATH");if(!R(l))throw new c("GENNE_MCP_STORE_PATH must be absolute");const h=P(E(t,"GENNE_MCP_PORT"),"GENNE_MCP_PORT",{min:0,max:65535}),m=E(t,"GENNE_MCP_BIND");if(!/^(?:[A-Za-z0-9.-]+|\[[0-9A-Fa-f:]+\])$/u.test(m))throw new c("Invalid GENNE_MCP_BIND");const T=p(t,"GENNE_MCP_MAX_BODY_BYTES")?P(p(t,"GENNE_MCP_MAX_BODY_BYTES"),"GENNE_MCP_MAX_BODY_BYTES",{min:1,max:j}):X,S=q(p(t,"GENNE_MCP_ALLOWED_ORIGINS"),"GENNE_MCP_ALLOWED_ORIGINS"),G=new URL(r).origin,A=s.map(D=>new URL(D).origin),b=new Set(S.length?S:[e,G,...A]);return Object.freeze({resource:r,issuer:e,coreOrigin:n,adminOrigin:a,clientId:o,redirectUris:Object.freeze(s),adapterKeyFile:u,storeKeyFile:f,storePath:l,port:h,bind:m,maxBody:T,allowedOrigins:b})}i(et,"loadRemoteConfig");function _(t,r=200){return new Response(JSON.stringify(t),{status:r,headers:{"content-type":"application/json","cache-control":"no-store"}})}i(_,"responseJson");function nt(t,r){if(typeof t!="string"||!t.startsWith("/")||t.startsWith("//")||t.includes("\\"))throw new d;let e;try{e=new URL(t,r)}catch{throw new d}if(e.origin!==new URL(r).origin||e.username||e.password||e.hash||e.pathname.includes("//"))throw new d;return e}i(nt,"parseTarget");function ot(t){return Q.has(t)||/^\/oauth\/grants\/[0-9a-f-]{36}\/revoke$/u.test(t)}i(ot,"knownRequestPath");function it(t){const r=new Headers;for(const[e,n]of Object.entries(t.headers))if(Array.isArray(n))for(const a of n)r.append(e,a);else n!==void 0&&r.set(e,n);return r}i(it,"headerValues");function at(t){const r=t.headers["content-length"];if(r===void 0)return;if(Array.isArray(r)||!/^(?:0|[1-9]\d*)$/u.test(r))throw new d;const e=Number(r);if(!Number.isSafeInteger(e))throw new d;return e}i(at,"contentLength");async function st(t,r){let e;try{e=at(t)}catch(n){throw t.resume(),n}if(e!==void 0&&e>r)throw t.resume(),new I;return["GET","HEAD"].includes(t.method)?Buffer.alloc(0):new Promise((n,a)=>{const o=[];let s=0,u=!1;const f=i(l=>{u||(u=!0,t.resume(),a(l))},"fail");t.on("data",l=>{if(!u){if(s+=l.length,s>r){f(new I);return}o.push(l)}}),t.once("end",()=>{u||(u=!0,n(Buffer.concat(o,s)))}),t.once("aborted",()=>f(new d)),t.once("error",()=>f(new d))})}i(st,"readBoundedBody");function N(t,r){return r&&(t.headers.set("access-control-allow-origin",r),t.headers.set("access-control-expose-headers","WWW-Authenticate, MCP-Session-Id"),t.headers.append("vary","Origin")),t}i(N,"addCors");async function w(t,r){if(r.statusCode=t.status,t.headers.forEach((e,n)=>r.setHeader(n,e)),!t.body){r.end();return}try{for await(const e of x.fromWeb(t.body))r.write(e)||await new Promise((n,a)=>{const o=i(()=>{r.off("drain",s),r.off("close",u),r.off("error",f)},"cleanup"),s=i(()=>{o(),n()},"onDrain"),u=i(()=>{o(),a(new Error("response_closed"))},"onClose"),f=i(l=>{o(),a(l)},"onError");r.once("drain",s),r.once("close",u),r.once("error",f)});r.end()}catch{r.destroy()}}i(w,"sendResponse");function ct(t){return t instanceof I?_({error:"request_too_large"},413):t instanceof d?_({error:"invalid_request"},400):_({error:"internal_error"},500)}i(ct,"safeError");function ut({config:t,handler:r}){return async(e,n)=>{const a=new AbortController,o=i(()=>a.abort(),"onAbort");e.on("aborted",o);try{await $(a.signal,()=>ft(e,n,t,r))}finally{e.off("aborted",o)}}}i(ut,"requestHandler");async function ft(t,r,e,n){const a=t.headers.origin;if(a!==void 0&&(!C(a)||!e.allowedOrigins.has(a))){await w(_({error:"forbidden"},403),r);return}try{const o=nt(t.url,e.resource);if(t.method==="OPTIONS"){if(!a){await w(_({error:"invalid_request"},400),r);return}const h=new Response(null,{status:204,headers:{"cache-control":"no-store","access-control-allow-methods":"GET,HEAD,POST,OPTIONS","access-control-allow-headers":"Authorization, Content-Type, Accept, MCP-Protocol-Version, MCP-Session-Id, Last-Event-ID"}});await w(N(h,a),r);return}const s=await st(t,e.maxBody);if(o.pathname==="/health"){await w(N(_({service:K,version:V}),a),r);return}if(!ot(o.pathname)){await w(N(_({error:"not_found"},404),a),r);return}const u=it(t),f={method:t.method,headers:u};!["GET","HEAD"].includes(t.method)&&s.length>0&&(f.body=s);const l=await n(new Request(o,f));await w(N(l,a),r)}catch(o){await w(N(ct(o),a),r)}}i(ft,"serveRequest");function lt(t,r,e){return new Promise((n,a)=>{const o=i(u=>{t.off("listening",s),a(u)},"onError"),s=i(()=>{t.off("error",o),n(t.address())},"onListening");t.once("error",o),t.once("listening",s),t.listen(r,e)})}i(lt,"listen");async function Et(t){await new Promise((r,e)=>{t.close(n=>{!n||n.code==="ERR_SERVER_NOT_RUNNING"?r():e(n)})})}i(Et,"closeServer");async function dt({env:t=process.env,fetchImpl:r=fetch}={}){const e=et(t),n=await M(t,"GENNE_MCP_ADAPTER_KEY_FILE"),a=await M(t,"GENNE_MCP_STORE_KEY_FILE",{key:!0}),o=await F(e.storePath,a);try{const s=k({origin:e.coreOrigin,adapterKey:n,consentOrigin:e.adminOrigin,fetchImpl:r}),u=H({store:o,core:s,resource:e.resource,issuer:e.issuer,clientId:e.clientId,redirectUris:e.redirectUris}),f=z({auth:u,coreOrigin:e.coreOrigin,resource:e.resource,adapterKey:n,adminOrigin:e.adminOrigin,fetchImpl:r}),l=W({auth:u,core:s,mcpHandler:f}),h=L(ut({config:e,handler:l}));let m=!1;return{config:e,server:h,listen:i(()=>lt(h,e.port,e.bind),"listen"),close:i(async()=>{if(!m){m=!0;try{await Et(h)}finally{o.close()}}},"close")}}catch(s){throw o.close(),s}}i(dt,"createRemoteServer");async function ht(t={}){const r=await dt(t);try{return await r.listen(),r}catch(e){throw await r.close(),e}}i(ht,"startRemoteServer");async function _t(){const t=await ht(),r=i(async()=>{try{await t.close()}catch{process.exitCode=1}},"stop");process.once("SIGINT",r),process.once("SIGTERM",r)}i(_t,"main");function wt(){if(!process.argv[1])return!1;try{return y(process.argv[1])===y(v(import.meta.url))}catch{return!1}}i(wt,"isMainModule"),wt()&&_t().catch(()=>{console.error("genne-mcp-remote: failed to start; check the runtime configuration"),process.exitCode=1});export{X as DEFAULT_MAX_REQUEST_BODY_BYTES,K as REMOTE_SERVER_NAME,V as REMOTE_SERVER_VERSION,dt as createRemoteServer,et as loadRemoteConfig,ht as startRemoteServer};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var o=Object.defineProperty;var e=(n,t)=>o(n,"name",{value:t,configurable:!0});import{AsyncLocalStorage as u}from"node:async_hooks";const r=new u;function s(n,t){return r.run({signal:n},t)}e(s,"runWithRequestSignal");function a(){return r.getStore()?.signal}e(a,"currentRequestSignal");export{a as currentRequestSignal,s as runWithRequestSignal};
|
package/src/session.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var v=Object.defineProperty;var i=(e,t)=>v(e,"name",{value:t,configurable:!0});import{constants as m}from"node:fs";import{lstat as g,mkdir as S,open as T,readFile as P,rename as U,rm as y,stat as R,unlink as d}from"node:fs/promises";import{homedir as b}from"node:os";import{basename as j,join as u}from"node:path";import{randomBytes as C}from"node:crypto";import{apiOrigin as D,fail as a}from"./api.js";const H=i(e=>new Promise(t=>setTimeout(t,e)),"wait"),h="https://genne.ai";function N(e){return u(e.XDG_STATE_HOME||u(b(),".local","state"),"genne-cli")}i(N,"stateDir");function k(e){return e.GENNE_API_URL?{origin:e.GENNE_API_URL,source:"GENNE_API_URL"}:{origin:h,source:"default"}}i(k,"selectedEnvironment");function X(e){return k(e).origin}i(X,"selectedOrigin");async function M(e,t){if(t.length===1&&t[0]==="show"){const n=k(e),r=D(n.origin),o=l(r)??"custom",s=N(e),c={prod:!!await p(s,h)},f=o==="custom"?!!await p(s,r):c[o];return{data:{environment:o,origin:r,source:n.source,credential_source:e.GENNE_ACCESS_TOKEN?"GENNE_ACCESS_TOKEN":f?"saved_session":"none",sessions:c}}}a("USAGE","Use genne env show; a sele\xE7\xE3o de ambiente foi removida",2)}i(M,"environmentCommand");async function _(e){const t=N(e);await S(t,{recursive:!0,mode:448});const n=await g(t);return(!n.isDirectory()||n.isSymbolicLink()||n.mode&63)&&a("AUTH","Diret\xF3rio de sess\xE3o inseguro"),t}i(_,"ensureDirectory");function I(e){try{const[,t]=e.split("."),{exp:n}=JSON.parse(Buffer.from(t,"base64url").toString());return!Number.isInteger(n)||n*1e3<=Date.now()+6e4}catch{return!0}}i(I,"expiresSoon");function l(e){return e===h?"prod":null}i(l,"sessionName");function A(e,t){return u(e,l(t)?`session-${l(t)}.json`:"session.json")}i(A,"sessionPath");async function w(e,t,n=!1){let r;try{r=await g(e)}catch(o){if(o.code==="ENOENT")return null;throw o}(!r.isFile()||r.isSymbolicLink()||r.mode&63||process.getuid&&r.uid!==process.getuid())&&a("AUTH","Arquivo de sess\xE3o inseguro");try{const o=JSON.parse(await P(e,"utf8"));return n&&o.origin!==t?null:((o.origin!==t||typeof o.access_token!="string"||typeof o.refresh_token!="string"||!o.access_token||!o.refresh_token)&&a("AUTH","Fa\xE7a login nesta API com genne login"),{session:o,path:e})}catch(o){if(o.code==="AUTH")throw o;a("AUTH","Sess\xE3o local inv\xE1lida; fa\xE7a genne login novamente")}}i(w,"readSessionAt");async function p(e,t){const n=await w(A(e,t),t);if(n)return n;if(l(t)){const r=await w(u(e,"session.json"),t,!0);if(r)return r}return null}i(p,"readSession");async function x(e,t,n){const r=u(e,`.session-${process.pid}-${C(8).toString("hex")}`);try{const o=await T(r,m.O_WRONLY|m.O_CREAT|m.O_EXCL,384);try{await o.writeFile(JSON.stringify(n)),await o.sync()}finally{await o.close()}await U(r,u(e,t))}finally{await y(r,{force:!0})}}i(x,"writePrivateFile");async function O(e,t){if(await x(e,j(A(e,t.origin)),t),l(t.origin)){const n=await w(u(e,"session.json"),t.origin,!0);n&&await d(n.path)}}i(O,"writeSession");async function E(e,t){const n=u(e,"session.lock"),r=Date.now()+35e3;for(;;)try{await S(n,{mode:448});break}catch(o){if(o.code!=="EEXIST")throw o;let s;try{s=Date.now()-(await R(n)).mtimeMs}catch(c){if(c.code==="ENOENT")continue;throw c}s>3e4&&await y(n,{recursive:!0,force:!0}),Date.now()>r&&a("AUTH","Sess\xE3o ocupada; tente novamente"),await H(100)}try{return await t()}finally{await y(n,{recursive:!0,force:!0})}}i(E,"withLock");async function W(e,t,n){(typeof n?.token!="string"||!n.token||typeof n?.refresh_token!="string"||!n.refresh_token)&&a("RESPONSE","Resposta inv\xE1lida da API");const r=await _(e);await E(r,()=>O(r,{origin:t,access_token:n.token,refresh_token:n.refresh_token}))}i(W,"saveSession");async function q(e,t,n){const r=await _(e);await E(r,async()=>{const o=await p(r,t);if(!(n!==void 0&&o?.session.access_token!==n)&&(o&&await d(o.path),l(t))){const s=await w(u(r,"session.json"),t,!0);s&&s.path!==o?.path&&await d(s.path)}})}i(q,"clearSession");async function Y(e,t){const n=e.GENNE_ACCESS_TOKEN?.trim();if(n)return n;const r=await _(e);return E(r,async()=>{const o=await p(r,t);o||a("AUTH","Fa\xE7a genne login");const{session:s}=o;if(!I(s.access_token))return s.access_token;let c;try{c=await fetch(`${t}/api/v1/auth/refresh`,{method:"POST",redirect:"error",headers:{accept:"application/json","content-type":"application/json"},body:JSON.stringify({refresh_token:s.refresh_token}),signal:AbortSignal.timeout(15e3)})}catch{a("NETWORK","N\xE3o foi poss\xEDvel renovar a sess\xE3o")}c.ok||([400,401,403].includes(c.status)&&await d(o.path),a("AUTH","Sess\xE3o expirada; fa\xE7a genne login novamente"));let f;try{f=(await c.json()).data}catch{a("RESPONSE","Resposta inv\xE1lida da API")}return(typeof f?.token!="string"||!f.token||typeof f?.refresh_token!="string"||!f.refresh_token)&&a("RESPONSE","Resposta inv\xE1lida da API"),await O(r,{origin:t,access_token:f.token,refresh_token:f.refresh_token}),f.token})}i(Y,"accessToken");export{Y as accessToken,q as clearSession,M as environmentCommand,W as saveSession,X as selectedOrigin};
|