@getjusto/team-cli 0.0.5 → 0.0.7
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/bin/cli.js +718 -377
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -1,76 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var H={main:{local:"http://localhost:3000",develop:"https://api.bejusto.com",prod:"https://api.getjusto.com"},auth:{local:"http://localhost:4112",develop:"https://auth.service.bejusto.com",prod:"https://auth.service.getjusto.com"},webdata:{local:"http://localhost:4125",develop:"https://webdata.service.bejusto.com",prod:"https://webdatacdn.getjusto.com"},preferences:{local:"http://localhost:4120",develop:"https://preferences.service.bejusto.com",prod:"https://preferences.service.getjusto.com"},buckets:{local:"http://localhost:4106",develop:"https://buckets.service.bejusto.com",prod:"https://buckets.service.getjusto.com"},reservations:{local:"http://localhost:4113",develop:"https://reservations.service.bejusto.com",prod:"https://reservations.service.getjusto.com"},data:{local:"http://localhost:4107",develop:"https://data.service.bejusto.com",prod:"https://data.service.getjusto.com"},finances:{local:"http://localhost:4105",develop:"https://finances.service.bejusto.com",prod:"https://finances.service.getjusto.com"},"url-shortener":{local:"http://localhost:4102",develop:"https://url-shortener.service.bejusto.com",prod:"https://url-shortener.service.getjusto.com"},files:{local:"http://localhost:4108",develop:"https://files.service.bejusto.com",prod:"https://files.service.getjusto.com"},tabs:{local:"http://localhost:4115",develop:"https://tabs.service.bejusto.com",prod:"https://tabs.service.getjusto.com"},commander:{local:"http://localhost:4109",develop:"https://commander.service.bejusto.com",prod:"https://commander.service.getjusto.com"},experiments:{local:"http://localhost:4114",develop:"https://experiments.service.bejusto.com",prod:"https://experiments.service.getjusto.com"},sales:{local:"http://localhost:4117",develop:"https://sales.service.bejusto.com",prod:"https://sales.service.getjusto.com"},delivery:{local:"http://localhost:3410",develop:"https://api-delivery.bejusto.com",prod:"https://api-delivery-2.getjusto.com"},payments:{local:"http://localhost:4118",develop:"https://payments.service.bejusto.com",prod:"https://payments.service.getjusto.com"},addresses:{local:"http://localhost:4051",develop:"https://addresses.service.bejusto.com",prod:"https://addresses.service.getjusto.com"},royalty:{local:"http://localhost:4121",develop:"https://royalty.service.bejusto.com",prod:"https://royalty.service.getjusto.com"},marketing:{local:"http://localhost:4005",develop:"https://marketing.service.bejusto.com",prod:"https://marketing.service.getjusto.com"},api:{local:"http://localhost:4119",develop:"https://api.service.bejusto.com",prod:"https://api.service.getjusto.com"},messenger:{local:"http://localhost:4122",develop:"https://messenger.service.bejusto.com",prod:"https://messenger.service.getjusto.com"},invoice:{local:"http://localhost:4123",develop:"https://invoice.service.bejusto.com",prod:"https://invoice.service.getjusto.com"},"drivers-server":{local:"http://localhost:3410",develop:"https://api-delivery.bejusto.com",prod:"https://api-delivery-2.getjusto.com"}},re="prod";function be(e){re=e}function ye(){return re}function B(e){return H[e][re]}function qe(e){let o=[],r={},t={};for(let i=0;i<e.length;i++)if(e[i].startsWith("--")&&e[i+1]&&!e[i+1].startsWith("--")){let n=e[i].slice(2);if(r[n]=e[i+1],!t[n])t[n]=[];t[n].push(e[i+1]),i++}else if(e[i].startsWith("--"))r[e[i].slice(2)]="true";else o.push(e[i]);return{positional:o,flags:r,arrayFlags:t}}function T(e,o){let r=e[o];if(!r)throw Error(`--${o} es requerido.`);return r}import{existsSync as ie,mkdirSync as vo,readFileSync as Uo,writeFileSync as Qo,unlinkSync as No}from"node:fs";import{join as Ce}from"node:path";import{homedir as Po}from"node:os";var te=Ce(Po(),".justo-team");function ne(){let e=ye(),o=e==="prod"?"credentials.json":`credentials.${e}.json`;return Ce(te,o)}function So(){if(!ie(te))vo(te,{recursive:!0})}function D(e){So(),Qo(ne(),JSON.stringify(e,null,2))}function g(){let e=ne();if(!ie(e))return null;try{let o=Uo(e,"utf-8");return JSON.parse(o)}catch{return null}}function ae(){let e=ne();if(ie(e))No(e)}import{existsSync as Ie,readFileSync as Oo,writeFileSync as Wo,mkdirSync as Go}from"node:fs";import{join as he}from"node:path";import{homedir as Jo}from"node:os";function Bo(){let e=he(Jo(),".justo-team"),o=he(e,"device-id");if(Ie(o))return Oo(o,"utf-8").trim();let r=crypto.randomUUID();if(!Ie(e))Go(e,{recursive:!0});return Wo(o,r),r}var je={required:({label:e})=>`${e} no es opcional`,notAString:({label:e})=>`${e} no es un texto`,notANumber:({label:e})=>`${e} no es un número`,notAnInteger:({label:e})=>`${e} no es un número entero`,notABoolean:({label:e})=>`${e} no es un valor verdadero o falso`,notAnEmail:({label:e})=>`${e} no es un email`,notAnId:({label:e})=>`${e} no es un ID válido`,notADate:({label:e})=>`${e} no es una fecha válida`,notAnArray:({label:e})=>`${e} no es un arreglo`,notAnObject:({label:e})=>`${e} no es un objeto`,stringTooShort:({label:e})=>`${e} no tiene el largo suficiente`,stringTooLong:"El largo es mayor al permitido",numberTooSmall:({label:e})=>`${e} es un número muy pequeño`,numberTooBig:({label:e})=>`${e} es un número muy grande`,notInSchema:({label:e})=>`${e} no esta permitido`,notUnique:({label:e})=>`${e} no es único`,notFound:({label:e})=>`${e} no se encontró`,invalid:"No es válido",rateLimitExceeded:"Has excedido el límite de intentos. Intenta de nuevo más tarde.",incorrectLoginCode:"El código es incorrecto",loginCodeExpired:"El código expiró. Solicita un nuevo",loginCodeLocked:"El código se bloqueó. Genera un nuevo código para continuar",userNotFound:"No existe una cuenta con este email"};function To(e,o){let r=je[e];if(!r)return`${o}: ${e}`;if(typeof r==="function")return r({label:o});return r}function $e(e){return Object.entries(e).map(([o,r])=>To(r,o)).join(", ")}function _o(e){if(e.error==="validationError"&&e.validationErrors)return $e(e.validationErrors);if(e.extensions?.code==="PermissionsError"){let i=e.extensions.info?.type;if(i?.includes("User doesn't have permissions for "))return`Tu usuario no tiene permisos para [${i.split("User doesn't have permissions for ")[1]}]`;return e.message}if(e.validationErrors)return`${e.message} (${$e(e.validationErrors)})`;let o=e.message||"Error desconocido",r=je[o];if(r)return typeof r==="function"?r({label:""}).trim():r;let t=e.error||e.code||e.type;return t?`${o} [${t}]`:o}function Fo(e){try{return JSON.parse(Buffer.from(e.split(".")[1],"base64").toString()).exp*1000<Date.now()}catch{return!0}}async function Mo(){let e=g();if(!e?.refreshToken)return null;let o=`${B("auth")}/refresh-token`,t=await(await fetch(o,{method:"POST",headers:{"X-ORION-REFRESH":e.refreshToken}})).json();if(!t.token)return null;return D({...e,token:t.token}),t.token}async function Xo(){let e=g();if(!e?.token)return;if(!Fo(e.token))return e.token;return await Mo()??void 0}async function c(e){let o=`${B(e.service)}/graphql`,r=await Xo(),t={"Content-Type":"application/json","X-ORION-DEVICEID":Bo(),"X-ORION-PLATFORM":"web"};if(r)t["x-orion-jwt"]=r;let i;try{i=await fetch(o,{method:"POST",headers:t,body:JSON.stringify({query:e.query,variables:e.variables}),signal:AbortSignal.timeout(15000)})}catch{throw Error("La solicitud tardó demasiado. Intenta de nuevo.")}let n=await i.json();if(n.errors?.length)throw Error(_o(n.errors[0]));if(!n.data)throw Error("No data returned from server");return n.data}import{createInterface as Yo}from"node:readline";function _(e){let o=Yo({input:process.stdin,output:process.stderr});return new Promise((r)=>{o.question(e,(t)=>{o.close(),r(t.trim())})})}var Zo={comma:",",tab:"\t",pipe:"|"},Y=Zo.comma;function Ae(e){return e.replace(/\\/g,"\\\\").replace(/"/g,"\\\"").replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/\t/g,"\\t")}function zo(e){return e==="true"||e==="false"||e==="null"}function h(e){if(e===null)return null;if(typeof e==="object"&&e!==null&&"toJSON"in e&&typeof e.toJSON==="function"){let o=e.toJSON();if(o!==e)return h(o)}if(typeof e==="string"||typeof e==="boolean")return e;if(typeof e==="number"){if(Object.is(e,-0))return 0;if(!Number.isFinite(e))return null;return e}if(typeof e==="bigint"){if(e>=Number.MIN_SAFE_INTEGER&&e<=Number.MAX_SAFE_INTEGER)return Number(e);return e.toString()}if(e instanceof Date)return e.toISOString();if(Array.isArray(e))return e.map(h);if(e instanceof Set)return Array.from(e).map(h);if(e instanceof Map)return Object.fromEntries(Array.from(e,([o,r])=>[String(o),h(r)]));if(Ho(e)){let o={};for(let r in e)if(Object.prototype.hasOwnProperty.call(e,r))o[r]=h(e[r]);return o}return null}function U(e){return e===null||typeof e==="string"||typeof e==="number"||typeof e==="boolean"}function A(e){return Array.isArray(e)}function b(e){return e!==null&&typeof e==="object"&&!Array.isArray(e)}function F(e){return Object.keys(e).length===0}function Ho(e){if(e===null||typeof e!=="object")return!1;let o=Object.getPrototypeOf(e);return o===null||o===Object.prototype}function M(e){return e.length===0||e.every((o)=>U(o))}function Do(e){return e.length===0||e.every((o)=>A(o))}function xe(e){return e.length===0||e.every((o)=>b(o))}function ko(e){return/^[A-Z_][\w.]*$/i.test(e)}function Ko(e){return/^[A-Z_]\w*$/i.test(e)}function Vo(e,o=Y){if(!e)return!1;if(e!==e.trim())return!1;if(zo(e)||Lo(e))return!1;if(e.includes(":"))return!1;if(e.includes('"')||e.includes("\\"))return!1;if(/[[\]{}]/.test(e))return!1;if(/[\n\r\t]/.test(e))return!1;if(e.includes(o))return!1;if(e.startsWith("-"))return!1;return!0}function Lo(e){return/^-?\d+(?:\.\d+)?(?:e[+-]?\d+)?$/i.test(e)||/^0\d+$/.test(e)}var nt=Symbol("quotedKey");function er(e,o,r,t,i,n,a){if(t.keyFolding!=="safe")return;if(!b(o))return;let{segments:s,tail:u,leafValue:f}=or(e,o,a??t.flattenDepth);if(s.length<2)return;if(!s.every((E)=>Ko(E)))return;let p=rr(s),v=n?`${n}.${p}`:p;if(r.includes(p))return;if(i&&i.has(v))return;return{foldedKey:p,remainder:u,leafValue:f,segmentCount:s.length}}function or(e,o,r){let t=[e],i=o;while(t.length<r){if(!b(i))break;let n=Object.keys(i);if(n.length!==1)break;let a=n[0],s=i[a];t.push(a),i=s}if(!b(i)||F(i))return{segments:t,tail:void 0,leafValue:i};return{segments:t,tail:i,leafValue:i}}function rr(e){return e.join(".")}function S(e,o){if(e===null)return"null";if(typeof e==="boolean")return String(e);if(typeof e==="number")return String(e);return tr(e,o)}function tr(e,o=Y){if(Vo(e,o))return e;return`"${Ae(e)}"`}function X(e){if(ko(e))return e;return`"${Ae(e)}"`}function Re(e,o=Y){return e.map((r)=>S(r,o)).join(o)}function $(e,o){let r=o?.key,t=o?.fields,i=o?.delimiter??",",n="";if(r)n+=X(r);if(n+=`[${e}${i!==Y?i:""}]`,t){let a=t.map((s)=>X(s));n+=`{${a.join(i)}}`}return n+=":",n}function*ir(e,o,r){if(U(e)){let t=S(e,o.delimiter);if(t!=="")yield t;return}if(A(e))yield*se(void 0,e,r,o);else if(b(e))yield*P(e,r,o)}function*P(e,o,r,t,i,n){let a=Object.keys(e);if(o===0&&!t)t=new Set(a.filter((u)=>u.includes(".")));let s=n??r.flattenDepth;for(let[u,f]of Object.entries(e))yield*nr(u,f,o,r,a,t,i,s)}function*nr(e,o,r,t,i,n,a,s){let u=a?`${a}.${e}`:e,f=s??t.flattenDepth;if(t.keyFolding==="safe"&&i){let v=er(e,o,i,t,n,a,f);if(v){let{foldedKey:E,remainder:J,leafValue:N,segmentCount:Ao}=v,oe=X(E);if(J===void 0){if(U(N)){yield w(r,`${oe}: ${S(N,t.delimiter)}`,t.indent);return}else if(A(N)){yield*se(E,N,r,t);return}else if(b(N)&&F(N)){yield w(r,`${oe}:`,t.indent);return}}if(b(J)){yield w(r,`${oe}:`,t.indent);let xo=f-Ao,Ro=a?`${a}.${E}`:E;yield*P(J,r+1,t,n,Ro,xo);return}}}let p=X(e);if(U(o))yield w(r,`${p}: ${S(o,t.delimiter)}`,t.indent);else if(A(o))yield*se(e,o,r,t);else if(b(o)){if(yield w(r,`${p}:`,t.indent),!F(o))yield*P(o,r+1,t,n,u,f)}}function*se(e,o,r,t){if(o.length===0){yield w(r,$(0,{key:e,delimiter:t.delimiter}),t.indent);return}if(M(o)){yield w(r,K(o,t.delimiter,e),t.indent);return}if(Do(o)){if(o.every((i)=>M(i))){yield*ar(e,o,r,t);return}}if(xe(o)){let i=ve(o);if(i)yield*sr(e,o,i,r,t);else yield*Ee(e,o,r,t);return}yield*Ee(e,o,r,t)}function*ar(e,o,r,t){yield w(r,$(o.length,{key:e,delimiter:t.delimiter}),t.indent);for(let i of o)if(M(i)){let n=K(i,t.delimiter);yield C(r+1,n,t.indent)}}function K(e,o,r){let t=$(e.length,{key:r,delimiter:o}),i=Re(e,o);if(e.length===0)return t;return`${t} ${i}`}function*sr(e,o,r,t,i){yield w(t,$(o.length,{key:e,fields:r,delimiter:i.delimiter}),i.indent),yield*Ue(o,r,t+1,i)}function ve(e){if(e.length===0)return;let o=e[0],r=Object.keys(o);if(r.length===0)return;if(cr(e,r))return r}function cr(e,o){for(let r of e){if(Object.keys(r).length!==o.length)return!1;for(let t of o){if(!(t in r))return!1;if(!U(r[t]))return!1}}return!0}function*Ue(e,o,r,t){for(let i of e)yield w(r,Re(o.map((n)=>i[n]),t.delimiter),t.indent)}function*Ee(e,o,r,t){yield w(r,$(o.length,{key:e,delimiter:t.delimiter}),t.indent);for(let i of o)yield*ce(i,r+1,t)}function*mr(e,o,r){if(F(e)){yield w(o,"-",r.indent);return}let t=Object.entries(e),[i,n]=t[0],a=t.slice(1);if(A(n)&&xe(n)){let u=ve(n);if(u){if(yield C(o,$(n.length,{key:i,fields:u,delimiter:r.delimiter}),r.indent),yield*Ue(n,u,o+2,r),a.length>0)yield*P(Object.fromEntries(a),o+1,r);return}}let s=X(i);if(U(n))yield C(o,`${s}: ${S(n,r.delimiter)}`,r.indent);else if(A(n))if(n.length===0)yield C(o,`${s}${$(0,{delimiter:r.delimiter})}`,r.indent);else if(M(n))yield C(o,`${s}${K(n,r.delimiter)}`,r.indent);else{yield C(o,`${s}${$(n.length,{delimiter:r.delimiter})}`,r.indent);for(let u of n)yield*ce(u,o+2,r)}else if(b(n)){if(yield C(o,`${s}:`,r.indent),!F(n))yield*P(n,o+2,r)}if(a.length>0)yield*P(Object.fromEntries(a),o+1,r)}function*ce(e,o,r){if(U(e))yield C(o,S(e,r.delimiter),r.indent);else if(A(e))if(M(e))yield C(o,K(e,r.delimiter),r.indent);else{yield C(o,$(e.length,{delimiter:r.delimiter}),r.indent);for(let t of e)yield*ce(t,o+1,r)}else if(b(e))yield*mr(e,o,r)}function w(e,o,r){return" ".repeat(r*e)+o}function C(e,o,r){return w(e,"- "+o,r)}function ur(e,o){let r=o("",e,[]);if(r===void 0)return k(e,o,[]);return k(h(r),o,[])}function k(e,o,r){if(b(e))return dr(e,o,r);if(A(e))return lr(e,o,r);return e}function dr(e,o,r){let t={};for(let[i,n]of Object.entries(e)){let a=[...r,i],s=o(i,n,a);if(s===void 0)continue;t[i]=k(h(s),o,a)}return t}function lr(e,o,r){let t=[];for(let i=0;i<e.length;i++){let n=e[i],a=[...r,i],s=o(String(i),n,a);if(s===void 0)continue;let u=h(s);t.push(k(u,o,a))}return t}function me(e,o){return Array.from(gr(e,o)).join(`
|
|
3
|
-
`)}function
|
|
4
|
-
`)}function
|
|
5
|
-
requestLoginCode(email: $email)
|
|
6
|
-
}`,variables:{email:e}})).requestLoginCode}async function Se(e,o,r){let t=await c({service:"auth",query:`mutation ($email: String!, $token: String!, $code: String!) {
|
|
7
|
-
loginWithCode(email: $email, token: $token, code: $code) {
|
|
8
|
-
token
|
|
9
|
-
refreshToken
|
|
10
|
-
}
|
|
11
|
-
}`,variables:{email:e,token:o,code:r.toUpperCase()}});D({email:e,token:t.loginWithCode.token,refreshToken:t.loginWithCode.refreshToken}),await fr()}async function fr(){if(!(await c({service:"main",query:"query { me { roles } }"})).me?.roles?.length)throw ae(),Error("Solo miembros del equipo Justo pueden usar esta herramienta.")}async function Oe(){let e=await _("Email: ");y(`Enviando codigo de verificacion...
|
|
12
|
-
`);let o=await Pe(e);y(`Codigo enviado a tu email.
|
|
13
|
-
`);let r=await _("Codigo: ");return await Se(e,o,r),{ok:!0,authenticated:!0,email:e}}async function We(e){let o=T(e,"email"),r=T(e,"token"),t=T(e,"code");return await Se(o,r,t),{ok:!0,authenticated:!0,email:o}}async function Ge(e){let o=T(e,"email");y(`Enviando codigo de verificacion...
|
|
14
|
-
`);let r=await Pe(o);return{ok:!0,email:o,token:r,nextCommand:`npx @getjusto/team-cli auth login-with-token --email ${o} --token ${r} --code <CODIGO>`}}async function Je(){return ae(),{ok:!0,authenticated:!1}}async function Be(){let e=g();if(!e)return{authenticated:!1,loginCommand:"npx @getjusto/team-cli@latest auth login"};return{authenticated:!0,email:e.email}}function ue(){return`team-cli auth
|
|
15
|
-
|
|
16
|
-
Gestion de sesion.
|
|
17
|
-
|
|
18
|
-
Uso:
|
|
19
|
-
team-cli auth <subcomando> [opciones]
|
|
20
|
-
|
|
21
|
-
Subcomandos:
|
|
22
|
-
login
|
|
23
|
-
Iniciar sesion en modo interactivo.
|
|
24
|
-
Uso: team-cli auth login
|
|
25
|
-
|
|
26
|
-
logout
|
|
27
|
-
Cerrar sesion actual.
|
|
28
|
-
Uso: team-cli auth logout
|
|
29
|
-
|
|
30
|
-
status
|
|
31
|
-
Ver la sesion actual.
|
|
32
|
-
Uso: team-cli auth status
|
|
33
|
-
|
|
34
|
-
request-code
|
|
35
|
-
Solicitar codigo para login no interactivo.
|
|
36
|
-
Uso: team-cli auth request-code --email <email>
|
|
37
|
-
|
|
38
|
-
login-with-token
|
|
39
|
-
Iniciar sesion sin prompts.
|
|
40
|
-
Uso: team-cli auth login-with-token --email <email> --token <token> --code <codigo>`}var de=["main","auth","webdata","preferences","buckets","reservations","data","finances","url-shortener","files","tabs","commander","experiments","sales","delivery","payments","addresses","royalty","marketing","api","messenger","invoice","drivers-server"],Te=`
|
|
41
|
-
query ResolverInfo($name: ID!, $mutation: Boolean!) {
|
|
42
|
-
params(name: $name, mutation: $mutation) {
|
|
43
|
-
name
|
|
44
|
-
params
|
|
45
|
-
result
|
|
46
|
-
basicResultQuery
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
`;function br(e){if(!e)throw Error("Uso: team-cli graphql <servicio> '<query>' [--variables '<json>'] [--format toon|json]");if(!de.includes(e))throw Error(`Servicio "${e}" no válido. Servicios disponibles: ${de.join(", ")}`)}async function yr(e,o){let r;try{let t=await c({service:e,query:Te,variables:{name:o,mutation:!1}});return{service:e,operationName:o,operationType:"query",info:t.params}}catch(t){r=t}try{let t=await c({service:e,query:Te,variables:{name:o,mutation:!0}});return{service:e,operationName:o,operationType:"mutation",info:t.params}}catch(t){let i=r instanceof Error?r.message:"",n=t instanceof Error?t.message:"";if(i.includes('Cannot query field "params"')||n.includes('Cannot query field "params"'))throw Error(`El servicio "${e}" no expone metadata de resolvers por GraphQL.`);throw r instanceof Error?r:t}}async function _e(e,o){let r=e[1],t=e[2],i=e[2];if(!g())throw Error("Debes iniciar sesión primero. Usa: team-cli auth login");if(br(r),t==="info"){let s=e[3];if(!s)throw Error("Uso: team-cli graphql <servicio> info <queryName|mutationName> [--format toon|json]");return await yr(r,s)}if(!i)throw Error("Uso: team-cli graphql <servicio> '<query>' [--variables '<json>'] [--format toon|json]");let n;if(o.variables)try{n=JSON.parse(o.variables)}catch{throw Error("Las variables deben ser un JSON válido.")}return await c({service:r,query:i,variables:n})}function Fe(){return`team-cli graphql
|
|
50
|
-
|
|
51
|
-
Ejecutar queries y mutations GraphQL.
|
|
52
|
-
|
|
53
|
-
Uso:
|
|
54
|
-
team-cli graphql <servicio> '<query>' [--variables '<json>'] [--format toon|json]
|
|
55
|
-
team-cli graphql <servicio> info <queryName|mutationName> [--format toon|json]
|
|
56
|
-
|
|
57
|
-
Ejemplos:
|
|
58
|
-
team-cli graphql main 'query { me { _id roles } }'
|
|
59
|
-
team-cli graphql main 'query($id: ID) { user(userId: $id) { _id } }' --variables '{"id": "abc123"}'
|
|
60
|
-
team-cli graphql main 'query { me { _id } }' --format json
|
|
61
|
-
team-cli graphql main info website
|
|
62
|
-
team-cli graphql webdata info setWebsiteTheme --format json
|
|
63
|
-
|
|
64
|
-
Servicios disponibles:
|
|
65
|
-
${de.join(", ")}
|
|
66
|
-
|
|
67
|
-
Comando info:
|
|
68
|
-
Consulta la metadata publicada por OrionJS para un query o mutation.
|
|
69
|
-
Devuelve el tipo de operación, los params serializados, el resultado y un basicResultQuery.
|
|
70
|
-
Si no indicas si es query o mutation, la CLI prueba ambas automáticamente.
|
|
71
|
-
|
|
72
|
-
Formato:
|
|
73
|
-
Por defecto usa toon. Usa --format json para JSON estándar.`}function qr(e){return e.replace(/^https?:\/\//,"").replace(/^www\./,"").replace(/\/.*$/,"")}function Cr(e){return e.includes(".")||e.startsWith("http://")||e.startsWith("https://")}async function O(e){if(Cr(e)){let o=qr(e),r=await fetch(`${B("main")}/website-id/${o}`,{signal:AbortSignal.timeout(1e4)});if(!r.ok)throw Error(`No se encontro el sitio "${o}"`);let t=await r.json();if(!t.websiteId)throw Error(`No se pudo resolver el websiteId para "${o}"`);return{input:e,websiteId:t.websiteId,targetType:"domain"}}return{input:e,websiteId:e,targetType:"websiteId"}}async function Me(e){let o=await c({service:"main",query:`query ($websiteId: ID) {
|
|
2
|
+
function re(e){let t=[],o={},r={};for(let a=0;a<e.length;a++)if(e[a].startsWith("--")&&e[a+1]&&!e[a+1].startsWith("--")){let n=e[a].slice(2);if(o[n]=e[a+1],!r[n])r[n]=[];r[n].push(e[a+1]),a++}else if(e[a].startsWith("--"))o[e[a].slice(2)]="true";else t.push(e[a]);return{positional:t,flags:o,arrayFlags:r}}function F(e,t){let o=e[t];if(!o)throw Error(`--${t} es requerido.`);return o}var Mo={comma:",",tab:"\t",pipe:"|"},Y=Mo.comma;function Xe(e){return e.replace(/\\/g,"\\\\").replace(/"/g,"\\\"").replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/\t/g,"\\t")}function Po(e){return e==="true"||e==="false"||e==="null"}function E(e){if(e===null)return null;if(typeof e==="object"&&e!==null&&"toJSON"in e&&typeof e.toJSON==="function"){let t=e.toJSON();if(t!==e)return E(t)}if(typeof e==="string"||typeof e==="boolean")return e;if(typeof e==="number"){if(Object.is(e,-0))return 0;if(!Number.isFinite(e))return null;return e}if(typeof e==="bigint"){if(e>=Number.MIN_SAFE_INTEGER&&e<=Number.MAX_SAFE_INTEGER)return Number(e);return e.toString()}if(e instanceof Date)return e.toISOString();if(Array.isArray(e))return e.map(E);if(e instanceof Set)return Array.from(e).map(E);if(e instanceof Map)return Object.fromEntries(Array.from(e,([t,o])=>[String(t),E(o)]));if(Go(e)){let t={};for(let o in e)if(Object.prototype.hasOwnProperty.call(e,o))t[o]=E(e[o]);return t}return null}function U(e){return e===null||typeof e==="string"||typeof e==="number"||typeof e==="boolean"}function T(e){return Array.isArray(e)}function q(e){return e!==null&&typeof e==="object"&&!Array.isArray(e)}function X(e){return Object.keys(e).length===0}function Go(e){if(e===null||typeof e!=="object")return!1;let t=Object.getPrototypeOf(e);return t===null||t===Object.prototype}function H(e){return e.length===0||e.every((t)=>U(t))}function Fo(e){return e.length===0||e.every((t)=>T(t))}function He(e){return e.length===0||e.every((t)=>q(t))}function Xo(e){return/^[A-Z_][\w.]*$/i.test(e)}function Ho(e){return/^[A-Z_]\w*$/i.test(e)}function Zo(e,t=Y){if(!e)return!1;if(e!==e.trim())return!1;if(Po(e)||Yo(e))return!1;if(e.includes(":"))return!1;if(e.includes('"')||e.includes("\\"))return!1;if(/[[\]{}]/.test(e))return!1;if(/[\n\r\t]/.test(e))return!1;if(e.includes(t))return!1;if(e.startsWith("-"))return!1;return!0}function Yo(e){return/^-?\d+(?:\.\d+)?(?:e[+-]?\d+)?$/i.test(e)||/^0\d+$/.test(e)}var Ha=Symbol("quotedKey");function Do(e,t,o,r,a,n,i){if(r.keyFolding!=="safe")return;if(!q(t))return;let{segments:s,tail:c,leafValue:m}=zo(e,t,i??r.flattenDepth);if(s.length<2)return;if(!s.every((p)=>Ho(p)))return;let l=ko(s),g=n?`${n}.${l}`:l;if(o.includes(l))return;if(a&&a.has(g))return;return{foldedKey:l,remainder:c,leafValue:m,segmentCount:s.length}}function zo(e,t,o){let r=[e],a=t;while(r.length<o){if(!q(a))break;let n=Object.keys(a);if(n.length!==1)break;let i=n[0],s=a[i];r.push(i),a=s}if(!q(a)||X(a))return{segments:r,tail:void 0,leafValue:a};return{segments:r,tail:a,leafValue:a}}function ko(e){return e.join(".")}function B(e,t){if(e===null)return"null";if(typeof e==="boolean")return String(e);if(typeof e==="number")return String(e);return Ko(e,t)}function Ko(e,t=Y){if(Zo(e,t))return e;return`"${Xe(e)}"`}function Z(e){if(Xo(e))return e;return`"${Xe(e)}"`}function Ze(e,t=Y){return e.map((o)=>B(o,t)).join(t)}function j(e,t){let o=t?.key,r=t?.fields,a=t?.delimiter??",",n="";if(o)n+=Z(o);if(n+=`[${e}${a!==Y?a:""}]`,r){let i=r.map((s)=>Z(s));n+=`{${i.join(a)}}`}return n+=":",n}function*Vo(e,t,o){if(U(e)){let r=B(e,t.delimiter);if(r!=="")yield r;return}if(T(e))yield*he(void 0,e,o,t);else if(q(e))yield*_(e,o,t)}function*_(e,t,o,r,a,n){let i=Object.keys(e);if(t===0&&!r)r=new Set(i.filter((c)=>c.includes(".")));let s=n??o.flattenDepth;for(let[c,m]of Object.entries(e))yield*Lo(c,m,t,o,i,r,a,s)}function*Lo(e,t,o,r,a,n,i,s){let c=i?`${i}.${e}`:e,m=s??r.flattenDepth;if(r.keyFolding==="safe"&&a){let g=Do(e,t,a,r,n,i,m);if(g){let{foldedKey:p,remainder:y,leafValue:w,segmentCount:oe}=g,W=Z(p);if(y===void 0){if(U(w)){yield b(o,`${W}: ${B(w,r.delimiter)}`,r.indent);return}else if(T(w)){yield*he(p,w,o,r);return}else if(q(w)&&X(w)){yield b(o,`${W}:`,r.indent);return}}if(q(y)){yield b(o,`${W}:`,r.indent);let R=m-oe,G=i?`${i}.${p}`:p;yield*_(y,o+1,r,n,G,R);return}}}let l=Z(e);if(U(t))yield b(o,`${l}: ${B(t,r.delimiter)}`,r.indent);else if(T(t))yield*he(e,t,o,r);else if(q(t)){if(yield b(o,`${l}:`,r.indent),!X(t))yield*_(t,o+1,r,n,c,m)}}function*he(e,t,o,r){if(t.length===0){yield b(o,j(0,{key:e,delimiter:r.delimiter}),r.indent);return}if(H(t)){yield b(o,ne(t,r.delimiter,e),r.indent);return}if(Fo(t)){if(t.every((a)=>H(a))){yield*er(e,t,o,r);return}}if(He(t)){let a=Ye(t);if(a)yield*tr(e,t,a,o,r);else yield*Fe(e,t,o,r);return}yield*Fe(e,t,o,r)}function*er(e,t,o,r){yield b(o,j(t.length,{key:e,delimiter:r.delimiter}),r.indent);for(let a of t)if(H(a)){let n=ne(a,r.delimiter);yield x(o+1,n,r.indent)}}function ne(e,t,o){let r=j(e.length,{key:o,delimiter:t}),a=Ze(e,t);if(e.length===0)return r;return`${r} ${a}`}function*tr(e,t,o,r,a){yield b(r,j(t.length,{key:e,fields:o,delimiter:a.delimiter}),a.indent),yield*De(t,o,r+1,a)}function Ye(e){if(e.length===0)return;let t=e[0],o=Object.keys(t);if(o.length===0)return;if(or(e,o))return o}function or(e,t){for(let o of e){if(Object.keys(o).length!==t.length)return!1;for(let r of t){if(!(r in o))return!1;if(!U(o[r]))return!1}}return!0}function*De(e,t,o,r){for(let a of e)yield b(o,Ze(t.map((n)=>a[n]),r.delimiter),r.indent)}function*Fe(e,t,o,r){yield b(o,j(t.length,{key:e,delimiter:r.delimiter}),r.indent);for(let a of t)yield*$e(a,o+1,r)}function*rr(e,t,o){if(X(e)){yield b(t,"-",o.indent);return}let r=Object.entries(e),[a,n]=r[0],i=r.slice(1);if(T(n)&&He(n)){let c=Ye(n);if(c){if(yield x(t,j(n.length,{key:a,fields:c,delimiter:o.delimiter}),o.indent),yield*De(n,c,t+2,o),i.length>0)yield*_(Object.fromEntries(i),t+1,o);return}}let s=Z(a);if(U(n))yield x(t,`${s}: ${B(n,o.delimiter)}`,o.indent);else if(T(n))if(n.length===0)yield x(t,`${s}${j(0,{delimiter:o.delimiter})}`,o.indent);else if(H(n))yield x(t,`${s}${ne(n,o.delimiter)}`,o.indent);else{yield x(t,`${s}${j(n.length,{delimiter:o.delimiter})}`,o.indent);for(let c of n)yield*$e(c,t+2,o)}else if(q(n)){if(yield x(t,`${s}:`,o.indent),!X(n))yield*_(n,t+2,o)}if(i.length>0)yield*_(Object.fromEntries(i),t+1,o)}function*$e(e,t,o){if(U(e))yield x(t,B(e,o.delimiter),o.indent);else if(T(e))if(H(e))yield x(t,ne(e,o.delimiter),o.indent);else{yield x(t,j(e.length,{delimiter:o.delimiter}),o.indent);for(let r of e)yield*$e(r,t+1,o)}else if(q(e))yield*rr(e,t,o)}function b(e,t,o){return" ".repeat(o*e)+t}function x(e,t,o){return b(e,"- "+t,o)}function ar(e,t){let o=t("",e,[]);if(o===void 0)return ae(e,t,[]);return ae(E(o),t,[])}function ae(e,t,o){if(q(e))return nr(e,t,o);if(T(e))return ir(e,t,o);return e}function nr(e,t,o){let r={};for(let[a,n]of Object.entries(e)){let i=[...o,a],s=t(a,n,i);if(s===void 0)continue;r[a]=ae(E(s),t,i)}return r}function ir(e,t,o){let r=[];for(let a=0;a<e.length;a++){let n=e[a],i=[...o,a],s=t(String(a),n,i);if(s===void 0)continue;let c=E(s);r.push(ae(c,t,i))}return r}function xe(e,t){return Array.from(sr(e,t)).join(`
|
|
3
|
+
`)}function sr(e,t){let o=E(e),r=cr(t);return Vo(r.replacer?ar(o,r.replacer):o,r,0)}function cr(e){return{indent:e?.indent??2,delimiter:e?.delimiter??Y,keyFolding:e?.keyFolding??"off",flattenDepth:e?.flattenDepth??Number.POSITIVE_INFINITY,replacer:e?.replacer}}function ur(e){let t=e.format??"toon";if(t!=="toon"&&t!=="json")throw Error("--format debe ser toon o json.");return t}function ze(e,t){if(ur(t)==="json"){console.log(JSON.stringify(e,null,2));return}console.log(xe(e))}function ke(e){process.stdout.write(`${e}
|
|
4
|
+
`)}function Ke(e,t){let r={ok:!1,error:e instanceof Error?e.message:String(e)};if((t.format==="json"?"json":"toon")==="json"){console.error(JSON.stringify(r,null,2));return}console.error(xe(r))}function C(e){process.stderr.write(e)}import{existsSync as ce,mkdirSync as dr,readFileSync as Le,writeFileSync as pr,unlinkSync as gr}from"node:fs";import{join as et}from"node:path";import{homedir as fr}from"node:os";import{AsyncLocalStorage as mr}from"node:async_hooks";var lr=new mr;function I(){return lr.getStore()}var ie={main:{local:"http://localhost:3000",develop:"https://api.bejusto.com",prod:"https://api.getjusto.com"},auth:{local:"http://localhost:4112",develop:"https://auth.service.bejusto.com",prod:"https://auth.service.getjusto.com"},webdata:{local:"http://localhost:4125",develop:"https://webdata.service.bejusto.com",prod:"https://webdatacdn.getjusto.com"},preferences:{local:"http://localhost:4120",develop:"https://preferences.service.bejusto.com",prod:"https://preferences.service.getjusto.com"},buckets:{local:"http://localhost:4106",develop:"https://buckets.service.bejusto.com",prod:"https://buckets.service.getjusto.com"},reservations:{local:"http://localhost:4113",develop:"https://reservations.service.bejusto.com",prod:"https://reservations.service.getjusto.com"},data:{local:"http://localhost:4107",develop:"https://data.service.bejusto.com",prod:"https://data.service.getjusto.com"},finances:{local:"http://localhost:4105",develop:"https://finances.service.bejusto.com",prod:"https://finances.service.getjusto.com"},"url-shortener":{local:"http://localhost:4102",develop:"https://url-shortener.service.bejusto.com",prod:"https://url-shortener.service.getjusto.com"},files:{local:"http://localhost:4108",develop:"https://files.service.bejusto.com",prod:"https://files.service.getjusto.com"},tabs:{local:"http://localhost:4115",develop:"https://tabs.service.bejusto.com",prod:"https://tabs.service.getjusto.com"},commander:{local:"http://localhost:4109",develop:"https://commander.service.bejusto.com",prod:"https://commander.service.getjusto.com"},experiments:{local:"http://localhost:4114",develop:"https://experiments.service.bejusto.com",prod:"https://experiments.service.getjusto.com"},sales:{local:"http://localhost:4117",develop:"https://sales.service.bejusto.com",prod:"https://sales.service.getjusto.com"},delivery:{local:"http://localhost:3410",develop:"https://api-delivery.bejusto.com",prod:"https://api-delivery-2.getjusto.com"},payments:{local:"http://localhost:4118",develop:"https://payments.service.bejusto.com",prod:"https://payments.service.getjusto.com"},addresses:{local:"http://localhost:4051",develop:"https://addresses.service.bejusto.com",prod:"https://addresses.service.getjusto.com"},royalty:{local:"http://localhost:4121",develop:"https://royalty.service.bejusto.com",prod:"https://royalty.service.getjusto.com"},marketing:{local:"http://localhost:4005",develop:"https://marketing.service.bejusto.com",prod:"https://marketing.service.getjusto.com"},api:{local:"http://localhost:4119",develop:"https://api.service.bejusto.com",prod:"https://api.service.getjusto.com"},messenger:{local:"http://localhost:4122",develop:"https://messenger.service.bejusto.com",prod:"https://messenger.service.getjusto.com"},invoice:{local:"http://localhost:4123",develop:"https://invoice.service.bejusto.com",prod:"https://invoice.service.getjusto.com"},"drivers-server":{local:"http://localhost:3410",develop:"https://api-delivery.bejusto.com",prod:"https://api-delivery-2.getjusto.com"}},Se="prod";function Ve(e){Se=e}function se(){let e=process.env.JUSTO_TEAM_CLI_ENV;if(e)return e;let t=I()?.environment;if(t)return t;return Se}function h(e){return ie[e][Se]}var Ee=et(fr(),".justo-team");function tt(e){let t=e==="prod"?"credentials.json":`credentials.${e}.json`;return et(Ee,t)}function je(){return tt(se())}function wr(){if(!ce(Ee))dr(Ee,{recursive:!0})}function ue(e){let t=I();if(t&&t.canPersistCredentials===!1)throw Error("Este entorno no permite guardar credenciales.");wr(),pr(je(),JSON.stringify(e,null,2))}function d(){let e=process.env.JUSTO_TEAM_CLI_TOKEN,t=process.env.JUSTO_TEAM_CLI_EMAIL,o=process.env.JUSTO_TEAM_CLI_REFRESH_TOKEN;if(e&&t)return{email:t,token:e,refreshToken:o||""};let r=I()?.credentials;if(r!==void 0)return r?{email:r.email,token:r.token,refreshToken:r.refreshToken||""}:null;let a=je();if(!ce(a))return null;try{let n=Le(a,"utf-8");return JSON.parse(n)}catch{return null}}function ot(e){let t=tt(e);if(!ce(t))return null;try{let o=Le(t,"utf-8");return JSON.parse(o)}catch{return null}}function Ae(){let e=I();if(e&&e.canPersistCredentials===!1)throw Error("Este entorno no permite borrar credenciales.");let t=je();if(ce(t))gr(t)}import{existsSync as rt,readFileSync as br,writeFileSync as Cr,mkdirSync as yr}from"node:fs";import{join as at}from"node:path";import{homedir as qr}from"node:os";function Ir(){let e=process.env.JUSTO_TEAM_CLI_DEVICE_ID;if(e)return e;let t=I()?.deviceId;if(t)return t;let o=at(qr(),".justo-team"),r=at(o,"device-id");if(rt(r))return br(r,"utf-8").trim();let a=crypto.randomUUID();if(!rt(o))yr(o,{recursive:!0});return Cr(r,a),a}var it={required:({label:e})=>`${e} no es opcional`,notAString:({label:e})=>`${e} no es un texto`,notANumber:({label:e})=>`${e} no es un número`,notAnInteger:({label:e})=>`${e} no es un número entero`,notABoolean:({label:e})=>`${e} no es un valor verdadero o falso`,notAnEmail:({label:e})=>`${e} no es un email`,notAnId:({label:e})=>`${e} no es un ID válido`,notADate:({label:e})=>`${e} no es una fecha válida`,notAnArray:({label:e})=>`${e} no es un arreglo`,notAnObject:({label:e})=>`${e} no es un objeto`,stringTooShort:({label:e})=>`${e} no tiene el largo suficiente`,stringTooLong:"El largo es mayor al permitido",numberTooSmall:({label:e})=>`${e} es un número muy pequeño`,numberTooBig:({label:e})=>`${e} es un número muy grande`,notInSchema:({label:e})=>`${e} no esta permitido`,notUnique:({label:e})=>`${e} no es único`,notFound:({label:e})=>`${e} no se encontró`,invalid:"No es válido",rateLimitExceeded:"Has excedido el límite de intentos. Intenta de nuevo más tarde.",incorrectLoginCode:"El código es incorrecto",loginCodeExpired:"El código expiró. Solicita un nuevo",loginCodeLocked:"El código se bloqueó. Genera un nuevo código para continuar",userNotFound:"No existe una cuenta con este email"};function hr(e,t){let o=it[e];if(!o)return`${t}: ${e}`;if(typeof o==="function")return o({label:t});return o}function nt(e){return Object.entries(e).map(([t,o])=>hr(o,t)).join(", ")}function $r(e){if(e.error==="validationError"&&e.validationErrors)return nt(e.validationErrors);if(e.extensions?.code==="PermissionsError"){let a=e.extensions.info?.type;if(a?.includes("User doesn't have permissions for "))return`Tu usuario no tiene permisos para [${a.split("User doesn't have permissions for ")[1]}]`;return e.message}if(e.validationErrors)return`${e.message} (${nt(e.validationErrors)})`;let t=e.message||"Error desconocido",o=it[t];if(o)return typeof o==="function"?o({label:""}).trim():o;let r=e.error||e.code||e.type;return r?`${t} [${r}]`:t}function xr(e){try{return JSON.parse(Buffer.from(e.split(".")[1],"base64").toString()).exp*1000<Date.now()}catch{return!0}}async function Sr(){let e=d();if(!e?.refreshToken)return null;let t=`${h("auth")}/refresh-token`,r=await(await fetch(t,{method:"POST",headers:{"X-ORION-REFRESH":e.refreshToken}})).json();if(!r.token)return null;if(I()?.canPersistCredentials!==!1)ue({...e,token:r.token});return r.token}async function Ne(){let e=d();if(!e?.token)return;if(!xr(e.token))return e.token;return await Sr()??void 0}async function ve(e="application/json"){let t=await Ne(),o={"Content-Type":e,"X-ORION-DEVICEID":Ir(),"X-ORION-PLATFORM":"web"};if(t)o["x-orion-jwt"]=t;return o}async function u(e){let t=`${h(e.service)}/graphql`,o=await ve(),r;try{r=await fetch(t,{method:"POST",headers:o,body:JSON.stringify({query:e.query,variables:e.variables}),signal:AbortSignal.timeout(15000)})}catch{throw Error("La solicitud tardó demasiado. Intenta de nuevo.")}let a=await r.json();if(a.errors?.length)throw Error($r(a.errors[0]));if(!a.data)throw Error("No data returned from server");return a.data}function Er(e){return e.replace(/^https?:\/\//,"").replace(/^www\./,"").replace(/\/.*$/,"")}function jr(e){return e.includes(".")||e.startsWith("http://")||e.startsWith("https://")}async function M(e){if(jr(e)){let t=Er(e),o=await fetch(`${h("main")}/website-id/${t}`,{signal:AbortSignal.timeout(1e4)});if(!o.ok)throw Error(`No se encontro el sitio "${t}"`);let r=await o.json();if(!r.websiteId)throw Error(`No se pudo resolver el websiteId para "${t}"`);return{input:e,websiteId:r.websiteId,targetType:"domain"}}return{input:e,websiteId:e,targetType:"websiteId"}}async function st(e){let t=await u({service:"main",query:`query ($websiteId: ID) {
|
|
74
5
|
website(websiteId: $websiteId) {
|
|
75
6
|
_id
|
|
76
7
|
name
|
|
@@ -82,7 +13,7 @@ Formato:
|
|
|
82
13
|
timezone
|
|
83
14
|
defaultMenuId
|
|
84
15
|
}
|
|
85
|
-
}`,variables:{websiteId:e}});if(!
|
|
16
|
+
}`,variables:{websiteId:e}});if(!t.website)throw Error(`No se encontro el website "${e}"`);return t.website}function Ar(){if(!d())throw Error("Debes iniciar sesión primero. Recomendado: team-cli auth request-code --email <email> y luego team-cli auth login-with-token --email <email> --token <token> --code <CODIGO>")}async function ct(e){if(Ar(),!e)throw Error("Uso: team-cli admin <websiteId|domain> show");let t=await M(e),o=await st(t.websiteId);return{context:t,website:o}}function me(){return`team-cli admin
|
|
86
17
|
|
|
87
18
|
Comandos administrativos con contexto de website.
|
|
88
19
|
|
|
@@ -104,7 +35,7 @@ Modulos:
|
|
|
104
35
|
|
|
105
36
|
coupons
|
|
106
37
|
Administrar cupones y sus códigos.
|
|
107
|
-
Uso: team-cli admin <websiteId|domain> coupons <accion> [opciones]`}var
|
|
38
|
+
Uso: team-cli admin <websiteId|domain> coupons <accion> [opciones]`}var ut=`
|
|
108
39
|
availableAtPeriods
|
|
109
40
|
closedDays
|
|
110
41
|
closedUntilDate
|
|
@@ -120,7 +51,7 @@ Modulos:
|
|
|
120
51
|
fromMinute
|
|
121
52
|
toMinute
|
|
122
53
|
}
|
|
123
|
-
`,
|
|
54
|
+
`,le=`
|
|
124
55
|
_id
|
|
125
56
|
websiteId
|
|
126
57
|
name
|
|
@@ -155,13 +86,13 @@ Modulos:
|
|
|
155
86
|
requiredBINs
|
|
156
87
|
extraRequirementsForPaymentTypes
|
|
157
88
|
schedule {
|
|
158
|
-
${
|
|
89
|
+
${ut}
|
|
159
90
|
}
|
|
160
91
|
scheduleAtUse {
|
|
161
|
-
${
|
|
92
|
+
${ut}
|
|
162
93
|
}
|
|
163
94
|
codesCode
|
|
164
|
-
`,
|
|
95
|
+
`,mt=`
|
|
165
96
|
_id
|
|
166
97
|
code
|
|
167
98
|
couponId
|
|
@@ -170,64 +101,55 @@ Modulos:
|
|
|
170
101
|
sentToEmail
|
|
171
102
|
totalRedemptions
|
|
172
103
|
createdAt
|
|
173
|
-
`;function
|
|
104
|
+
`;function Re(){if(!d())throw Error("Debes iniciar sesión primero. Recomendado: team-cli auth request-code --email <email> y luego team-cli auth login-with-token --email <email> --token <token> --code <CODIGO>")}function P(e,t){let o=e[t];if(!o)throw Error(`--${t} es requerido.`);try{return JSON.parse(o)}catch{throw Error(`--${t} debe ser un JSON válido.`)}}function S(e,t){let o=e[t];if(!o)return;let r=Number.parseInt(o,10);if(Number.isNaN(r))throw Error(`--${t} debe ser un número entero.`);return r}function lt(e,t){let o=e[t];if(!o)return;if(o==="true")return!0;if(o==="false")return!1;throw Error(`--${t} debe ser true o false.`)}async function $(e){if(Re(),!e)throw Error("Debes indicar <websiteId|domain>.");return M(e)}async function A(e,t){let o=await u({service:"main",query:`query ($couponId: ID) {
|
|
174
105
|
coupon(couponId: $couponId) {
|
|
175
106
|
_id
|
|
176
107
|
websiteId
|
|
177
108
|
}
|
|
178
|
-
}`,variables:{couponId:e}});if(!
|
|
179
|
-
|
|
109
|
+
}`,variables:{couponId:e}});if(!o.coupon)throw Error(`No se encontró el cupón "${e}"`);if(o.coupon.websiteId!==t)throw Error(`El cupón "${e}" no pertenece al website seleccionado.`);return o.coupon}function Nr(e){if(!Array.isArray(e))throw Error("--input debe ser un arreglo JSON.");return e.map((t)=>{if(!t||typeof t!=="object"||typeof t.code!=="string")throw Error('Cada item de --input debe tener al menos { "code": "..." }.');if(t.userEmail!=null&&typeof t.userEmail!=="string")throw Error("userEmail debe ser string cuando viene informado.");return{code:t.code,userEmail:t.userEmail}})}function vr(e){if(!Array.isArray(e)||e.some((t)=>typeof t!=="string"))throw Error("--ids debe ser un arreglo JSON de strings.");return e}async function dt(e,t,o){let r=await $(e);await A(t,r.websiteId);let a=S(o,"limit"),n=S(o,"page"),i=o.filter,s=await u({service:"main",query:`query ($couponId: ID, $filter: String, $limit: BigInt, $page: BigInt) {
|
|
110
|
+
couponCodes(couponId: $couponId, filter: $filter, limit: $limit, page: $page) {
|
|
180
111
|
items {
|
|
181
|
-
|
|
182
|
-
name
|
|
183
|
-
active
|
|
184
|
-
baseURL
|
|
185
|
-
domain
|
|
186
|
-
countryCode
|
|
187
|
-
timezone
|
|
112
|
+
${mt}
|
|
188
113
|
}
|
|
189
114
|
totalCount
|
|
190
115
|
totalPages
|
|
191
116
|
hasNextPage
|
|
192
117
|
hasPreviousPage
|
|
193
118
|
}
|
|
194
|
-
}`,variables:{filter:
|
|
119
|
+
}`,variables:{couponId:t,filter:i,limit:a,page:n}});return{context:r,couponId:t,codes:s.couponCodes.items??[],pagination:{totalCount:s.couponCodes.totalCount??0,totalPages:s.couponCodes.totalPages??0,hasNextPage:Boolean(s.couponCodes.hasNextPage),hasPreviousPage:Boolean(s.couponCodes.hasPreviousPage),page:n??1,limit:a??null}}}async function pt(e,t,o){let r=await $(e);await A(t,r.websiteId);let a=Nr(P(o,"input")),n=a.some((s)=>s.userEmail),i=await u({service:"main",query:`mutation ($couponId: ID, $codesWithEmail: [CodeWithEmailInput], $useCodeWithEmail: Boolean) {
|
|
120
|
+
createCouponCodes(couponId: $couponId, codesWithEmail: $codesWithEmail, useCodeWithEmail: $useCodeWithEmail)
|
|
121
|
+
}`,variables:{couponId:t,codesWithEmail:a,useCodeWithEmail:n}});return{context:r,couponId:t,requestedCount:a.length,result:i.createCouponCodes}}async function gt(e,t,o){let r=await $(e);await A(t,r.websiteId);let a=S(o,"quantity");if(!a)throw Error("--quantity es requerido.");let n=await u({service:"main",query:`mutation ($couponId: ID, $couponQuantity: Float, $couponCodePrefix: String) {
|
|
122
|
+
createRandomCouponCodes(couponId: $couponId, couponQuantity: $couponQuantity, couponCodePrefix: $couponCodePrefix)
|
|
123
|
+
}`,variables:{couponId:t,couponQuantity:a,couponCodePrefix:o.prefix}});return{context:r,couponId:t,quantity:a,prefix:o.prefix??null,result:n.createRandomCouponCodes}}async function ft(e,t,o){let r=await $(e);await A(t,r.websiteId);let a=vr(P(o,"ids")),n=await u({service:"main",query:`mutation ($couponId: ID, $couponCodesIds: [ID]) {
|
|
124
|
+
deleteCouponCodes(couponId: $couponId, couponCodesIds: $couponCodesIds, globalCoupon: false)
|
|
125
|
+
}`,variables:{couponId:t,couponCodesIds:a}});return{context:r,couponId:t,deleted:n.deleteCouponCodes,couponCodesIds:a}}function wt(){return`team-cli admin coupons codes create
|
|
195
126
|
|
|
196
|
-
|
|
127
|
+
Crea códigos explícitos para un cupón.
|
|
197
128
|
|
|
198
129
|
Uso:
|
|
199
|
-
team-cli admin
|
|
130
|
+
team-cli admin <websiteId|domain> coupons codes create <couponId> --input '<json>'
|
|
200
131
|
|
|
201
|
-
|
|
202
|
-
--
|
|
203
|
-
|
|
132
|
+
Como funciona:
|
|
133
|
+
--input recibe un arreglo JSON.
|
|
134
|
+
Cada item debe tener al menos el campo code.
|
|
135
|
+
Opcionalmente puede incluir userEmail.
|
|
204
136
|
|
|
205
|
-
|
|
206
|
-
|
|
137
|
+
Formato esperado:
|
|
138
|
+
[
|
|
139
|
+
{"code":"BIENVENIDA1"},
|
|
140
|
+
{"code":"BIENVENIDA2","userEmail":"persona@ejemplo.com"}
|
|
141
|
+
]
|
|
207
142
|
|
|
208
|
-
|
|
209
|
-
|
|
143
|
+
Ejemplo:
|
|
144
|
+
team-cli admin <web> coupons codes create <couponId> --input '[{"code":"PROMO001"},{"code":"PROMO002","userEmail":"ana@ejemplo.com"}]'
|
|
210
145
|
|
|
211
|
-
|
|
212
|
-
team-cli
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
items {
|
|
217
|
-
_id
|
|
218
|
-
name
|
|
219
|
-
address {
|
|
220
|
-
streetAddress
|
|
221
|
-
extendedAddress
|
|
222
|
-
locality
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}`,variables:{websiteId:o.websiteId}})).stores.items??[]).map((i)=>({_id:i._id,name:i.name,address:$r(i)})).sort((i,n)=>i.name.localeCompare(n.name,"es",{sensitivity:"base"}));return{context:o,stores:t,totalCount:t.length}}var Ke={active:"Boolean",allowedEmails:"[String]",applyDeliveryDiscount:"Boolean",code:"ID",deliveryDiscountPercentage:"Float",deliveryDiscountType:"String",deliveryDiscountValue:"Float",description:"String",discountAmount:"Float",dontApplyToProductsIds:"[ID]",endDate:"Date",externalId:"String",extraRequirementsForPaymentTypes:"JSON",fixedAmount:"Float",fromDate:"Date",isBirthdayCoupon:"Boolean",isHidden:"Boolean",maxPercentageOffDiscount:"Float",maxProductsPerOrder:"Float",maxRedemptions:"Float",maxRedemptionsPerUser:"Float",maxRedemptionsPerUserPerDay:"Boolean",maximumOrderPrice:"Float",minimumOrderPrice:"Float",name:"String",onlyForNewUsers:"Boolean",onlyForProductsWithoutDiscount:"Boolean",onlyRedeemOnBirthday:"Boolean",percentageOff:"Float",requireChannels:"[ID]",requirePhoneVerification:"Boolean",requiredBINs:"[String]",requiresCategoriesIds:"[ID]",requiresMenusIds:"[ID]",requiresPaymentTypes:"[ID]",requiresProductsIds:"[ID]",requiresStoresIds:"[ID]",schedule:"ScheduleInput",scheduleAtUse:"ScheduleInput",type:"ID",websiteId:"ID"};function jr(e){let o=Object.entries(e).filter(([,n])=>n!==void 0),r=o.map(([n])=>n).filter((n)=>!Ke[n]);if(r.length)throw Error(`Campos no soportados para create: ${r.join(", ")}`);let t=o.map(([n])=>`$${n}: ${Ke[n]}`).join(", "),i=o.map(([n])=>`${n}: $${n}`).join(", ");return`mutation (${t}) {
|
|
227
|
-
createCoupon(${i}) {
|
|
228
|
-
${L}
|
|
146
|
+
Notas:
|
|
147
|
+
Si algún item trae userEmail, team-cli activa useCodeWithEmail automáticamente.
|
|
148
|
+
couponId se valida contra el website seleccionado antes de ejecutar la mutation.`}var bt={active:"Boolean",allowedEmails:"[String]",applyDeliveryDiscount:"Boolean",code:"ID",deliveryDiscountPercentage:"Float",deliveryDiscountType:"String",deliveryDiscountValue:"Float",description:"String",discountAmount:"Float",dontApplyToProductsIds:"[ID]",endDate:"Date",externalId:"String",extraRequirementsForPaymentTypes:"JSON",fixedAmount:"Float",fromDate:"Date",isBirthdayCoupon:"Boolean",isHidden:"Boolean",maxPercentageOffDiscount:"Float",maxProductsPerOrder:"Float",maxRedemptions:"Float",maxRedemptionsPerUser:"Float",maxRedemptionsPerUserPerDay:"Boolean",maximumOrderPrice:"Float",minimumOrderPrice:"Float",name:"String",onlyForNewUsers:"Boolean",onlyForProductsWithoutDiscount:"Boolean",onlyRedeemOnBirthday:"Boolean",percentageOff:"Float",requireChannels:"[ID]",requirePhoneVerification:"Boolean",requiredBINs:"[String]",requiresCategoriesIds:"[ID]",requiresMenusIds:"[ID]",requiresPaymentTypes:"[ID]",requiresProductsIds:"[ID]",requiresStoresIds:"[ID]",schedule:"ScheduleInput",scheduleAtUse:"ScheduleInput",type:"ID",websiteId:"ID"};function Rr(e){let t=Object.entries(e).filter(([,n])=>n!==void 0),o=t.map(([n])=>n).filter((n)=>!bt[n]);if(o.length)throw Error(`Campos no soportados para create: ${o.join(", ")}`);let r=t.map(([n])=>`$${n}: ${bt[n]}`).join(", "),a=t.map(([n])=>`${n}: $${n}`).join(", ");return`mutation (${r}) {
|
|
149
|
+
createCoupon(${a}) {
|
|
150
|
+
${le}
|
|
229
151
|
}
|
|
230
|
-
}`}async function
|
|
152
|
+
}`}async function Ct(e,t){let o=await $(e),r=S(t,"limit"),a=S(t,"page"),n=t.filter,i=await u({service:"main",query:`query ($websiteId: ID, $filter: String, $limit: BigInt, $page: BigInt) {
|
|
231
153
|
coupons(websiteId: $websiteId, filter: $filter, limit: $limit, page: $page) {
|
|
232
154
|
items {
|
|
233
155
|
_id
|
|
@@ -247,17 +169,17 @@ Ejemplos:
|
|
|
247
169
|
hasNextPage
|
|
248
170
|
hasPreviousPage
|
|
249
171
|
}
|
|
250
|
-
}`,variables:{websiteId:
|
|
172
|
+
}`,variables:{websiteId:o.websiteId,filter:n,limit:r,page:a}});return{context:o,coupons:i.coupons.items??[],pagination:{totalCount:i.coupons.totalCount??0,totalPages:i.coupons.totalPages??0,hasNextPage:Boolean(i.coupons.hasNextPage),hasPreviousPage:Boolean(i.coupons.hasPreviousPage),page:a??1,limit:r??null}}}async function yt(e,t){let o=await $(e);await A(t,o.websiteId);let r=await u({service:"main",query:`query ($couponId: ID) {
|
|
251
173
|
coupon(couponId: $couponId) {
|
|
252
|
-
${
|
|
174
|
+
${le}
|
|
253
175
|
}
|
|
254
|
-
}`,variables:{couponId:
|
|
176
|
+
}`,variables:{couponId:t}});return{context:o,coupon:r.coupon}}async function qt(e,t){let o=await $(e),r=P(t,"input");if(r.websiteId&&r.websiteId!==o.websiteId)throw Error("El websiteId del input no coincide con el website seleccionado.");let a={...r,websiteId:o.websiteId},n=Rr(a),i=await u({service:"main",query:n,variables:a});return{context:o,coupon:i.createCoupon}}async function It(e,t,o){let r=await $(e);await A(t,r.websiteId);let a=P(o,"input"),n=await u({service:"main",query:`mutation ($couponId: ID, $coupon: UpdateCouponInput) {
|
|
255
177
|
updateCoupon(couponId: $couponId, coupon: $coupon) {
|
|
256
|
-
${
|
|
178
|
+
${le}
|
|
257
179
|
}
|
|
258
|
-
}`,variables:{couponId:
|
|
180
|
+
}`,variables:{couponId:t,coupon:a}});return{context:r,coupon:n.updateCoupon}}async function ht(e,t){let o=await $(e);await A(t,o.websiteId);let r=await u({service:"main",query:`mutation ($couponsIds: [ID]) {
|
|
259
181
|
deleteCoupons(couponsIds: $couponsIds, globalCoupon: false)
|
|
260
|
-
}`,variables:{couponsIds:[
|
|
182
|
+
}`,variables:{couponsIds:[t]}});return{context:o,couponId:t,deleted:r.deleteCoupons}}function D(){return`team-cli admin coupons
|
|
261
183
|
|
|
262
184
|
Administracion de cupones para el website seleccionado.
|
|
263
185
|
|
|
@@ -305,7 +227,7 @@ Acciones:
|
|
|
305
227
|
Uso: team-cli admin <web> coupons codes delete <couponId> --ids '["id1","id2"]'
|
|
306
228
|
|
|
307
229
|
Nota:
|
|
308
|
-
El schema actual no expone update para coupon codes.`}function
|
|
230
|
+
El schema actual no expone update para coupon codes.`}function $t(){return`team-cli admin coupons create
|
|
309
231
|
|
|
310
232
|
Crea un cupón para el website seleccionado.
|
|
311
233
|
|
|
@@ -354,7 +276,7 @@ Ejemplo con schedule:
|
|
|
354
276
|
Tips:
|
|
355
277
|
Usa comillas simples afuera del JSON en shell.
|
|
356
278
|
Usa arrays JSON reales para ids o listas.
|
|
357
|
-
Si necesitas el shape exacto de un cupón existente, parte con: team-cli admin <web> coupons show <couponId>`}function
|
|
279
|
+
Si necesitas el shape exacto de un cupón existente, parte con: team-cli admin <web> coupons show <couponId>`}function xt(){return`team-cli admin coupons update
|
|
358
280
|
|
|
359
281
|
Actualiza un cupón existente.
|
|
360
282
|
|
|
@@ -396,47 +318,503 @@ Ejemplo reemplazando restricciones:
|
|
|
396
318
|
team-cli admin <web> coupons update <couponId> --input '{"requiresStoresIds":["store1"],"requiresPaymentTypes":["card"]}'
|
|
397
319
|
|
|
398
320
|
Tip:
|
|
399
|
-
Primero mira el cupón actual con: team-cli admin <web> coupons show <couponId>`}function
|
|
400
|
-
|
|
321
|
+
Primero mira el cupón actual con: team-cli admin <web> coupons show <couponId>`}async function St(e,t){Re();let o=e[2]??t.filter;if(!o)throw Error("Debes indicar un término de búsqueda. Uso: team-cli admin search <texto>");let r=S(t,"limit"),a=S(t,"page"),n=lt(t,"only-active"),i=await u({service:"main",query:`query ($filter: String, $limit: BigInt, $page: BigInt, $onlyActiveWebsites: Boolean) {
|
|
322
|
+
websites(filter: $filter, limit: $limit, page: $page, onlyActiveWebsites: $onlyActiveWebsites) {
|
|
401
323
|
items {
|
|
402
|
-
|
|
324
|
+
_id
|
|
325
|
+
name
|
|
326
|
+
active
|
|
327
|
+
baseURL
|
|
328
|
+
domain
|
|
329
|
+
countryCode
|
|
330
|
+
timezone
|
|
403
331
|
}
|
|
404
332
|
totalCount
|
|
405
333
|
totalPages
|
|
406
334
|
hasNextPage
|
|
407
335
|
hasPreviousPage
|
|
408
336
|
}
|
|
409
|
-
}`,variables:{
|
|
410
|
-
createCouponCodes(couponId: $couponId, codesWithEmail: $codesWithEmail, useCodeWithEmail: $useCodeWithEmail)
|
|
411
|
-
}`,variables:{couponId:o,codesWithEmail:i,useCodeWithEmail:n}});return{context:t,couponId:o,requestedCount:i.length,result:a.createCouponCodes}}async function so(e,o,r){let t=await q(e);await j(o,t.websiteId);let i=I(r,"quantity");if(!i)throw Error("--quantity es requerido.");let n=await c({service:"main",query:`mutation ($couponId: ID, $couponQuantity: Float, $couponCodePrefix: String) {
|
|
412
|
-
createRandomCouponCodes(couponId: $couponId, couponQuantity: $couponQuantity, couponCodePrefix: $couponCodePrefix)
|
|
413
|
-
}`,variables:{couponId:o,couponQuantity:i,couponCodePrefix:r.prefix}});return{context:t,couponId:o,quantity:i,prefix:r.prefix??null,result:n.createRandomCouponCodes}}async function co(e,o,r){let t=await q(e);await j(o,t.websiteId);let i=Ar(W(r,"ids")),n=await c({service:"main",query:`mutation ($couponId: ID, $couponCodesIds: [ID]) {
|
|
414
|
-
deleteCouponCodes(couponId: $couponId, couponCodesIds: $couponCodesIds, globalCoupon: false)
|
|
415
|
-
}`,variables:{couponId:o,couponCodesIds:i}});return{context:t,couponId:o,deleted:n.deleteCouponCodes,couponCodesIds:i}}function mo(){return`team-cli admin coupons codes create
|
|
337
|
+
}`,variables:{filter:o,limit:r,page:a,onlyActiveWebsites:n}});return{searchTerm:o,websites:i.websites.items??[],pagination:{totalCount:i.websites.totalCount??0,totalPages:i.websites.totalPages??0,hasNextPage:Boolean(i.websites.hasNextPage),hasPreviousPage:Boolean(i.websites.hasPreviousPage),page:a??1,limit:r??null}}}function Et(){return`team-cli admin search
|
|
416
338
|
|
|
417
|
-
|
|
339
|
+
Buscar websites en admin.
|
|
418
340
|
|
|
419
341
|
Uso:
|
|
420
|
-
team-cli admin <
|
|
342
|
+
team-cli admin search <texto> [--limit <n>] [--page <n>] [--only-active true|false]
|
|
421
343
|
|
|
422
|
-
|
|
423
|
-
--
|
|
424
|
-
|
|
425
|
-
Opcionalmente puede incluir userEmail.
|
|
344
|
+
Opciones:
|
|
345
|
+
--limit <n>
|
|
346
|
+
Límite de resultados.
|
|
426
347
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
{"code":"BIENVENIDA1"},
|
|
430
|
-
{"code":"BIENVENIDA2","userEmail":"persona@ejemplo.com"}
|
|
431
|
-
]
|
|
348
|
+
--page <n>
|
|
349
|
+
Página a consultar.
|
|
432
350
|
|
|
433
|
-
|
|
434
|
-
|
|
351
|
+
--only-active true|false
|
|
352
|
+
Filtrar solo websites activos.
|
|
435
353
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
354
|
+
Ejemplos:
|
|
355
|
+
team-cli admin search milas
|
|
356
|
+
team-cli admin search buffalo --limit 5
|
|
357
|
+
team-cli admin search pizza --only-active true`}function Tr(){if(!d())throw Error("Debes iniciar sesión primero. Recomendado: team-cli auth request-code --email <email> y luego team-cli auth login-with-token --email <email> --token <token> --code <CODIGO>")}function Or(e){let t=[e.address?.streetAddress,e.address?.extendedAddress,e.address?.locality].filter(Boolean);if(!t.length)return null;return t.join(", ")}async function jt(e){if(Tr(),!e)throw Error("Uso: team-cli admin <websiteId|domain> stores list");let t=await M(e),r=((await u({service:"main",query:`query ($websiteId: ID) {
|
|
358
|
+
stores(websiteId: $websiteId) {
|
|
359
|
+
items {
|
|
360
|
+
_id
|
|
361
|
+
name
|
|
362
|
+
address {
|
|
363
|
+
streetAddress
|
|
364
|
+
extendedAddress
|
|
365
|
+
locality
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}`,variables:{websiteId:t.websiteId}})).stores.items??[]).map((a)=>({_id:a._id,name:a.name,address:Or(a)})).sort((a,n)=>a.name.localeCompare(n.name,"es",{sensitivity:"base"}));return{context:t,stores:r,totalCount:r.length}}import{createInterface as Ur}from"node:readline";function z(e){if(process.env.JUSTO_TEAM_CLI_INTERACTIVE==="false")throw Error("Este entorno no soporta prompts interactivos.");if(I()?.interactive===!1)throw Error("Este entorno no soporta prompts interactivos.");let t=Ur({input:process.stdin,output:process.stderr});return new Promise((o)=>{t.question(e,(r)=>{t.close(),o(r.trim())})})}async function At(e){return(await u({service:"auth",query:`mutation ($email: String!) {
|
|
370
|
+
requestLoginCode(email: $email)
|
|
371
|
+
}`,variables:{email:e}})).requestLoginCode}async function Nt(e,t,o){let r=await u({service:"auth",query:`mutation ($email: String!, $token: String!, $code: String!) {
|
|
372
|
+
loginWithCode(email: $email, token: $token, code: $code) {
|
|
373
|
+
token
|
|
374
|
+
refreshToken
|
|
375
|
+
}
|
|
376
|
+
}`,variables:{email:e,token:t,code:o.toUpperCase()}});ue({email:e,token:r.loginWithCode.token,refreshToken:r.loginWithCode.refreshToken}),await Qr()}async function Qr(){if(!(await u({service:"main",query:"query { me { roles } }"})).me?.roles?.length)throw Ae(),Error("Solo miembros del equipo Justo pueden usar esta herramienta.")}async function vt(){let e=await z("Email: ");C(`Enviando codigo de verificacion...
|
|
377
|
+
`);let t=await At(e);C(`Codigo enviado a tu email.
|
|
378
|
+
`);let o=await z("Codigo: ");return await Nt(e,t,o),{ok:!0,authenticated:!0,email:e}}async function Rt(e){let t=F(e,"email"),o=F(e,"token"),r=F(e,"code");return await Nt(t,o,r),{ok:!0,authenticated:!0,email:t}}async function Tt(e){let t=F(e,"email");C(`Enviando codigo de verificacion...
|
|
379
|
+
`);let o=await At(t);return{ok:!0,email:t,token:o,nextCommand:`npx @getjusto/team-cli auth login-with-token --email ${t} --token ${o} --code <CODIGO>`}}async function Ot(){return Ae(),{ok:!0,authenticated:!1}}async function Ut(){let e=d();if(!e)return{authenticated:!1,loginCommand:"npx @getjusto/team-cli auth request-code --email <email>",nextCommand:"npx @getjusto/team-cli auth login-with-token --email <email> --token <token> --code <CODIGO>"};return{authenticated:!0,email:e.email}}function Te(){return`team-cli auth
|
|
380
|
+
|
|
381
|
+
Gestion de sesion.
|
|
382
|
+
|
|
383
|
+
Uso:
|
|
384
|
+
team-cli auth <subcomando> [opciones]
|
|
385
|
+
|
|
386
|
+
Subcomandos:
|
|
387
|
+
login
|
|
388
|
+
Iniciar sesion en modo interactivo. Usar solo como fallback manual.
|
|
389
|
+
Uso: team-cli auth login
|
|
390
|
+
|
|
391
|
+
logout
|
|
392
|
+
Cerrar sesion actual.
|
|
393
|
+
Uso: team-cli auth logout
|
|
394
|
+
|
|
395
|
+
status
|
|
396
|
+
Ver la sesion actual.
|
|
397
|
+
Uso: team-cli auth status
|
|
398
|
+
|
|
399
|
+
request-code
|
|
400
|
+
Solicitar codigo para login no interactivo. Recomendado para agentes.
|
|
401
|
+
Uso: team-cli auth request-code --email <email>
|
|
402
|
+
|
|
403
|
+
login-with-token
|
|
404
|
+
Iniciar sesion sin prompts. Recomendado para agentes.
|
|
405
|
+
Uso: team-cli auth login-with-token --email <email> --token <token> --code <codigo>`}import{spawn as Ce}from"node:child_process";import{createServer as Vt}from"node:http";import{existsSync as Zr,mkdirSync as Yr,openSync as Dr,readFileSync as zr,rmSync as kr,writeFileSync as Kr}from"node:fs";import{dirname as Vr,join as ye,resolve as Lt}from"node:path";import{request as Lr}from"node:http";import{request as ea}from"node:https";import{execFileSync as Jr}from"node:child_process";import{existsSync as fe,mkdirSync as Wr,readFileSync as we,readdirSync as _r,rmSync as Oe,writeFileSync as N}from"node:fs";import{basename as Bt,dirname as Mt,join as f,resolve as Pt}from"node:path";var de="iUzDOAFCUx33tmT6OCea",k="VITE_JUSTO_MAP_TILER_TOKEN";function Qt(){return`import {useState, type FormEvent} from 'react'
|
|
406
|
+
import {Badge} from '@/components/ui/badge'
|
|
407
|
+
import {Button} from '@/components/ui/button'
|
|
408
|
+
import {Card, CardContent, CardDescription, CardHeader, CardTitle} from '@/components/ui/card'
|
|
409
|
+
import {ChartContainer, ChartTooltip, ChartTooltipContent} from '@/components/ui/chart'
|
|
410
|
+
import type {ChartConfig} from '@/components/ui/chart'
|
|
411
|
+
import {Input} from '@/components/ui/input'
|
|
412
|
+
import {Separator} from '@/components/ui/separator'
|
|
413
|
+
import {Textarea} from '@/components/ui/textarea'
|
|
414
|
+
import {Toaster} from '@/components/ui/sonner'
|
|
415
|
+
import {MapContainer, TileLayer, CircleMarker, Popup} from 'react-leaflet'
|
|
416
|
+
import {Bar, BarChart, CartesianGrid, XAxis} from 'recharts'
|
|
417
|
+
import {toast} from 'sonner'
|
|
418
|
+
import {justoCli} from '@/lib/justo'
|
|
419
|
+
|
|
420
|
+
const defaultCommand = 'auth status'
|
|
421
|
+
const queryExample = "data queries preview <queryId> --params '{\\"limit\\":10}'"
|
|
422
|
+
const mapTilerToken =
|
|
423
|
+
(import.meta.env as {${k}?: string}).${k} ||
|
|
424
|
+
'${de}'
|
|
425
|
+
const chartData = [
|
|
426
|
+
{day: 'Lun', sessions: 12},
|
|
427
|
+
{day: 'Mar', sessions: 18},
|
|
428
|
+
{day: 'Mié', sessions: 15},
|
|
429
|
+
{day: 'Jue', sessions: 22},
|
|
430
|
+
{day: 'Vie', sessions: 19},
|
|
431
|
+
]
|
|
432
|
+
|
|
433
|
+
const chartConfig = {
|
|
434
|
+
sessions: {
|
|
435
|
+
label: 'Sesiones',
|
|
436
|
+
color: 'var(--color-stone-900)',
|
|
437
|
+
},
|
|
438
|
+
} satisfies ChartConfig
|
|
439
|
+
|
|
440
|
+
export function App() {
|
|
441
|
+
const [command, setCommand] = useState(defaultCommand)
|
|
442
|
+
const [result, setResult] = useState('Ejecuta un comando para ver el resultado aquí.')
|
|
443
|
+
const [loading, setLoading] = useState(false)
|
|
444
|
+
|
|
445
|
+
async function onSubmit(event: FormEvent<HTMLFormElement>) {
|
|
446
|
+
event.preventDefault()
|
|
447
|
+
setLoading(true)
|
|
448
|
+
|
|
449
|
+
try {
|
|
450
|
+
const response = await justoCli(command)
|
|
451
|
+
setResult(JSON.stringify(response, null, 2))
|
|
452
|
+
toast.success('Comando ejecutado')
|
|
453
|
+
} catch (error) {
|
|
454
|
+
const message = error instanceof Error ? error.message : 'Unexpected error'
|
|
455
|
+
setResult(message)
|
|
456
|
+
toast.error(message)
|
|
457
|
+
} finally {
|
|
458
|
+
setLoading(false)
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
return (
|
|
463
|
+
<>
|
|
464
|
+
<main className="min-h-screen bg-stone-50 text-stone-950">
|
|
465
|
+
<div className="mx-auto flex min-h-screen w-full max-w-6xl flex-col gap-8 px-6 py-10">
|
|
466
|
+
<section className="grid gap-4">
|
|
467
|
+
<Badge variant="secondary" className="w-fit bg-stone-200 text-stone-700">
|
|
468
|
+
Justo Space Starter
|
|
469
|
+
</Badge>
|
|
470
|
+
<div className="grid gap-3">
|
|
471
|
+
<h1 className="max-w-3xl text-4xl font-semibold tracking-tight text-balance">
|
|
472
|
+
React, Vite, Tailwind y todos los componentes shadcn listos para construir un
|
|
473
|
+
space.
|
|
474
|
+
</h1>
|
|
475
|
+
<p className="max-w-3xl text-base leading-7 text-stone-600">
|
|
476
|
+
Este proyecto ya viene preparado para publicar en Justo Spaces. Construye la UI en
|
|
477
|
+
React y llama el CLI con <code>window.justo.cli(...)</code> a través del helper
|
|
478
|
+
<code>justoCli(...)</code>.
|
|
479
|
+
</p>
|
|
480
|
+
</div>
|
|
481
|
+
</section>
|
|
482
|
+
|
|
483
|
+
<section className="grid gap-6 lg:grid-cols-[1.1fr_0.9fr]">
|
|
484
|
+
<Card className="border-stone-200 bg-white text-stone-950 shadow-sm">
|
|
485
|
+
<CardHeader>
|
|
486
|
+
<CardTitle>Playground del CLI</CardTitle>
|
|
487
|
+
<CardDescription className="text-stone-600">
|
|
488
|
+
Usa exactamente los mismos comandos que usarías en team-cli.
|
|
489
|
+
</CardDescription>
|
|
490
|
+
</CardHeader>
|
|
491
|
+
<CardContent className="grid gap-4">
|
|
492
|
+
<form className="grid gap-4" onSubmit={onSubmit}>
|
|
493
|
+
<Input
|
|
494
|
+
value={command}
|
|
495
|
+
onChange={event => setCommand(event.target.value)}
|
|
496
|
+
className="border-stone-300 bg-white text-stone-950"
|
|
497
|
+
/>
|
|
498
|
+
<div className="flex flex-wrap gap-3">
|
|
499
|
+
<Button disabled={loading} type="submit">
|
|
500
|
+
{loading ? 'Ejecutando...' : 'Ejecutar comando'}
|
|
501
|
+
</Button>
|
|
502
|
+
<Button
|
|
503
|
+
type="button"
|
|
504
|
+
variant="outline"
|
|
505
|
+
className="border-stone-300 bg-transparent text-stone-900"
|
|
506
|
+
onClick={() => setCommand(queryExample)}
|
|
507
|
+
>
|
|
508
|
+
Probar query preview
|
|
509
|
+
</Button>
|
|
510
|
+
</div>
|
|
511
|
+
</form>
|
|
512
|
+
|
|
513
|
+
<Separator className="bg-stone-200" />
|
|
514
|
+
|
|
515
|
+
<div className="grid gap-2">
|
|
516
|
+
<p className="text-sm font-medium text-stone-700">Resultado</p>
|
|
517
|
+
<Textarea
|
|
518
|
+
readOnly
|
|
519
|
+
value={result}
|
|
520
|
+
className="min-h-[320px] border-stone-300 bg-stone-950 font-mono text-xs text-emerald-200"
|
|
521
|
+
/>
|
|
522
|
+
</div>
|
|
523
|
+
</CardContent>
|
|
524
|
+
</Card>
|
|
525
|
+
|
|
526
|
+
<Card className="border-stone-200 bg-white text-stone-950 shadow-sm">
|
|
527
|
+
<CardHeader>
|
|
528
|
+
<CardTitle>Cómo construir el space</CardTitle>
|
|
529
|
+
<CardDescription className="text-stone-600">
|
|
530
|
+
Flujo recomendado para agentes.
|
|
531
|
+
</CardDescription>
|
|
532
|
+
</CardHeader>
|
|
533
|
+
<CardContent className="grid gap-4 text-sm leading-7 text-stone-600">
|
|
534
|
+
<div>
|
|
535
|
+
<p className="font-medium text-stone-900">1. Crea el entity</p>
|
|
536
|
+
<p>team-cli spaces create --name 'Mi space' --description '...' --slug mi-space</p>
|
|
537
|
+
</div>
|
|
538
|
+
<div>
|
|
539
|
+
<p className="font-medium text-stone-900">2. Trabaja aquí mismo</p>
|
|
540
|
+
<p>Edita <code>src/App.tsx</code>, crea pantallas, hooks y usa shadcn libremente.</p>
|
|
541
|
+
</div>
|
|
542
|
+
<div>
|
|
543
|
+
<p className="font-medium text-stone-900">3. Usa queries como APIs</p>
|
|
544
|
+
<p>
|
|
545
|
+
Lo recomendado para obtener data es crear queries en data y luego llamar desde el
|
|
546
|
+
space comandos como <code>data queries preview</code>.
|
|
547
|
+
</p>
|
|
548
|
+
</div>
|
|
549
|
+
<div>
|
|
550
|
+
<p className="font-medium text-stone-900">4. Publica</p>
|
|
551
|
+
<p>team-cli spaces publish <spaceId> --path ./mi-space-app</p>
|
|
552
|
+
</div>
|
|
553
|
+
<div>
|
|
554
|
+
<p className="font-medium text-stone-900">Reglas de diseño</p>
|
|
555
|
+
<p>Prefiere shadcn, usa solo light mode y mantén una paleta neutra.</p>
|
|
556
|
+
</div>
|
|
557
|
+
</CardContent>
|
|
558
|
+
</Card>
|
|
559
|
+
</section>
|
|
560
|
+
|
|
561
|
+
<section className="grid gap-6 lg:grid-cols-[0.95fr_1.05fr]">
|
|
562
|
+
<Card className="border-stone-200 bg-white text-stone-950 shadow-sm">
|
|
563
|
+
<CardHeader>
|
|
564
|
+
<CardTitle>Charts listos</CardTitle>
|
|
565
|
+
<CardDescription className="text-stone-600">
|
|
566
|
+
El starter ya trae el wrapper de charts de shadcn y recharts instalado.
|
|
567
|
+
</CardDescription>
|
|
568
|
+
</CardHeader>
|
|
569
|
+
<CardContent>
|
|
570
|
+
<ChartContainer className="h-[260px] w-full" config={chartConfig}>
|
|
571
|
+
<BarChart accessibilityLayer data={chartData}>
|
|
572
|
+
<CartesianGrid vertical={false} />
|
|
573
|
+
<XAxis axisLine={false} dataKey="day" tickLine={false} tickMargin={10} />
|
|
574
|
+
<ChartTooltip content={<ChartTooltipContent />} cursor={false} />
|
|
575
|
+
<Bar dataKey="sessions" fill="var(--color-sessions)" radius={10} />
|
|
576
|
+
</BarChart>
|
|
577
|
+
</ChartContainer>
|
|
578
|
+
</CardContent>
|
|
579
|
+
</Card>
|
|
580
|
+
|
|
581
|
+
<Card className="border-stone-200 bg-white text-stone-950 shadow-sm">
|
|
582
|
+
<CardHeader>
|
|
583
|
+
<CardTitle>Mapa con OpenStreetMap</CardTitle>
|
|
584
|
+
<CardDescription className="text-stone-600">
|
|
585
|
+
Usa el mismo token de MapTiler que ya ocupa vite-fronts, sobre datos de
|
|
586
|
+
OpenStreetMap.
|
|
587
|
+
</CardDescription>
|
|
588
|
+
</CardHeader>
|
|
589
|
+
<CardContent className="grid gap-3">
|
|
590
|
+
<div className="overflow-hidden rounded-xl border border-stone-200">
|
|
591
|
+
<MapContainer
|
|
592
|
+
center={[-33.4372, -70.6506]}
|
|
593
|
+
className="h-[260px] w-full"
|
|
594
|
+
scrollWheelZoom={false}
|
|
595
|
+
zoom={12}
|
|
596
|
+
>
|
|
597
|
+
<TileLayer
|
|
598
|
+
attribution='© <a href="https://www.maptiler.com/copyright/" target="_blank">MapTiler</a> <a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>'
|
|
599
|
+
tileSize={512}
|
|
600
|
+
url={\`https://api.maptiler.com/maps/streets/{z}/{x}/{y}@2x.png?key=\${mapTilerToken}\`}
|
|
601
|
+
zoomOffset={-1}
|
|
602
|
+
/>
|
|
603
|
+
<CircleMarker
|
|
604
|
+
center={[-33.4372, -70.6506]}
|
|
605
|
+
pathOptions={{color: '#44403c', fillColor: '#44403c', fillOpacity: 0.9}}
|
|
606
|
+
radius={10}
|
|
607
|
+
>
|
|
608
|
+
<Popup>Justo Spaces starter</Popup>
|
|
609
|
+
</CircleMarker>
|
|
610
|
+
</MapContainer>
|
|
611
|
+
</div>
|
|
612
|
+
<p className="text-sm text-stone-600">
|
|
613
|
+
No necesitas configurar una key adicional en el space: el starter ya reutiliza el
|
|
614
|
+
token que existe en vite-fronts.
|
|
615
|
+
</p>
|
|
616
|
+
</CardContent>
|
|
617
|
+
</Card>
|
|
618
|
+
</section>
|
|
619
|
+
</div>
|
|
620
|
+
</main>
|
|
621
|
+
<Toaster richColors />
|
|
622
|
+
</>
|
|
623
|
+
)
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
export default App
|
|
627
|
+
`}function Jt(){return`type JustoCliFunction = <T = unknown>(command: string) => Promise<T>
|
|
628
|
+
type JustoStreamFunction = <T = unknown>(
|
|
629
|
+
command: string,
|
|
630
|
+
onRow: (row: T) => Promise<void> | void,
|
|
631
|
+
) => Promise<{rowCount: number}>
|
|
632
|
+
|
|
633
|
+
type ImportMetaEnvWithJusto = ImportMeta['env'] & {
|
|
634
|
+
VITE_JUSTO_CLI_ENDPOINT?: string
|
|
635
|
+
VITE_JUSTO_STREAM_ENDPOINT?: string
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
declare global {
|
|
639
|
+
interface Window {
|
|
640
|
+
justo?: {
|
|
641
|
+
cli: JustoCliFunction
|
|
642
|
+
stream: JustoStreamFunction
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
async function callLocalPreviewCli<T>(command: string) {
|
|
648
|
+
const endpoint = (import.meta.env as ImportMetaEnvWithJusto).VITE_JUSTO_CLI_ENDPOINT
|
|
649
|
+
|
|
650
|
+
if (!endpoint) {
|
|
651
|
+
throw new Error(
|
|
652
|
+
'window.justo.cli no está disponible. Ejecuta team-cli spaces preview --path . para probar esta app localmente o publícala dentro de Justo Spaces.',
|
|
653
|
+
)
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
const response = await fetch(endpoint, {
|
|
657
|
+
method: 'POST',
|
|
658
|
+
headers: {'Content-Type': 'application/json'},
|
|
659
|
+
body: JSON.stringify({command}),
|
|
660
|
+
})
|
|
661
|
+
|
|
662
|
+
const payload = (await response.json()) as {result?: T; error?: string}
|
|
663
|
+
if (!response.ok) {
|
|
664
|
+
throw new Error(payload.error || 'justoCli failed')
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
return payload.result as T
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
async function callLocalPreviewStream<T>(
|
|
671
|
+
command: string,
|
|
672
|
+
onRow: (row: T) => Promise<void> | void,
|
|
673
|
+
) {
|
|
674
|
+
const endpoint = (import.meta.env as ImportMetaEnvWithJusto).VITE_JUSTO_STREAM_ENDPOINT
|
|
675
|
+
|
|
676
|
+
if (!endpoint) {
|
|
677
|
+
throw new Error(
|
|
678
|
+
'window.justo.stream no está disponible. Ejecuta team-cli spaces preview --path . para probar esta app localmente o publícala dentro de Justo Spaces.',
|
|
679
|
+
)
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
const response = await fetch(endpoint, {
|
|
683
|
+
method: 'POST',
|
|
684
|
+
headers: {'Content-Type': 'application/json'},
|
|
685
|
+
body: JSON.stringify({command}),
|
|
686
|
+
})
|
|
687
|
+
|
|
688
|
+
if (!response.ok) {
|
|
689
|
+
const payload = (await response.json().catch(() => ({}))) as {error?: string}
|
|
690
|
+
throw new Error(payload.error || 'justoStream failed')
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
if (!response.body) {
|
|
694
|
+
throw new Error('justoStream no recibió datos')
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
const reader = response.body.getReader()
|
|
698
|
+
const decoder = new TextDecoder()
|
|
699
|
+
let buffer = ''
|
|
700
|
+
let rowCount = 0
|
|
701
|
+
|
|
702
|
+
while (true) {
|
|
703
|
+
const result = await reader.read()
|
|
704
|
+
if (result.done) break
|
|
705
|
+
|
|
706
|
+
buffer += decoder.decode(result.value, {stream: true})
|
|
707
|
+
|
|
708
|
+
let newlineIndex = buffer.indexOf('\\n')
|
|
709
|
+
while (newlineIndex >= 0) {
|
|
710
|
+
const line = buffer.slice(0, newlineIndex).trim()
|
|
711
|
+
buffer = buffer.slice(newlineIndex + 1)
|
|
712
|
+
if (line) {
|
|
713
|
+
rowCount += 1
|
|
714
|
+
await onRow(JSON.parse(line) as T)
|
|
715
|
+
}
|
|
716
|
+
newlineIndex = buffer.indexOf('\\n')
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
buffer += decoder.decode()
|
|
721
|
+
if (buffer.trim()) {
|
|
722
|
+
rowCount += 1
|
|
723
|
+
await onRow(JSON.parse(buffer.trim()) as T)
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
return {rowCount}
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
function ensurePreviewWindowJusto() {
|
|
730
|
+
if (window.justo) return window.justo
|
|
731
|
+
|
|
732
|
+
const env = import.meta.env as ImportMetaEnvWithJusto
|
|
733
|
+
if (!env.VITE_JUSTO_CLI_ENDPOINT || !env.VITE_JUSTO_STREAM_ENDPOINT) {
|
|
734
|
+
return undefined
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
window.justo = {
|
|
738
|
+
cli: callLocalPreviewCli,
|
|
739
|
+
stream: callLocalPreviewStream,
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
return window.justo
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
export async function justoCli<T = unknown>(command: string) {
|
|
746
|
+
ensurePreviewWindowJusto()
|
|
747
|
+
|
|
748
|
+
if (window.justo?.cli) {
|
|
749
|
+
return await window.justo.cli<T>(command)
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
return await callLocalPreviewCli<T>(command)
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
export async function justoStream<T = unknown>(
|
|
756
|
+
command: string,
|
|
757
|
+
onRow: (row: T) => Promise<void> | void,
|
|
758
|
+
) {
|
|
759
|
+
ensurePreviewWindowJusto()
|
|
760
|
+
|
|
761
|
+
if (window.justo?.stream) {
|
|
762
|
+
return await window.justo.stream<T>(command, onRow)
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
return await callLocalPreviewStream<T>(command, onRow)
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
ensurePreviewWindowJusto()
|
|
769
|
+
`}function Wt(e){return`# ${e}
|
|
770
|
+
|
|
771
|
+
Starter de Justo Spaces generado por \`team-cli spaces init\`.
|
|
772
|
+
|
|
773
|
+
Incluye:
|
|
774
|
+
- React + Vite
|
|
775
|
+
- Tailwind
|
|
776
|
+
- todos los componentes shadcn
|
|
777
|
+
- chart wrapper de shadcn + recharts
|
|
778
|
+
- mapas con \`react-leaflet\` + MapTiler/OpenStreetMap
|
|
779
|
+
- helper \`justoCli(...)\` para llamar \`window.justo.cli(...)\`
|
|
780
|
+
- helper \`justoStream(...)\` para consumir NDJSON desde el CLI
|
|
781
|
+
|
|
782
|
+
Reglas de diseño:
|
|
783
|
+
- preferir siempre shadcn
|
|
784
|
+
- usar solo light mode
|
|
785
|
+
- usar paleta de colores neutra
|
|
786
|
+
|
|
787
|
+
Flujo recomendado:
|
|
788
|
+
1. \`team-cli spaces create --name '...' --description '...' --slug ...\`
|
|
789
|
+
2. \`team-cli spaces preview --path . --open\`
|
|
790
|
+
3. desarrolla esta app
|
|
791
|
+
4. \`team-cli spaces publish <spaceId> --path .\`
|
|
792
|
+
5. abre el space en intra
|
|
793
|
+
|
|
794
|
+
Tip:
|
|
795
|
+
- usa \`spaces preview --open\` para abrir el dashboard en el navegador por defecto y mostrárselo al usuario mientras lo iteras
|
|
796
|
+
`}function _t(){return`import {StrictMode} from 'react'
|
|
797
|
+
import {createRoot} from 'react-dom/client'
|
|
798
|
+
import App from './App.tsx'
|
|
799
|
+
import './index.css'
|
|
800
|
+
import './lib/justo'
|
|
801
|
+
import {ThemeProvider} from '@/components/theme-provider.tsx'
|
|
802
|
+
|
|
803
|
+
createRoot(document.getElementById('root')!).render(
|
|
804
|
+
<StrictMode>
|
|
805
|
+
<ThemeProvider defaultTheme="light">
|
|
806
|
+
<App />
|
|
807
|
+
</ThemeProvider>
|
|
808
|
+
</StrictMode>,
|
|
809
|
+
)
|
|
810
|
+
`}function pe(){return process.execPath}function Q(e){if(process.platform==="win32")return`${e}.cmd`;return e}var Gt=".justo-space.json";function ge(e,t,o){Jr(e,t,{cwd:o,stdio:"inherit",env:{...process.env,CI:"1"}})}function Br(e){if(!e)throw Error("Falta --path. Ejemplo: team-cli spaces init --path ./mi-space-app");let t=Pt(e);if(fe(t)){if(_r(t).length>0)throw Error(`La carpeta ya existe y no está vacía: ${t}`);Oe(t,{recursive:!0,force:!0})}return Wr(Mt(t),{recursive:!0}),t}function Mr(e){let t=f(e,"vite.config.ts"),o=we(t,"utf-8");if(o.includes("base: './'"))return;let r=o.replace("export default defineConfig({",`export default defineConfig({
|
|
811
|
+
base: './',`);N(t,r)}function Pr(e){let t=f(e,"tsconfig.app.json"),r=we(t,"utf-8").replace('"noUnusedLocals": true,','"noUnusedLocals": false,').replace('"noUnusedParameters": true,','"noUnusedParameters": false,');N(t,r)}function Gr(e){let t=f(e,"package.json"),o=JSON.parse(we(t,"utf-8"));o.dependencies=o.dependencies||{},o.devDependencies=o.devDependencies||{},o.dependencies.leaflet="^1.9.4",o.dependencies["react-leaflet"]="^5.0.0",o.devDependencies["@types/leaflet"]="^1.9.20",o.justoSpaceApp=!0,N(t,`${JSON.stringify(o,null,2)}
|
|
812
|
+
`)}function Fr(e){let t=f(e,"src","index.css"),o=we(t,"utf-8");if(o.includes("leaflet/dist/leaflet.css"))return;N(t,`@import "leaflet/dist/leaflet.css";
|
|
813
|
+
${o}`)}function Xr(e){let t=Bt(e);N(f(e,"README.md"),Wt(t)),N(f(e,"src","App.tsx"),Qt()),N(f(e,"src","main.tsx"),_t()),N(f(e,"src","lib","justo.ts"),Jt()),N(f(e,Gt),`${JSON.stringify({template:"react-vite-shadcn",version:1},null,2)}
|
|
814
|
+
`),Oe(f(e,".git"),{recursive:!0,force:!0})}function Hr(e){Oe(f(e,"package-lock.json"),{force:!0})}function Ue(e){let t=Pt(e);if(!fe(t))throw Error(`No existe la app del space: ${t}`);if(!fe(f(t,Gt)))throw Error("Este publish solo acepta apps creadas con team-cli spaces init. Debes apuntar al root de esa app.");return t}function Ft(e){let t=Ue(e);ge(Q("yarn"),["build"],t);let o=f(t,"dist");if(!fe(f(o,"index.html")))throw Error("El build no generó dist/index.html");return o}function Xt(e){let t=Br(e),o=Mt(t),r=Bt(t);return ge(Q("npx"),["shadcn@latest","init","-t","vite","-d","-y","-n",r],o),ge(Q("npx"),["shadcn@latest","add","-a","-y"],t),Hr(t),Gr(t),ge(Q("yarn"),["install"],t),Mr(t),Pr(t),Fr(t),Xr(t),{path:t,nextSteps:[`cd ${t}`,"team-cli spaces create --name '...' --description '...' --slug mi-space","team-cli spaces publish <spaceId> --path ."]}}function Ht(e){let t=[],o="",r=null,a=!1;for(let n of e){if(a){o+=n,a=!1;continue}if(n==="\\"){a=!0;continue}if(r){if(n===r)r=null;else o+=n;continue}if(n==='"'||n==="'"){r=n;continue}if(/\s/.test(n)){if(o)t.push(o),o="";continue}o+=n}if(r)throw Error("Comando inválido: falta cerrar una comilla");if(o)t.push(o);return t}var ta=".justo-space-preview",oa="preview.json",ra=30000;function qe(e){return ye(e,ta)}function eo(e){return ye(qe(e),oa)}function Zt(e){return ye(qe(e),"bridge.log")}function Yt(e){return ye(qe(e),"vite.log")}function to(e){Yr(qe(e),{recursive:!0})}function be(e){if(!e)return;try{process.kill(e,"SIGTERM")}catch{return}}function aa(e){if(process.platform==="darwin")return{command:"open",args:[e]};if(process.platform==="win32")return{command:"cmd",args:["/c","start","",e]};return{command:"xdg-open",args:[e]}}async function na(e,t){if(!t)return{attempted:!1,opened:!1};let o=aa(e);return await new Promise((r)=>{let a=Ce(o.command,o.args,{stdio:"ignore",detached:!0});a.once("error",()=>{r({attempted:!0,opened:!1,message:"No se pudo abrir el navegador por defecto automáticamente. Abre la URL manualmente."})}),a.once("spawn",()=>{a.unref(),r({attempted:!0,opened:!0})})})}function ia(e){let t=eo(e);if(!Zr(t))return;try{let o=JSON.parse(zr(t,"utf-8"));be(o.appPid),be(o.bridgePid)}catch{}kr(t,{force:!0})}function Dt(){return new Promise((e,t)=>{let o=Vt();o.listen(0,"127.0.0.1",()=>{let r=o.address();if(!r||typeof r==="string"){o.close(),t(Error("No se pudo obtener un puerto libre"));return}let{port:a}=r;o.close((n)=>{if(n){t(n);return}e(a)})}),o.on("error",t)})}function zt(e){return new Promise((t)=>setTimeout(t,e))}function sa(e){return new Promise((t,o)=>{let n=(new URL(e).protocol==="https:"?ea:Lr)(e,{method:"GET"},(i)=>{t(i.statusCode||0),i.resume()});n.on("error",o),n.end()})}async function kt(e,t=ra){let o=Date.now();while(Date.now()-o<t){try{if(await sa(e)>0)return}catch{await zt(500);continue}await zt(500)}throw Error(`Timeout esperando que el preview responda en ${e}`)}function ca(e){return to(Vr(e)),Dr(e,"a")}function Kt(e,t,o,r,a){let n=ca(r),i=Ce(e,t,{cwd:o,detached:!0,stdio:["ignore",n,n],env:{...process.env,...a}});if(!i.pid)throw Error(`No se pudo iniciar el proceso ${e}`);return i.unref(),i.pid}function oo(){let e=ot("prod");if(!e)throw Error("Debes iniciar sesión en prod antes de usar spaces preview. Recomendado: team-cli auth request-code --email <email> y luego team-cli auth login-with-token --email <email> --token <token> --code <CODIGO>");return e}async function ua(e){let t=[];for await(let o of e)t.push(Buffer.isBuffer(o)?o:Buffer.from(o));return Buffer.concat(t).toString("utf-8")}function K(e,t,o){e.writeHead(t,{"Content-Type":"application/json; charset=utf-8","Access-Control-Allow-Origin":"*","Access-Control-Allow-Headers":"Content-Type","Access-Control-Allow-Methods":"POST,OPTIONS,GET"}),e.end(JSON.stringify(o))}function Qe(e){let t=e.trim(),o=new Set([0]);for(let a=0;a<t.length;a++)if(t[a]==="{"||t[a]==="[")o.add(a);let r=[...o].sort((a,n)=>n-a);for(let a of r)try{return JSON.parse(t.slice(a))}catch{continue}return t}function ro(e){return{...process.env,NODE_OPTIONS:"",__JUSTO_REPL_PORT:"",JUSTO_TEAM_CLI_EMAIL:e.email,JUSTO_TEAM_CLI_TOKEN:e.token,JUSTO_TEAM_CLI_REFRESH_TOKEN:e.refreshToken,JUSTO_TEAM_CLI_INTERACTIVE:"false",JUSTO_TEAM_CLI_DEVICE_ID:"spaces-preview"}}function ma(e,t){return{VITE_JUSTO_CLI_ENDPOINT:e,VITE_JUSTO_STREAM_ENDPOINT:t,VITE_JUSTO_CLI_MODE:"preview",[k]:de}}function la(e,t,o,r){return new Promise((a,n)=>{let i=Ce(pe(),[t,"--env","prod",...r,"--format","json"],{cwd:process.cwd(),env:ro(o),stdio:["ignore","pipe","pipe"]}),s="";i.stdout.on("data",(c)=>{if(!e.headersSent)e.writeHead(200,{"Content-Type":"application/x-ndjson; charset=utf-8","Access-Control-Allow-Origin":"*","Access-Control-Allow-Headers":"Content-Type","Access-Control-Allow-Methods":"POST,OPTIONS,GET"});e.write(c)}),i.stderr.on("data",(c)=>{s+=Buffer.from(c).toString("utf-8")}),i.on("error",n),i.on("close",(c)=>{if(!c){if(!e.headersSent)e.writeHead(200,{"Content-Type":"application/x-ndjson; charset=utf-8","Access-Control-Allow-Origin":"*","Access-Control-Allow-Headers":"Content-Type","Access-Control-Allow-Methods":"POST,OPTIONS,GET"});e.end(),a();return}let m=Qe(s.trim());n(Error(m.error||s.trim()||"justoStream failed"))})})}async function ao(e){let t=Number(e.port);if(!t)throw Error("Falta --port para el bridge interno de preview");let o=oo(),r=Lt(e["cli-path"]||process.argv[1]||""),a=Vt(async(n,i)=>{if(n.method==="OPTIONS"){K(i,200,{ok:!0});return}if(n.method==="GET"&&n.url==="/__justo/health"){K(i,200,{ok:!0});return}if(n.method!=="POST"||n.url!=="/__justo/cli"&&n.url!=="/__justo/stream"){K(i,404,{ok:!1,error:"Not found"});return}try{let s=await ua(n),m=JSON.parse(s||"{}").command;if(!m)throw Error("Debes indicar un comando");let l=Array.isArray(m)?m:Ht(m);if(n.url==="/__justo/stream"){await la(i,r,o,l);return}let g=await new Promise((p,y)=>{let w=Ce(pe(),[r,"--env","prod",...l,"--format","json"],{cwd:process.cwd(),env:ro(o),stdio:["ignore","pipe","pipe"]}),oe=[],W=[];w.stdout.on("data",(R)=>oe.push(Buffer.from(R))),w.stderr.on("data",(R)=>W.push(Buffer.from(R))),w.on("error",y),w.on("close",(R)=>{let G=Buffer.concat(oe).toString("utf-8")||Buffer.concat(W).toString("utf-8");if(R&&R!==0){let Bo=Qe(G);y(Error(Bo.error||G||"justoCli failed"));return}p(Qe(G))})});K(i,200,{result:g})}catch(s){let c=s instanceof Error?s.message:"Unexpected error";K(i,400,{error:c})}});await new Promise((n,i)=>{a.listen(t,"127.0.0.1",()=>n()),a.on("error",i)}),C(`Space preview bridge listening on http://127.0.0.1:${t}
|
|
815
|
+
`),await new Promise((n,i)=>{a.on("close",()=>n()),a.on("error",i)})}async function no(e){let t=e.path;if(!t)throw Error("Falta --path. Ejemplo: team-cli spaces preview --path ./mi-space-app");let o=Ue(t);oo(),to(o),ia(o);let r=Number(e.port)||await Dt(),a=Number(e["bridge-port"])||await Dt(),n=e.open==="true",i=`http://127.0.0.1:${r}`,s=`http://127.0.0.1:${a}/__justo/cli`,c=`http://127.0.0.1:${a}/__justo/stream`,m=Lt(process.argv[1]||""),l=Kt(pe(),[m,"__spaces-preview-bridge","--port",String(a),"--cli-path",m],process.cwd(),Zt(o),{}),g=Kt(Q("yarn"),["dev","--host","127.0.0.1","--port",String(r)],o,Yt(o),ma(s,c));try{await kt(`http://127.0.0.1:${a}/__justo/health`),await kt(i)}catch(w){throw be(g),be(l),w}let p={appPid:g,bridgePid:l,previewUrl:i,bridgeUrl:s,streamUrl:c,cliEnv:"prod"};Kr(eo(o),`${JSON.stringify(p,null,2)}
|
|
816
|
+
`);let y=await na(i,n);return{ok:!0,path:o,previewUrl:i,bridgeUrl:s,streamUrl:c,cliEnv:"prod",appPid:g,bridgePid:l,logs:{app:Yt(o),bridge:Zt(o)},open:y}}import{writeFileSync as ha}from"node:fs";import{mkdtempSync as da,readFileSync as pa,rmSync as ga,writeFileSync as fa}from"node:fs";import{tmpdir as wa}from"node:os";import{join as io}from"node:path";import{spawnSync as ba}from"node:child_process";function Ca(e){return`'${e.replaceAll("'",`'"'"'`)}'`}function so(e,t){if(e==null)return;if(!Array.isArray(e)||e.some((o)=>typeof o!=="string"))throw Error(`${t} debe ser un arreglo de strings.`);return e}function ya(e){if(!Array.isArray(e))throw Error("variables debe ser un arreglo.");return e.map((t,o)=>{if(!t||typeof t!=="object"||Array.isArray(t))throw Error(`variables[${o}] debe ser un objeto.`);let r=t;if(typeof r.key!=="string"||!r.key)throw Error(`variables[${o}].key debe ser un string no vacío.`);if(typeof r.fieldType!=="string"||!r.fieldType)throw Error(`variables[${o}].fieldType debe ser un string no vacío.`);if(r.fieldParams!=null&&typeof r.fieldParams!=="string")throw Error(`variables[${o}].fieldParams debe ser un string.`);return{key:r.key,fieldType:r.fieldType,fieldParams:typeof r.fieldParams==="string"?r.fieldParams:void 0}})}function qa(e){if(!e||typeof e!=="object"||Array.isArray(e))throw Error("El archivo editado debe contener un objeto JSON.");let t=e;if(typeof t.name!=="string"||!t.name.trim())throw Error("name debe ser un string no vacío.");if(t.description!=null&&typeof t.description!=="string")throw Error("description debe ser un string.");if(typeof t.collection!=="string"||!t.collection.trim())throw Error("collection debe ser un string no vacío.");if(typeof t.pipeline!=="string")throw Error("pipeline debe ser un string.");return{name:t.name.trim(),description:t.description?.trim()||void 0,collection:t.collection.trim(),allowedUsersIds:so(t.allowedUsersIds,"allowedUsersIds")??[],tags:so(t.tags,"tags")??[],pipeline:t.pipeline,variables:ya(t.variables)}}function co(e){let t=process.env.VISUAL||process.env.EDITOR||"vi",o=da(io(wa(),"team-cli-query-")),r=io(o,"aggregation-query.json");fa(r,`${JSON.stringify(e,null,2)}
|
|
817
|
+
`);let a=`${t} ${Ca(r)}`,n=ba(a,{shell:!0,stdio:"inherit"});if(n.error)throw Error(`No se pudo abrir el editor "${t}": ${n.error.message}`);if(n.status!==0)throw Error(`El editor terminó con código ${n.status}.`);try{let i=pa(r,"utf-8");if(!i.trim())throw Error("El archivo quedó vacío.");let s;try{s=JSON.parse(i)}catch{throw Error("El archivo editado no contiene JSON válido.")}return qa(s)}finally{ga(o,{recursive:!0,force:!0})}}function v(){if(!d())throw Error("Debes iniciar sesión primero. Recomendado: team-cli auth request-code --email <email> y luego team-cli auth login-with-token --email <email> --token <token> --code <CODIGO>")}function O(e,t){let o=e[3];if(!o)throw Error(`Uso: ${t}`);return o}function V(e){if(!e.params)return{};try{return JSON.parse(e.params)}catch{throw Error("--params debe ser un JSON válido.")}}function uo(e){let t=e.limit;if(!t)throw Error("--limit es requerido. Ejemplo: --limit 1000");let o=Number(t);if(!Number.isInteger(o)||o<=0)throw Error("--limit debe ser un entero positivo.");return o}function Je(e){if(typeof e!=="string")return e;try{return JSON.parse(e)}catch{return{value:e}}}async function L(e){return(await u({service:"data",query:`query ($aggregationQueryId: String) {
|
|
440
818
|
aggregationQuery(aggregationQueryId: $aggregationQueryId) {
|
|
441
819
|
_id
|
|
442
820
|
name
|
|
@@ -452,9 +830,11 @@ Notas:
|
|
|
452
830
|
fieldParams
|
|
453
831
|
}
|
|
454
832
|
}
|
|
455
|
-
}`,variables:{aggregationQueryId:e}})).aggregationQuery}function
|
|
833
|
+
}`,variables:{aggregationQueryId:e}})).aggregationQuery}function mo(e){return{name:e.name,description:e.description,collection:e.collection,allowedUsersIds:e.allowedUsersIds??[],tags:e.tags??[],pipeline:e.pipeline,variables:e.variables??[]}}async function We(e,t){let o=await u({service:"data",query:`mutation ($aggregationQueryId: String, $params: JSON) {
|
|
456
834
|
testAggregationQuery(aggregationQueryId: $aggregationQueryId, params: $params)
|
|
457
|
-
}`,variables:{aggregationQueryId:e,params:
|
|
835
|
+
}`,variables:{aggregationQueryId:e,params:t}});return Je(o.testAggregationQuery)}function Ia(e){try{return JSON.parse(e).error||e}catch{return e}}async function lo(e,t,o){let r=await fetch(`${h("data")}/aggregation-queries/${e}/run`,{method:"POST",headers:await ve(),body:JSON.stringify({params:t,limit:o}),signal:AbortSignal.timeout(315000)});if(!r.ok){let m=await r.text();throw Error(Ia(m)||"No se pudo ejecutar el query.")}if(!r.body)throw Error("El servidor no devolvió un stream de datos.");let a=r.body.getReader(),n=new TextDecoder,i="",s=0;while(!0){let{done:m,value:l}=await a.read();if(m)break;let g=n.decode(l,{stream:!0});process.stdout.write(g),i+=g;let p=i.indexOf(`
|
|
836
|
+
`);while(p>=0){if(i.slice(0,p).trim())s++;i=i.slice(p+1),p=i.indexOf(`
|
|
837
|
+
`)}}let c=n.decode();if(c)process.stdout.write(c),i+=c;if(i.trim())s++;return{ok:!0,queryId:e,limit:o,rows:s}}async function _e(e,t){await u({service:"data",query:`mutation ($aggregationQueryId: String, $aggregationQuery: UpdateAggregationQueryInput) {
|
|
458
838
|
updateAggregationQuery(
|
|
459
839
|
aggregationQueryId: $aggregationQueryId
|
|
460
840
|
aggregationQuery: $aggregationQuery
|
|
@@ -467,7 +847,7 @@ Notas:
|
|
|
467
847
|
tags
|
|
468
848
|
currentVersionIndex
|
|
469
849
|
}
|
|
470
|
-
}`,variables:{aggregationQueryId:e,aggregationQuery:{name:
|
|
850
|
+
}`,variables:{aggregationQueryId:e,aggregationQuery:{name:t.name,description:t.description,collection:t.collection,allowedUsersIds:t.allowedUsersIds,tags:t.tags}}}),await u({service:"data",query:`mutation ($aggregationQueryId: String, $pipeline: String, $variables: [AggregationQueryVariableInput]) {
|
|
471
851
|
addAggregationQueryVersion(
|
|
472
852
|
aggregationQueryId: $aggregationQueryId
|
|
473
853
|
pipeline: $pipeline
|
|
@@ -476,7 +856,7 @@ Notas:
|
|
|
476
856
|
_id
|
|
477
857
|
currentVersionIndex
|
|
478
858
|
}
|
|
479
|
-
}`,variables:{aggregationQueryId:e,pipeline:
|
|
859
|
+
}`,variables:{aggregationQueryId:e,pipeline:t.pipeline,variables:t.variables}})}async function po(){return(await u({service:"data",query:`mutation {
|
|
480
860
|
createAggregationQuery {
|
|
481
861
|
_id
|
|
482
862
|
name
|
|
@@ -492,7 +872,7 @@ Notas:
|
|
|
492
872
|
fieldParams
|
|
493
873
|
}
|
|
494
874
|
}
|
|
495
|
-
}`})).createAggregationQuery}function
|
|
875
|
+
}`})).createAggregationQuery}function $a(e){if(!Array.isArray(e))throw Error("El preview del query debe devolver un arreglo para usar AI edit.");return e}async function xa(e){let t=await u({service:"messenger",query:`mutation generateAdminQuery(
|
|
496
876
|
$prompt: String
|
|
497
877
|
$name: String
|
|
498
878
|
$description: String
|
|
@@ -518,13 +898,13 @@ Notas:
|
|
|
518
898
|
aggregationDescription
|
|
519
899
|
aggregationName
|
|
520
900
|
}
|
|
521
|
-
}`,variables:e});if(!
|
|
522
|
-
`);try{let
|
|
523
|
-
`);let s=await
|
|
524
|
-
`);let n=(await
|
|
901
|
+
}`,variables:e});if(!t.generateAdminQuery?.pipeline||!t.generateAdminQuery.fullCollectionName)throw Error("La IA no devolvió una versión válida del query.");return t.generateAdminQuery}async function go(){return v(),await po()}async function fo(e){v();let t=O(e,"team-cli data queries edit <queryId>"),o=await L(t),r=co(mo(o));return await _e(t,r),{ok:!0,queryId:t,name:r.name,collection:r.collection}}async function wo(e,t){v();let o=O(e,"team-cli data queries ai-edit <queryId> --prompt '<texto>' [--params '<json>']"),r=await L(o),a=t.prompt||await z("Describe los cambios para la IA: ");if(!a)throw Error("Debes indicar un prompt para AI edit.");let n=V(t),i;if(t.params){C(`Obteniendo preview del query actual...
|
|
902
|
+
`);try{let c=await We(o,n);i=$a(c)}catch(c){let m=c instanceof Error?c.message:String(c);throw Error(`No se pudo obtener el preview para AI edit: ${m}`)}}C(`Generando propuesta con IA...
|
|
903
|
+
`);let s=await xa({prompt:a,fullCollectionName:r.collection,pipeline:r.pipeline,preview:i,description:r.description,name:r.name,variables:r.variables});return await _e(o,{name:r.name==="Nuevo query"?s.aggregationName||r.name:r.name,description:r.description||s.aggregationDescription,collection:s.fullCollectionName,allowedUsersIds:r.allowedUsersIds??[],tags:r.tags??[],pipeline:s.pipeline,variables:s.variables??[]}),{ok:!0,queryId:o,responseText:s.responseText,collection:s.fullCollectionName,name:s.aggregationName,description:s.aggregationDescription}}async function bo(e){v();let t=O(e,"team-cli data queries view <queryId>");return await L(t)}async function Co(e){v();let t=O(e,"team-cli data queries view-pipeline <queryId>"),o=await L(t);return{queryId:t,pipeline:o.pipeline}}async function yo(e,t){v();let o=O(e,"team-cli data queries preview <queryId> --params '<json>'"),r=V(t),a=await We(o,r);return Je(a)}async function qo(e,t){v();let o=O(e,"team-cli data queries run <queryId> --limit <n> --params '<json>'"),r=V(t),a=uo(t);return await lo(o,r,a),{__streamHandled:!0}}function Sa(e){return new Promise((t)=>setTimeout(t,e))}async function Io(e,t){v();let o=O(e,"team-cli data queries download <queryId> --params '<json>'"),r=V(t);if(!t.path)throw Error("--path es requerido. Ejemplo: --path resultado.xlsx");C(`Iniciando descarga...
|
|
904
|
+
`);let n=(await u({service:"data",query:`mutation ($aggregationQueryId: String, $params: JSON) {
|
|
525
905
|
downloadAggregationQueryData(aggregationQueryId: $aggregationQueryId, params: $params)
|
|
526
|
-
}`,variables:{aggregationQueryId:
|
|
527
|
-
`);let
|
|
906
|
+
}`,variables:{aggregationQueryId:o,params:r}})).downloadAggregationQueryData;C(`Reporte en proceso (${n})...
|
|
907
|
+
`);let i=null;while(!i){await Sa(1000);let m=await u({service:"data",query:`query ($id: String) {
|
|
528
908
|
getAsyncReport(id: $id) {
|
|
529
909
|
_id
|
|
530
910
|
status
|
|
@@ -532,15 +912,15 @@ Notas:
|
|
|
532
912
|
fileUrl
|
|
533
913
|
}
|
|
534
914
|
getAsyncReportRecordsCount(id: $id)
|
|
535
|
-
}`,variables:{id:n}}),
|
|
915
|
+
}`,variables:{id:n}}),l=m.getAsyncReport,g=m.getAsyncReportRecordsCount;if(l.status==="error")throw Error("El reporte falló al generarse.");if(l.fileUrl)i=l.fileUrl;else{let p=l.estimatedRecordsCount?` (~${l.estimatedRecordsCount} registros)`:"",y=g!=null?` ${g} procesados`:"";C(`\rGenerando...${p}${y}`)}}C(`
|
|
536
916
|
Descargando archivo...
|
|
537
|
-
`);let s=await fetch(
|
|
917
|
+
`);let s=await fetch(i);if(!s.ok)throw Error(`Error descargando archivo: ${s.status}`);let c=Buffer.from(await s.arrayBuffer());return ha(t.path,c),{ok:!0,queryId:o,asyncReportId:n,outputPath:t.path,fileUrl:i}}function Be(){return`team-cli data
|
|
538
918
|
|
|
539
919
|
Comandos de datos y reportes.
|
|
540
920
|
|
|
541
921
|
Recomendado:
|
|
542
922
|
Si necesitas obtener data y no existe un query listo, usa create + ai-edit.
|
|
543
|
-
Flujo sugerido: create -> ai-edit -> preview -> download.
|
|
923
|
+
Flujo sugerido: create -> ai-edit -> preview -> run o download.
|
|
544
924
|
|
|
545
925
|
Uso:
|
|
546
926
|
team-cli data queries <subcomando> [opciones]
|
|
@@ -570,12 +950,18 @@ Subcomandos:
|
|
|
570
950
|
Ejecutar un query de prueba.
|
|
571
951
|
Uso: team-cli data queries preview <queryId> --params '<json>' [--format toon|json]
|
|
572
952
|
|
|
953
|
+
run <queryId>
|
|
954
|
+
Ejecutar un query completo en streaming NDJSON.
|
|
955
|
+
Usa timeout de 5 minutos y read preference secondaryPreferred.
|
|
956
|
+
Uso: team-cli data queries run <queryId> --limit <n> [--params '<json>']
|
|
957
|
+
|
|
573
958
|
download <queryId>
|
|
574
959
|
Descargar resultado completo como Excel.
|
|
575
960
|
Uso: team-cli data queries download <queryId> --path <filepath> [--params '<json>'] [--format toon|json]
|
|
576
961
|
|
|
577
962
|
Opciones:
|
|
578
963
|
--params '<json>' Parametros del query. Default: {}
|
|
964
|
+
--limit <n> Requerido para run. Máximo 10000 por request.
|
|
579
965
|
--prompt '<texto>' Prompt para ai-edit. Si no viene, se pide interactivamente.
|
|
580
966
|
--format <toon|json>
|
|
581
967
|
--path <filepath> Requerido para download
|
|
@@ -586,262 +972,217 @@ Ejemplos:
|
|
|
586
972
|
team-cli data queries ai-edit abc123 --prompt 'Filtra solo ordenes canceladas'
|
|
587
973
|
team-cli data queries ai-edit abc123 --prompt 'Ajusta el pipeline' --params '{"websiteId":"w1"}'
|
|
588
974
|
team-cli data queries preview abc123 --params '{"startDate": "2026-01-01"}'
|
|
589
|
-
team-cli data queries
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
The CLI must be authenticated. Check with:
|
|
602
|
-
\`\`\`bash
|
|
603
|
-
npx @getjusto/team-cli auth status
|
|
604
|
-
\`\`\`
|
|
975
|
+
team-cli data queries run abc123 --limit 1000 --params '{"startDate": "2026-01-01"}'
|
|
976
|
+
team-cli data queries download abc123 --params '{"startDate": "2026-01-01"}' --path resultado.xlsx`}var ho=["main","auth","webdata","preferences","buckets","reservations","data","finances","url-shortener","files","tabs","commander","experiments","sales","delivery","payments","addresses","royalty","marketing","api","messenger","invoice","drivers-server"],$o=`
|
|
977
|
+
query ResolverInfo($name: ID!, $mutation: Boolean!) {
|
|
978
|
+
params(name: $name, mutation: $mutation) {
|
|
979
|
+
name
|
|
980
|
+
params
|
|
981
|
+
result
|
|
982
|
+
basicResultQuery
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
`;function Ea(e){if(!e)throw Error("Uso: team-cli graphql <servicio> '<query>' [--variables '<json>'] [--format toon|json]");if(!ho.includes(e))throw Error(`Servicio "${e}" no válido. Servicios disponibles: ${ho.join(", ")}`)}async function ja(e,t){let o;try{let r=await u({service:e,query:$o,variables:{name:t,mutation:!1}});return{service:e,operationName:t,operationType:"query",info:r.params}}catch(r){o=r}try{let r=await u({service:e,query:$o,variables:{name:t,mutation:!0}});return{service:e,operationName:t,operationType:"mutation",info:r.params}}catch(r){let a=o instanceof Error?o.message:"",n=r instanceof Error?r.message:"";if(a.includes('Cannot query field "params"')||n.includes('Cannot query field "params"'))throw Error(`El servicio "${e}" no expone metadata de resolvers por GraphQL.`);throw o instanceof Error?o:r}}async function xo(e,t){let o=e[1],r=e[2],a=e[2];if(!d())throw Error("Debes iniciar sesión primero. Recomendado: team-cli auth request-code --email <email> y luego team-cli auth login-with-token --email <email> --token <token> --code <CODIGO>");if(Ea(o),r==="info"){let s=e[3];if(!s)throw Error("Uso: team-cli graphql <servicio> info <queryName|mutationName> [--format toon|json]");return await ja(o,s)}if(!a)throw Error("Uso: team-cli graphql <servicio> '<query>' [--variables '<json>'] [--format toon|json]");let n;if(t.variables)try{n=JSON.parse(t.variables)}catch{throw Error("Las variables deben ser un JSON válido.")}return await u({service:o,query:a,variables:n})}function So(){return Object.keys(ie)}function Aa(){return So().map((e)=>{let t=ie[e].prod;return`- \`${e}\`: \`${t}/graphql\``}).join(`
|
|
986
|
+
`)}function Eo(){let t=So().join(", "),o=Aa();return`team-cli graphql
|
|
605
987
|
|
|
606
|
-
|
|
607
|
-
\`\`\`bash
|
|
608
|
-
npx @getjusto/team-cli auth login
|
|
609
|
-
\`\`\`
|
|
988
|
+
Ejecutar queries y mutations GraphQL.
|
|
610
989
|
|
|
611
|
-
|
|
990
|
+
Uso:
|
|
991
|
+
team-cli graphql <servicio> '<query>' [--variables '<json>'] [--format toon|json]
|
|
992
|
+
team-cli graphql <servicio> info <queryName|mutationName> [--format toon|json]
|
|
612
993
|
|
|
613
|
-
|
|
614
|
-
|
|
994
|
+
Comando info:
|
|
995
|
+
Consulta la metadata publicada por OrionJS para un query o mutation.
|
|
996
|
+
Devuelve el tipo de operación, los params serializados, el resultado y un basicResultQuery.
|
|
997
|
+
Si no indicas si es query o mutation, la CLI prueba ambas automáticamente.
|
|
615
998
|
|
|
616
|
-
|
|
999
|
+
Formato:
|
|
1000
|
+
Por defecto usa toon. Usa --format json para JSON estándar.
|
|
617
1001
|
|
|
618
|
-
### graphql — Run arbitrary GraphQL queries/mutations
|
|
619
1002
|
|
|
620
|
-
\`\`\`bash
|
|
621
|
-
npx @getjusto/team-cli graphql <service> '<query>' [--variables '<json>'] [--format toon|json]
|
|
622
|
-
\`\`\`
|
|
623
1003
|
|
|
624
|
-
|
|
1004
|
+
Servicios disponibles: ${t}.
|
|
625
1005
|
|
|
626
|
-
|
|
1006
|
+
Ejemplos:
|
|
627
1007
|
\`\`\`bash
|
|
628
1008
|
npx @getjusto/team-cli graphql main 'query { me { _id roles } }'
|
|
629
1009
|
npx @getjusto/team-cli graphql main 'query($id: ID) { user(userId: $id) { _id } }' --variables '{"id": "abc123"}'
|
|
630
1010
|
npx @getjusto/team-cli graphql tabs 'query { tab(tabId: "t123") { _id status } }' --format json
|
|
631
1011
|
\`\`\`
|
|
632
1012
|
|
|
633
|
-
### graphql info
|
|
1013
|
+
### graphql info
|
|
634
1014
|
|
|
635
|
-
|
|
1015
|
+
Úsalo cuando conoces el nombre del resolver pero no su contrato exacto.
|
|
636
1016
|
|
|
637
1017
|
\`\`\`bash
|
|
638
1018
|
npx @getjusto/team-cli graphql <service> info <queryName|mutationName> [--format toon|json]
|
|
639
1019
|
\`\`\`
|
|
640
1020
|
|
|
641
|
-
|
|
642
|
-
- \`operationType\`
|
|
643
|
-
- \`info.params\`
|
|
644
|
-
- \`info.result\`
|
|
645
|
-
- \`info.basicResultQuery\`
|
|
1021
|
+
Devuelve:
|
|
1022
|
+
- \`operationType\`
|
|
1023
|
+
- \`info.params\`
|
|
1024
|
+
- \`info.result\`
|
|
1025
|
+
- \`info.basicResultQuery\`
|
|
646
1026
|
|
|
647
|
-
|
|
1027
|
+
Ejemplos:
|
|
648
1028
|
\`\`\`bash
|
|
649
1029
|
npx @getjusto/team-cli graphql main info website
|
|
650
1030
|
npx @getjusto/team-cli graphql auth info requestLoginCode --format json
|
|
651
1031
|
\`\`\`
|
|
652
1032
|
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
-
|
|
666
|
-
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
- \`
|
|
695
|
-
- \`
|
|
696
|
-
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
-
|
|
700
|
-
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
### data queries create — Create a new admin query
|
|
730
|
-
|
|
731
|
-
\`\`\`bash
|
|
732
|
-
npx @getjusto/team-cli data queries create [--format toon|json]
|
|
733
|
-
\`\`\`
|
|
734
|
-
|
|
735
|
-
Creates a new aggregation query in the data service. The default query is usually named \`Nuevo query\` and points to \`justo.users\`. Use the returned \`_id\` with \`edit\`, \`ai-edit\`, \`view\`, \`preview\`, or \`download\`.
|
|
736
|
-
|
|
737
|
-
### data queries edit — Edit a query manually in the local editor
|
|
738
|
-
|
|
739
|
-
\`\`\`bash
|
|
740
|
-
npx @getjusto/team-cli data queries edit <queryId> [--format toon|json]
|
|
1033
|
+
### Mapa de servicios GraphQL
|
|
1034
|
+
|
|
1035
|
+
Usa esto para mapear una URL GraphQL al valor correcto de \`team-cli graphql <service>\`.
|
|
1036
|
+
|
|
1037
|
+
${o}`}import{resolve as Pa}from"node:path";import{readdirSync as Na,readFileSync as va,statSync as Ra}from"node:fs";import{gzipSync as Ta}from"node:zlib";import{join as Oa,relative as Ua,resolve as Qa}from"node:path";var Ie=512,Ja=2;function Wa(e){let t=e.replaceAll("\\","/");if(t.startsWith("/")||t.includes("../"))throw Error(`Ruta inválida en el space: ${e}`);return t}function _a(e){let t=Wa(e);if(Buffer.from(t).length<=100)return{name:t,prefix:""};let r=t.lastIndexOf("/");if(r<=0)throw Error(`La ruta es demasiado larga para el paquete del space: ${e}`);let a=t.slice(0,r),n=t.slice(r+1);if(Buffer.from(a).length>155||Buffer.from(n).length>100)throw Error(`La ruta es demasiado larga para el paquete del space: ${e}`);return{name:n,prefix:a}}function J(e,t,o,r){let a=Buffer.from(r);a.copy(e,t,0,Math.min(a.length,o))}function ee(e,t,o,r){let a=Math.max(0,Math.trunc(r)).toString(8).padStart(o-1,"0");J(e,t,o,`${a}\x00`)}function Ba(e){let t=Buffer.alloc(Ie,0),{name:o,prefix:r}=_a(e.path);J(t,0,100,o),ee(t,100,8,e.mode),ee(t,108,8,0),ee(t,116,8,0),ee(t,124,12,e.content.length),ee(t,136,12,e.mtime),t.fill(32,148,156),J(t,156,1,"0"),J(t,257,6,"ustar"),J(t,263,2,"00"),J(t,345,155,r);let a=0;for(let i of t)a+=i;let n=`${a.toString(8).padStart(6,"0")}\x00 `;return J(t,148,8,n),t}function Ma(e){let t=e%Ie;return t===0?0:Ie-t}function jo(e,t=e){return Na(t,{withFileTypes:!0}).sort((r,a)=>r.name.localeCompare(a.name)).flatMap((r)=>{let a=Oa(t,r.name);if(r.isDirectory())return jo(e,a);if(!r.isFile())return[];let n=Ua(e,a),i=Ra(a);return[{path:n,content:va(a),mode:i.mode&511,mtime:Math.floor(i.mtimeMs/1000)}]})}function Ao(e){let t=Qa(e),o=jo(t);if(!o.length)throw Error("El build del space no contiene archivos para publicar");let r=[];for(let a of o){r.push(Ba(a)),r.push(a.content);let n=Ma(a.content.length);if(n>0)r.push(Buffer.alloc(n,0))}return r.push(Buffer.alloc(Ie*Ja,0)),Ta(Buffer.concat(r))}function Me(){if(!d())throw Error("Debes iniciar sesión primero. Recomendado: team-cli auth request-code --email <email> y luego team-cli auth login-with-token --email <email> --token <token> --code <CODIGO>")}function te(e,t,o){let r=e[t];if(!r)throw Error(`Falta --${t}. Ejemplo: ${o}`);return r}function No(e,t){let o=e[2];if(!o)throw Error(`Uso: ${t}`);return o}function Pe(){let e=se();if(e==="local")return"http://intra.localhost:5173";if(e==="develop")return"https://intra.bejusto.com";return"https://intra.getjusto.com"}async function Ga(e,t){let o=await Ne(),r=await fetch(`${h("data")}/spaces/publish/${e}`,{method:"POST",headers:{"Content-Type":"application/gzip",...o?{"X-ORION-JWT":o}:{}},body:t}),a=await r.json();if(!r.ok||a.error)throw Error(a.error||"No se pudo publicar el space.");return a}function Ge(){return`team-cli spaces
|
|
1038
|
+
|
|
1039
|
+
Spaces son aplicaciones internas en React, pensadas para que las construyan agentes.
|
|
1040
|
+
El flujo oficial parte con \`spaces init\` y \`spaces publish\` solo acepta apps creadas así.
|
|
1041
|
+
|
|
1042
|
+
Cada space:
|
|
1043
|
+
- vive en data
|
|
1044
|
+
- se desarrolla como app React + Vite
|
|
1045
|
+
- viene con Tailwind y todos los componentes shadcn instalados
|
|
1046
|
+
- publica el resultado de \`yarn build\` a S3 en \`spaces/[slug]/[version]/files/*\`
|
|
1047
|
+
- se sirve en \`/spaces/[slug]\`
|
|
1048
|
+
- el build debe generar \`dist/index.html\`
|
|
1049
|
+
- recibe automáticamente \`<base href="/spaces/[slug]/">\` al servir HTML
|
|
1050
|
+
- además reescribe rutas HTML/CSS que empiecen con \`/\` para que \`/image.jpg\` termine en \`/spaces/[slug]/image.jpg\`
|
|
1051
|
+
- al abrirse desde intra, siembra una cookie del space por 24 horas
|
|
1052
|
+
- esa cookie da acceso al HTML, assets y \`window.justo.cli(...)\` dentro del space
|
|
1053
|
+
- todos los HTML reciben automáticamente \`window.justo.cli(command)\`
|
|
1054
|
+
- \`window.justo.cli(...)\` devuelve Promises, entrega JSON parseado y hace throw en errores
|
|
1055
|
+
- para queries grandes también reciben \`window.justo.stream(command, onRow)\`
|
|
1056
|
+
- \`window.justo.stream(...)\` consume NDJSON, parsea cada fila a JSON y llama tu callback
|
|
1057
|
+
- \`spaces init\`, \`spaces preview\` y \`spaces publish\` funcionan en macOS, Linux y Windows sin depender de \`tar\` global
|
|
1058
|
+
|
|
1059
|
+
Flujo sugerido para agentes:
|
|
1060
|
+
1. \`team-cli spaces init --path ./mi-space-app\`
|
|
1061
|
+
2. \`team-cli spaces create --name '...' --description '...' --slug mi-space\`
|
|
1062
|
+
3. \`team-cli spaces preview --path ./mi-space-app\`
|
|
1063
|
+
4. desarrollar la app React dentro de esa carpeta
|
|
1064
|
+
5. \`team-cli spaces publish <spaceId> --path ./mi-space-app\`
|
|
1065
|
+
6. abrir \`${Pe()}/spaces/<slug>\`
|
|
1066
|
+
|
|
1067
|
+
Qué crea \`spaces init\`:
|
|
1068
|
+
- Vite + React + TypeScript
|
|
1069
|
+
- Tailwind listo para usar
|
|
1070
|
+
- todos los componentes shadcn disponibles en \`src/components/ui\`
|
|
1071
|
+
- charts listos con el wrapper de shadcn + \`recharts\`
|
|
1072
|
+
- mapas listos con \`react-leaflet\` + MapTiler/OpenStreetMap
|
|
1073
|
+
- helper \`justoCli(...)\` en \`src/lib/justo.ts\`
|
|
1074
|
+
- helper \`justoStream(...)\` en \`src/lib/justo.ts\`
|
|
1075
|
+
- ejemplo inicial en \`src/App.tsx\`
|
|
1076
|
+
- configuración para que Vite construya con rutas relativas y funcione dentro del space
|
|
1077
|
+
|
|
1078
|
+
Mapas:
|
|
1079
|
+
- el starter reutiliza el mismo token de MapTiler que ya usa vite-fronts
|
|
1080
|
+
- no necesitas configurar una key adicional para empezar
|
|
1081
|
+
|
|
1082
|
+
Reglas de diseño para agentes:
|
|
1083
|
+
- preferir siempre componentes shadcn antes que UI custom
|
|
1084
|
+
- usar solo light mode
|
|
1085
|
+
- usar paleta de colores neutra
|
|
1086
|
+
- si hace falta color de acento, que sea secundario y sobrio, no la base del diseño
|
|
1087
|
+
|
|
1088
|
+
Qué hace \`spaces preview\`:
|
|
1089
|
+
- levanta Vite localmente para esa app
|
|
1090
|
+
- levanta un bridge local para \`justoCli(...)\`
|
|
1091
|
+
- ese bridge ejecuta \`team-cli\` contra \`prod\`
|
|
1092
|
+
- devuelve la URL local para abrir con browser
|
|
1093
|
+
- si envías \`--open\`, intenta abrir la preview en el navegador por defecto del sistema
|
|
1094
|
+
- \`--open\` es ideal para ir mostrándole al usuario el dashboard mientras el agente lo va construyendo
|
|
1095
|
+
|
|
1096
|
+
Ejemplo desde el propio HTML del space:
|
|
1097
|
+
\`\`\`js
|
|
1098
|
+
import {justoCli, justoStream} from '@/lib/justo'
|
|
1099
|
+
|
|
1100
|
+
const me = await justoCli("graphql main 'query { me { _id email roles } }'")
|
|
1101
|
+
const rows = await justoCli("data queries preview <queryId> --params '{\\"limit\\":10}'")
|
|
1102
|
+
await justoStream(
|
|
1103
|
+
"data queries run <queryId> --limit 1000 --params '{\\"websiteId\\":\\"w1\\"}'",
|
|
1104
|
+
row => {
|
|
1105
|
+
console.log(row)
|
|
1106
|
+
},
|
|
1107
|
+
)
|
|
741
1108
|
\`\`\`
|
|
742
1109
|
|
|
743
|
-
|
|
744
|
-
- \`
|
|
745
|
-
- \`description\`
|
|
746
|
-
- \`
|
|
747
|
-
- \`
|
|
748
|
-
- \`
|
|
749
|
-
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
1110
|
+
Comandos:
|
|
1111
|
+
- \`spaces init --path ./mi-space-app\`
|
|
1112
|
+
- \`spaces create --name '...' --description '...' --slug my-space\`
|
|
1113
|
+
- \`spaces preview --path ./mi-space-app [--open]\`
|
|
1114
|
+
- \`spaces publish <spaceId> --path ./mi-space-app\`
|
|
1115
|
+
- \`spaces archive <spaceId>\`
|
|
1116
|
+
`}async function vo(e){let t=te(e,"path","team-cli spaces init --path ./mi-space-app");return Xt(t)}async function Ro(e){return await no(e)}async function To(e){Me();let t=te(e,"name","team-cli spaces create --name 'Mi space' --description '...' --slug mi-space"),o=te(e,"description","team-cli spaces create --name 'Mi space' --description 'Sitio interno' --slug mi-space"),r=te(e,"slug","team-cli spaces create --name 'Mi space' --description '...' --slug mi-space"),a=await u({service:"data",query:`mutation ($name: String, $description: String, $slug: String) {
|
|
1117
|
+
createSpace(name: $name, description: $description, slug: $slug) {
|
|
1118
|
+
_id
|
|
1119
|
+
name
|
|
1120
|
+
description
|
|
1121
|
+
slug
|
|
1122
|
+
currentVersion
|
|
1123
|
+
createdAt
|
|
1124
|
+
createdByEmail
|
|
1125
|
+
createdById
|
|
1126
|
+
}
|
|
1127
|
+
}`,variables:{name:t,description:o,slug:r}});return{...a.createSpace,intraUrl:`${Pe()}/spaces/${a.createSpace.slug}`,serveUrl:`${h("data")}/spaces/${a.createSpace.slug}`}}async function Oo(e,t){Me();let o=No(e,"team-cli spaces publish <spaceId> --path ./mi-space-app"),r=te(t,"path","team-cli spaces publish <spaceId> --path ./mi-space-app"),a=Ft(r),n=Ao(a),i=await Ga(o,n);return{...i,intraUrl:i.slug?`${Pe()}/spaces/${i.slug}`:void 0,serveUrl:i.slug?`${h("data")}/spaces/${i.slug}`:void 0,builtFrom:Pa(r)}}async function Uo(e){Me();let t=No(e,"team-cli spaces archive <spaceId>");return(await u({service:"data",query:`mutation ($spaceId: String) {
|
|
1128
|
+
archiveSpace(spaceId: $spaceId) {
|
|
1129
|
+
_id
|
|
1130
|
+
name
|
|
1131
|
+
description
|
|
1132
|
+
slug
|
|
1133
|
+
currentVersion
|
|
1134
|
+
createdAt
|
|
1135
|
+
createdByEmail
|
|
1136
|
+
createdById
|
|
1137
|
+
archivedAt
|
|
1138
|
+
}
|
|
1139
|
+
}`,variables:{spaceId:t}})).archiveSpace}function Qo(e){return`team-cli
|
|
761
1140
|
|
|
762
|
-
|
|
1141
|
+
Herramienta CLI para el equipo Justo.
|
|
763
1142
|
|
|
764
|
-
|
|
765
|
-
npx @getjusto/team-cli data queries ai-edit <queryId> --prompt '<text>' [--params '<json>'] [--format toon|json]
|
|
766
|
-
\`\`\`
|
|
1143
|
+
${e}
|
|
767
1144
|
|
|
768
|
-
|
|
1145
|
+
Si necesitas obtener data y no existe un query listo, usa create + ai-edit.
|
|
1146
|
+
Flujo sugerido: create -> ai-edit -> preview -> run o download.
|
|
769
1147
|
|
|
770
|
-
|
|
771
|
-
- \`--prompt\` is required unless you want the CLI to ask interactively
|
|
772
|
-
- if you pass \`--params\`, the CLI first runs \`preview\` on the current query and sends those rows to the AI as context
|
|
773
|
-
- if preview fails, the command stops with a clear error instead of silently continuing
|
|
774
|
-
- if the AI returns an invalid response, the command fails before saving
|
|
1148
|
+
## Login recomendado para agentes
|
|
775
1149
|
|
|
776
|
-
|
|
1150
|
+
Pide el email al usuario que te esta hablando y usa el flujo no interactivo:
|
|
777
1151
|
\`\`\`bash
|
|
778
|
-
npx @getjusto/team-cli
|
|
779
|
-
|
|
780
|
-
--format json
|
|
1152
|
+
npx @getjusto/team-cli auth request-code --email <email>
|
|
1153
|
+
npx @getjusto/team-cli auth login-with-token --email <email> --token <token> --code <CODIGO>
|
|
781
1154
|
\`\`\`
|
|
782
1155
|
|
|
783
|
-
|
|
1156
|
+
## Opciones globales
|
|
784
1157
|
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
1158
|
+
- \`--env <local|develop|prod>\` — Environment (default: prod)
|
|
1159
|
+
- \`--format toon|json\` — Output format (default: toon)
|
|
1160
|
+
- \`--version\`
|
|
1161
|
+
- \`--help\`
|
|
788
1162
|
|
|
789
|
-
|
|
1163
|
+
## Comandos
|
|
790
1164
|
|
|
791
|
-
|
|
1165
|
+
Cada grupo de comandos tiene su propia ayuda. Usa \`--help\` para ver los comandos disponibles (ej: npx @getjusto/team-cli spaces --help)
|
|
792
1166
|
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
1167
|
+
- \`auth\` — Gestión de sesión
|
|
1168
|
+
- \`graphql\` — Ejecutar queries y mutations GraphQL
|
|
1169
|
+
- \`admin\` — Comandos administrativos con contexto de website
|
|
1170
|
+
- \`data\` — Datos y reportes. Puede obtener data de todas las bases de datos de Justo
|
|
1171
|
+
- \`spaces\` — Crea apps React para Spaces con \`spaces init\`, publícalas con \`spaces publish\` y compártelas en intra.
|
|
796
1172
|
|
|
797
|
-
|
|
1173
|
+
## Tips
|
|
798
1174
|
|
|
799
|
-
###
|
|
1175
|
+
### Obten el websiteId usando admin search
|
|
800
1176
|
|
|
1177
|
+
A veces los usuarios de este cli le dicen marcas
|
|
801
1178
|
\`\`\`bash
|
|
802
|
-
npx @getjusto/team-cli
|
|
1179
|
+
npx @getjusto/team-cli admin search <text> [--limit <n>] [--page <n>] [--only-active true|false]
|
|
803
1180
|
\`\`\`
|
|
804
1181
|
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
## Output Format
|
|
808
|
-
|
|
809
|
-
Default output is TOON (Token-Oriented Object Notation), a compact human-readable format. Use \`--format json\` for standard JSON output.
|
|
810
|
-
|
|
811
|
-
## Typical Workflow
|
|
812
|
-
|
|
813
|
-
1. Create a query: \`data queries create\`
|
|
814
|
-
2. Edit it manually with \`data queries edit <id>\` or ask AI with \`data queries ai-edit <id> --prompt '...'\`
|
|
815
|
-
3. View the final metadata and pipeline: \`data queries view <id>\` and \`data queries view-pipeline <id>\`
|
|
816
|
-
4. Preview with params when needed: \`data queries preview <id> --params '{"startDate": "2026-01-01"}'\`
|
|
817
|
-
5. Download full data: \`data queries download <id> --params '{"startDate": "2026-01-01"}' --path output.xlsx\`
|
|
818
|
-
`}function jo(){return{skill:Fr()}}var{positional:l,flags:m}=qe(process.argv.slice(2));if(m.env)be(m.env);var G=l[0],R=l[1];function Eo(){let e=g();return`team-cli
|
|
819
|
-
|
|
820
|
-
Herramienta CLI para el equipo Justo.
|
|
821
|
-
|
|
822
|
-
${e?`Sesión: ${e.email}`:"Sesión: no iniciada"}
|
|
823
|
-
|
|
824
|
-
Uso:
|
|
825
|
-
team-cli <comando> [opciones]
|
|
826
|
-
|
|
827
|
-
Comandos:
|
|
828
|
-
auth
|
|
829
|
-
Gestión de sesión.
|
|
830
|
-
|
|
831
|
-
admin
|
|
832
|
-
Comandos administrativos con contexto de website.
|
|
833
|
-
|
|
834
|
-
graphql
|
|
835
|
-
Ejecutar queries y mutations GraphQL.
|
|
836
|
-
|
|
837
|
-
data
|
|
838
|
-
Datos y reportes.
|
|
1182
|
+
### Crea queries para usar en los dashboards
|
|
839
1183
|
|
|
840
|
-
|
|
841
|
-
|
|
1184
|
+
Crea queries personalizadas usando \`create\` y \`ai-edit\` para generar consultas a la base de datos y luego crear un dashboard que las use
|
|
1185
|
+
para mostrar datos. Usa \`preview\` para iterar rápido, \`run\` para consumir NDJSON en streaming y \`download\` para Excel.
|
|
1186
|
+
También puedes usar queries para poblar selectores y otras partes de la interfaz del space.
|
|
842
1187
|
|
|
843
|
-
|
|
844
|
-
--env <local|develop|prod>
|
|
845
|
-
--version
|
|
846
|
-
--help
|
|
847
|
-
--format <toon|json>`}async function Mr(){try{let e;if(m.version)e={version:"0.0.5"};else if(m.help&&!G){d(Eo());return}else if(G==="auth")if(R==="--help"||m.help){d(ue());return}else if(R==="login")e=await Oe();else if(R==="login-with-token")e=await We(m);else if(R==="request-code")e=await Ge(m);else if(R==="logout")e=await Je();else if(R==="status")e=await Be();else{d(ue());return}else if(G==="admin"){let o=l[1],r=l[2],t=l[3],i=l[4];if(!o||o==="--help"){d(V());return}else if(o==="search"&&m.help){d(De());return}else if(o==="search")e=await He(l,m);else if(!r||r==="--help"){d(V());return}else if(r==="show")e=await Xe(o);else if(r==="stores"&&t==="list")e=await ke(o);else if(r==="coupons"&&(!t||t==="--help")){d(Z());return}else if(r==="coupons"&&t==="create"&&m.help){d(to());return}else if(r==="coupons"&&t==="update"&&m.help){d(io());return}else if(r==="coupons"&&t==="codes"&&l[4]==="create"&&m.help){d(mo());return}else if(r==="coupons"&&m.help){d(Z());return}else if(r==="coupons"&&t==="list")e=await Ve(o,m);else if(r==="coupons"&&t==="show"){if(!i)throw Error("Uso: team-cli admin <web> coupons show <couponId>");e=await Le(o,i)}else if(r==="coupons"&&t==="create")e=await eo(o,m);else if(r==="coupons"&&t==="update"){if(!i)throw Error("Uso: team-cli admin <web> coupons update <couponId> --input '<json>'");e=await oo(o,i,m)}else if(r==="coupons"&&t==="delete"){if(!i)throw Error("Uso: team-cli admin <web> coupons delete <couponId>");e=await ro(o,i)}else if(r==="coupons"&&t==="codes"){let n=l[4],a=l[5];if(!n||n==="--help"){d(Z());return}else if(n==="list"){if(!a)throw Error("Uso: team-cli admin <web> coupons codes list <couponId>");e=await no(o,a,m)}else if(n==="create"){if(!a)throw Error("Uso: team-cli admin <web> coupons codes create <couponId> --input '<json>'");e=await ao(o,a,m)}else if(n==="create-random"){if(!a)throw Error("Uso: team-cli admin <web> coupons codes create-random <couponId> --quantity <n>");e=await so(o,a,m)}else if(n==="delete"){if(!a)throw Error(`Uso: team-cli admin <web> coupons codes delete <couponId> --ids '["id1"]'`);e=await co(o,a,m)}else{d(Z());return}}else{d(V());return}}else if(G==="graphql")if(R==="--help"||m.help){d(Fe());return}else e=await _e(l,m);else if(G==="get-skill")e=jo();else if(G==="data"){let o=l[1],r=l[2];if(m.help||R==="--help"){d(fe());return}else if(o==="queries"&&r==="create")e=await fo();else if(o==="queries"&&r==="edit")e=await bo(l);else if(o==="queries"&&r==="ai-edit")e=await yo(l,m);else if(o==="queries"&&r==="view")e=await qo(l);else if(o==="queries"&&r==="view-pipeline")e=await Co(l);else if(o==="queries"&&r==="preview")e=await Io(l,m);else if(o==="queries"&&r==="download")e=await ho(l,m);else{d(fe());return}}else{d(Eo());return}if(e!==void 0)Qe(e,m)}catch(e){Ne(e,m),process.exit(1)}}Mr();
|
|
1188
|
+
`}function Jo(){let e=d(),t=e?`Sesión: ${e.email}`:"Sesión: no iniciada";return Qo(t)}async function Wo(e){let{positional:t,flags:o}=re(e);if(o.env)Ve(o.env);let r=t[0],a=t[1];if(r==="__spaces-preview-bridge")return await ao(o);if(o.version)return{version:"0.0.6"};if(o.help&&!r)return Jo();if(r==="auth"){if(a==="--help"||o.help)return Te();if(a==="login")return await vt();if(a==="login-with-token")return await Rt(o);if(a==="request-code")return await Tt(o);if(a==="logout")return await Ot();if(a==="status")return await Ut();return Te()}if(r==="admin"){let n=t[1],i=t[2],s=t[3],c=t[4];if(!n||n==="--help")return me();if(n==="search"&&o.help)return Et();if(n==="search")return await St(t,o);if(!i||i==="--help")return me();if(i==="show")return await ct(n);if(i==="stores"&&s==="list")return await jt(n);if(i==="coupons"&&(!s||s==="--help"))return D();if(i==="coupons"&&s==="create"&&o.help)return $t();if(i==="coupons"&&s==="update"&&o.help)return xt();if(i==="coupons"&&s==="codes"&&t[4]==="create"&&o.help)return wt();if(i==="coupons"&&o.help)return D();if(i==="coupons"&&s==="list")return await Ct(n,o);if(i==="coupons"&&s==="show"){if(!c)throw Error("Uso: team-cli admin <web> coupons show <couponId>");return await yt(n,c)}if(i==="coupons"&&s==="create")return await qt(n,o);if(i==="coupons"&&s==="update"){if(!c)throw Error("Uso: team-cli admin <web> coupons update <couponId> --input '<json>'");return await It(n,c,o)}if(i==="coupons"&&s==="delete"){if(!c)throw Error("Uso: team-cli admin <web> coupons delete <couponId>");return await ht(n,c)}if(i==="coupons"&&s==="codes"){let m=t[4],l=t[5];if(!m||m==="--help")return D();if(m==="list"){if(!l)throw Error("Uso: team-cli admin <web> coupons codes list <couponId>");return await dt(n,l,o)}if(m==="create"){if(!l)throw Error("Uso: team-cli admin <web> coupons codes create <couponId> --input '<json>'");return await pt(n,l,o)}if(m==="create-random"){if(!l)throw Error("Uso: team-cli admin <web> coupons codes create-random <couponId> --quantity <n>");return await gt(n,l,o)}if(m==="delete"){if(!l)throw Error(`Uso: team-cli admin <web> coupons codes delete <couponId> --ids '["id1"]'`);return await ft(n,l,o)}return D()}return me()}if(r==="graphql"){if(a==="--help"||o.help)return Eo();return await xo(t,o)}if(r==="data"){let n=t[1],i=t[2];if(o.help||a==="--help")return Be();if(n==="queries"&&i==="create")return await go();if(n==="queries"&&i==="edit")return await fo(t);if(n==="queries"&&i==="ai-edit")return await wo(t,o);if(n==="queries"&&i==="view")return await bo(t);if(n==="queries"&&i==="view-pipeline")return await Co(t);if(n==="queries"&&i==="preview")return await yo(t,o);if(n==="queries"&&i==="run")return await qo(t,o);if(n==="queries"&&i==="download")return await Io(t,o);return Be()}if(r==="spaces"){let n=t[1];if(!n||n==="--help"||o.help)return Ge();if(n==="init")return await vo(o);if(n==="create")return await To(o);if(n==="preview")return await Ro(o);if(n==="publish")return await Oo(t,o);if(n==="archive")return await Uo(t);return Ge()}return Jo()}var{flags:_o}=re(process.argv.slice(2));async function Fa(){try{let e=await Wo(process.argv.slice(2));if(e&&typeof e==="object"&&"__streamHandled"in e&&e.__streamHandled)return;if(typeof e==="string"){ke(e);return}ze(e,_o)}catch(e){Ke(e,_o),process.exit(1)}}Fa();
|