@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.
Files changed (2) hide show
  1. package/bin/cli.js +718 -377
  2. 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 gr(e,o){let r=h(e),t=pr(o);return ir(t.replacer?ur(r,t.replacer):r,t,0)}function pr(e){return{indent:e?.indent??2,delimiter:e?.delimiter??Y,keyFolding:e?.keyFolding??"off",flattenDepth:e?.flattenDepth??Number.POSITIVE_INFINITY,replacer:e?.replacer}}function wr(e){let o=e.format??"toon";if(o!=="toon"&&o!=="json")throw Error("--format debe ser toon o json.");return o}function Qe(e,o){if(wr(o)==="json"){console.log(JSON.stringify(e,null,2));return}console.log(me(e))}function d(e){process.stdout.write(`${e}
4
- `)}function Ne(e,o){let t={ok:!1,error:e instanceof Error?e.message:String(e)};if((o.format==="json"?"json":"toon")==="json"){console.error(JSON.stringify(t,null,2));return}console.error(me(t))}function y(e){process.stderr.write(e)}async function Pe(e){return(await c({service:"auth",query:`mutation ($email: String!) {
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(!o.website)throw Error(`No se encontro el website "${e}"`);return o.website}function Ir(){if(!g())throw Error("Debes iniciar sesión primero. Usa: team-cli auth login")}async function Xe(e){if(Ir(),!e)throw Error("Uso: team-cli admin <websiteId|domain> show");let o=await O(e),r=await Me(o.websiteId);return{context:o,website:r}}function V(){return`team-cli admin
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 Ye=`
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
- `,L=`
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
- ${Ye}
89
+ ${ut}
159
90
  }
160
91
  scheduleAtUse {
161
- ${Ye}
92
+ ${ut}
162
93
  }
163
94
  codesCode
164
- `,Ze=`
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 le(){if(!g())throw Error("Debes iniciar sesión primero. Usa: team-cli auth login")}function W(e,o){let r=e[o];if(!r)throw Error(`--${o} es requerido.`);try{return JSON.parse(r)}catch{throw Error(`--${o} debe ser un JSON válido.`)}}function I(e,o){let r=e[o];if(!r)return;let t=Number.parseInt(r,10);if(Number.isNaN(t))throw Error(`--${o} debe ser un número entero.`);return t}function ze(e,o){let r=e[o];if(!r)return;if(r==="true")return!0;if(r==="false")return!1;throw Error(`--${o} debe ser true o false.`)}async function q(e){if(le(),!e)throw Error("Debes indicar <websiteId|domain>.");return O(e)}async function j(e,o){let r=await c({service:"main",query:`query ($couponId: ID) {
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(!r.coupon)throw Error(`No se encontró el cupón "${e}"`);if(r.coupon.websiteId!==o)throw Error(`El cupón "${e}" no pertenece al website seleccionado.`);return r.coupon}async function He(e,o){le();let r=e[2]??o.filter;if(!r)throw Error("Debes indicar un término de búsqueda. Uso: team-cli admin search <texto>");let t=I(o,"limit"),i=I(o,"page"),n=ze(o,"only-active"),a=await c({service:"main",query:`query ($filter: String, $limit: BigInt, $page: BigInt, $onlyActiveWebsites: Boolean) {
179
- websites(filter: $filter, limit: $limit, page: $page, onlyActiveWebsites: $onlyActiveWebsites) {
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
- _id
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:r,limit:t,page:i,onlyActiveWebsites:n}});return{searchTerm:r,websites:a.websites.items??[],pagination:{totalCount:a.websites.totalCount??0,totalPages:a.websites.totalPages??0,hasNextPage:Boolean(a.websites.hasNextPage),hasPreviousPage:Boolean(a.websites.hasPreviousPage),page:i??1,limit:t??null}}}function De(){return`team-cli admin search
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
- Buscar websites en admin.
127
+ Crea códigos explícitos para un cupón.
197
128
 
198
129
  Uso:
199
- team-cli admin search <texto> [--limit <n>] [--page <n>] [--only-active true|false]
130
+ team-cli admin <websiteId|domain> coupons codes create <couponId> --input '<json>'
200
131
 
201
- Opciones:
202
- --limit <n>
203
- Límite de resultados.
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
- --page <n>
206
- Página a consultar.
137
+ Formato esperado:
138
+ [
139
+ {"code":"BIENVENIDA1"},
140
+ {"code":"BIENVENIDA2","userEmail":"persona@ejemplo.com"}
141
+ ]
207
142
 
208
- --only-active true|false
209
- Filtrar solo websites activos.
143
+ Ejemplo:
144
+ team-cli admin <web> coupons codes create <couponId> --input '[{"code":"PROMO001"},{"code":"PROMO002","userEmail":"ana@ejemplo.com"}]'
210
145
 
211
- Ejemplos:
212
- team-cli admin search milas
213
- team-cli admin search buffalo --limit 5
214
- team-cli admin search pizza --only-active true`}function hr(){if(!g())throw Error("Debes iniciar sesión primero. Usa: team-cli auth login")}function $r(e){let o=[e.address?.streetAddress,e.address?.extendedAddress,e.address?.locality].filter(Boolean);if(!o.length)return null;return o.join(", ")}async function ke(e){if(hr(),!e)throw Error("Uso: team-cli admin <websiteId|domain> stores list");let o=await O(e),t=((await c({service:"main",query:`query ($websiteId: ID) {
215
- stores(websiteId: $websiteId) {
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 Ve(e,o){let r=await q(e),t=I(o,"limit"),i=I(o,"page"),n=o.filter,a=await c({service:"main",query:`query ($websiteId: ID, $filter: String, $limit: BigInt, $page: BigInt) {
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:r.websiteId,filter:n,limit:t,page:i}});return{context:r,coupons:a.coupons.items??[],pagination:{totalCount:a.coupons.totalCount??0,totalPages:a.coupons.totalPages??0,hasNextPage:Boolean(a.coupons.hasNextPage),hasPreviousPage:Boolean(a.coupons.hasPreviousPage),page:i??1,limit:t??null}}}async function Le(e,o){let r=await q(e);await j(o,r.websiteId);let t=await c({service:"main",query:`query ($couponId: ID) {
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
- ${L}
174
+ ${le}
253
175
  }
254
- }`,variables:{couponId:o}});return{context:r,coupon:t.coupon}}async function eo(e,o){let r=await q(e),t=W(o,"input");if(t.websiteId&&t.websiteId!==r.websiteId)throw Error("El websiteId del input no coincide con el website seleccionado.");let i={...t,websiteId:r.websiteId},n=jr(i),a=await c({service:"main",query:n,variables:i});return{context:r,coupon:a.createCoupon}}async function oo(e,o,r){let t=await q(e);await j(o,t.websiteId);let i=W(r,"input"),n=await c({service:"main",query:`mutation ($couponId: ID, $coupon: UpdateCouponInput) {
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
- ${L}
178
+ ${le}
257
179
  }
258
- }`,variables:{couponId:o,coupon:i}});return{context:t,coupon:n.updateCoupon}}async function ro(e,o){let r=await q(e);await j(o,r.websiteId);let t=await c({service:"main",query:`mutation ($couponsIds: [ID]) {
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:[o]}});return{context:r,couponId:o,deleted:t.deleteCoupons}}function Z(){return`team-cli admin coupons
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 to(){return`team-cli admin coupons create
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 io(){return`team-cli admin coupons update
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 Er(e){if(!Array.isArray(e))throw Error("--input debe ser un arreglo JSON.");return e.map((o)=>{if(!o||typeof o!=="object"||typeof o.code!=="string")throw Error('Cada item de --input debe tener al menos { "code": "..." }.');if(o.userEmail!=null&&typeof o.userEmail!=="string")throw Error("userEmail debe ser string cuando viene informado.");return{code:o.code,userEmail:o.userEmail}})}function Ar(e){if(!Array.isArray(e)||e.some((o)=>typeof o!=="string"))throw Error("--ids debe ser un arreglo JSON de strings.");return e}async function no(e,o,r){let t=await q(e);await j(o,t.websiteId);let i=I(r,"limit"),n=I(r,"page"),a=r.filter,s=await c({service:"main",query:`query ($couponId: ID, $filter: String, $limit: BigInt, $page: BigInt) {
400
- couponCodes(couponId: $couponId, filter: $filter, limit: $limit, page: $page) {
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
- ${Ze}
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:{couponId:o,filter:a,limit:i,page:n}});return{context:t,couponId:o,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:i??null}}}async function ao(e,o,r){let t=await q(e);await j(o,t.websiteId);let i=Er(W(r,"input")),n=i.some((s)=>s.userEmail),a=await c({service:"main",query:`mutation ($couponId: ID, $codesWithEmail: [CodeWithEmailInput], $useCodeWithEmail: Boolean) {
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
- Crea códigos explícitos para un cupón.
339
+ Buscar websites en admin.
418
340
 
419
341
  Uso:
420
- team-cli admin <websiteId|domain> coupons codes create <couponId> --input '<json>'
342
+ team-cli admin search <texto> [--limit <n>] [--page <n>] [--only-active true|false]
421
343
 
422
- Como funciona:
423
- --input recibe un arreglo JSON.
424
- Cada item debe tener al menos el campo code.
425
- Opcionalmente puede incluir userEmail.
344
+ Opciones:
345
+ --limit <n>
346
+ Límite de resultados.
426
347
 
427
- Formato esperado:
428
- [
429
- {"code":"BIENVENIDA1"},
430
- {"code":"BIENVENIDA2","userEmail":"persona@ejemplo.com"}
431
- ]
348
+ --page <n>
349
+ Página a consultar.
432
350
 
433
- Ejemplo:
434
- team-cli admin <web> coupons codes create <couponId> --input '[{"code":"PROMO001"},{"code":"PROMO002","userEmail":"ana@ejemplo.com"}]'
351
+ --only-active true|false
352
+ Filtrar solo websites activos.
435
353
 
436
- Notas:
437
- Si algún item trae userEmail, team-cli activa useCodeWithEmail automáticamente.
438
- couponId se valida contra el website seleccionado antes de ejecutar la mutation.`}import{writeFileSync as Wr}from"node:fs";import{mkdtempSync as xr,readFileSync as Rr,rmSync as vr,writeFileSync as Ur}from"node:fs";import{tmpdir as Qr}from"node:os";import{join as uo}from"node:path";import{spawnSync as Nr}from"node:child_process";function Pr(e){return`'${e.replaceAll("'",`'"'"'`)}'`}function lo(e,o){if(e==null)return;if(!Array.isArray(e)||e.some((r)=>typeof r!=="string"))throw Error(`${o} debe ser un arreglo de strings.`);return e}function Sr(e){if(!Array.isArray(e))throw Error("variables debe ser un arreglo.");return e.map((o,r)=>{if(!o||typeof o!=="object"||Array.isArray(o))throw Error(`variables[${r}] debe ser un objeto.`);let t=o;if(typeof t.key!=="string"||!t.key)throw Error(`variables[${r}].key debe ser un string no vacío.`);if(typeof t.fieldType!=="string"||!t.fieldType)throw Error(`variables[${r}].fieldType debe ser un string no vacío.`);if(t.fieldParams!=null&&typeof t.fieldParams!=="string")throw Error(`variables[${r}].fieldParams debe ser un string.`);return{key:t.key,fieldType:t.fieldType,fieldParams:typeof t.fieldParams==="string"?t.fieldParams:void 0}})}function Or(e){if(!e||typeof e!=="object"||Array.isArray(e))throw Error("El archivo editado debe contener un objeto JSON.");let o=e;if(typeof o.name!=="string"||!o.name.trim())throw Error("name debe ser un string no vacío.");if(o.description!=null&&typeof o.description!=="string")throw Error("description debe ser un string.");if(typeof o.collection!=="string"||!o.collection.trim())throw Error("collection debe ser un string no vacío.");if(typeof o.pipeline!=="string")throw Error("pipeline debe ser un string.");return{name:o.name.trim(),description:o.description?.trim()||void 0,collection:o.collection.trim(),allowedUsersIds:lo(o.allowedUsersIds,"allowedUsersIds")??[],tags:lo(o.tags,"tags")??[],pipeline:o.pipeline,variables:Sr(o.variables)}}function go(e){let o=process.env.VISUAL||process.env.EDITOR||"vi",r=xr(uo(Qr(),"team-cli-query-")),t=uo(r,"aggregation-query.json");Ur(t,`${JSON.stringify(e,null,2)}
439
- `);let i=`${o} ${Pr(t)}`,n=Nr(i,{shell:!0,stdio:"inherit"});if(n.error)throw Error(`No se pudo abrir el editor "${o}": ${n.error.message}`);if(n.status!==0)throw Error(`El editor terminó con código ${n.status}.`);try{let a=Rr(t,"utf-8");if(!a.trim())throw Error("El archivo quedó vacío.");let s;try{s=JSON.parse(a)}catch{throw Error("El archivo editado no contiene JSON válido.")}return Or(s)}finally{vr(r,{recursive:!0,force:!0})}}function x(){if(!g())throw Error("Debes iniciar sesión primero. Usa: team-cli auth login")}function Q(e,o){let r=e[3];if(!r)throw Error(`Uso: ${o}`);return r}function ee(e){if(!e.params)return{};try{return JSON.parse(e.params)}catch{throw Error("--params debe ser un JSON válido.")}}function ge(e){if(typeof e!=="string")return e;try{return JSON.parse(e)}catch{return{value:e}}}async function z(e){return(await c({service:"data",query:`query ($aggregationQueryId: String) {
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 &lt;spaceId&gt; --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='&copy; <a href="https://www.maptiler.com/copyright/" target="_blank">MapTiler</a> <a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; 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 po(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 pe(e,o){let r=await c({service:"data",query:`mutation ($aggregationQueryId: String, $params: JSON) {
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:o}});return ge(r.testAggregationQuery)}async function we(e,o){await c({service:"data",query:`mutation ($aggregationQueryId: String, $aggregationQuery: UpdateAggregationQueryInput) {
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:o.name,description:o.description,collection:o.collection,allowedUsersIds:o.allowedUsersIds,tags:o.tags}}}),await c({service:"data",query:`mutation ($aggregationQueryId: String, $pipeline: String, $variables: [AggregationQueryVariableInput]) {
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:o.pipeline,variables:o.variables}})}async function wo(){return(await c({service:"data",query:`mutation {
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 Gr(e){if(!Array.isArray(e))throw Error("El preview del query debe devolver un arreglo para usar AI edit.");return e}async function Jr(e){let o=await c({service:"messenger",query:`mutation generateAdminQuery(
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(!o.generateAdminQuery?.pipeline||!o.generateAdminQuery.fullCollectionName)throw Error("La IA no devolvió una versión válida del query.");return o.generateAdminQuery}async function fo(){return x(),await wo()}async function bo(e){x();let o=Q(e,"team-cli data queries edit <queryId>"),r=await z(o),t=go(po(r));return await we(o,t),{ok:!0,queryId:o,name:t.name,collection:t.collection}}async function yo(e,o){x();let r=Q(e,"team-cli data queries ai-edit <queryId> --prompt '<texto>' [--params '<json>']"),t=await z(r),i=o.prompt||await _("Describe los cambios para la IA: ");if(!i)throw Error("Debes indicar un prompt para AI edit.");let n=ee(o),a;if(o.params){y(`Obteniendo preview del query actual...
522
- `);try{let u=await pe(r,n);a=Gr(u)}catch(u){let f=u instanceof Error?u.message:String(u);throw Error(`No se pudo obtener el preview para AI edit: ${f}`)}}y(`Generando propuesta con IA...
523
- `);let s=await Jr({prompt:i,fullCollectionName:t.collection,pipeline:t.pipeline,preview:a,description:t.description,name:t.name,variables:t.variables});return await we(r,{name:t.name==="Nuevo query"?s.aggregationName||t.name:t.name,description:t.description||s.aggregationDescription,collection:s.fullCollectionName,allowedUsersIds:t.allowedUsersIds??[],tags:t.tags??[],pipeline:s.pipeline,variables:s.variables??[]}),{ok:!0,queryId:r,responseText:s.responseText,collection:s.fullCollectionName,name:s.aggregationName,description:s.aggregationDescription}}async function qo(e){x();let o=Q(e,"team-cli data queries view <queryId>");return await z(o)}async function Co(e){x();let o=Q(e,"team-cli data queries view-pipeline <queryId>"),r=await z(o);return{queryId:o,pipeline:r.pipeline}}async function Io(e,o){x();let r=Q(e,"team-cli data queries preview <queryId> --params '<json>'"),t=ee(o),i=await pe(r,t);return ge(i)}function Br(e){return new Promise((o)=>setTimeout(o,e))}async function ho(e,o){x();let r=Q(e,"team-cli data queries download <queryId> --params '<json>'"),t=ee(o);if(!o.path)throw Error("--path es requerido. Ejemplo: --path resultado.xlsx");y(`Iniciando descarga...
524
- `);let n=(await c({service:"data",query:`mutation ($aggregationQueryId: String, $params: JSON) {
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:r,params:t}})).downloadAggregationQueryData;y(`Reporte en proceso (${n})...
527
- `);let a=null;while(!a){await Br(1000);let f=await c({service:"data",query:`query ($id: String) {
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}}),p=f.getAsyncReport,v=f.getAsyncReportRecordsCount;if(p.status==="error")throw Error("El reporte falló al generarse.");if(p.fileUrl)a=p.fileUrl;else{let E=p.estimatedRecordsCount?` (~${p.estimatedRecordsCount} registros)`:"",J=v!=null?` ${v} procesados`:"";y(`\rGenerando...${E}${J}`)}}y(`
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(a);if(!s.ok)throw Error(`Error descargando archivo: ${s.status}`);let u=Buffer.from(await s.arrayBuffer());return Wr(o.path,u),{ok:!0,queryId:r,asyncReportId:n,outputPath:o.path,fileUrl:a}}function fe(){return`team-cli data
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 download abc123 --params '{"startDate": "2026-01-01"}' --path resultado.xlsx`}var Tr=["local","develop","prod"];function $o(){return Object.keys(H)}function _r(){return $o().map((e)=>{return[`- \`${e}\``,...Tr.map((r)=>{let t=H[e][r];return` - ${r}: \`${t}/graphql\``})].join(`
590
- `)}).join(`
591
- `)}function Fr(){let o=$o().join(", "),r=_r();return`# @getjusto/team-cli
592
-
593
- CLI tool for Justo team members. Authenticated access to Justo's GraphQL services and data queries.
594
-
595
- Recommended approach for data requests:
596
- - if you need to obtain data and there is no existing query ready to use, prefer \`data queries create\` followed by \`data queries ai-edit\`
597
- - recommended flow: \`create -> ai-edit -> preview -> download\`
598
-
599
- ## Prerequisites
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
- If not logged in, the user must log in interactively (you cannot do this):
607
- \`\`\`bash
608
- npx @getjusto/team-cli auth login
609
- \`\`\`
988
+ Ejecutar queries y mutations GraphQL.
610
989
 
611
- ## Global Options
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
- - \`--env <local|develop|prod>\` — Environment (default: prod)
614
- - \`--format toon|json\` Output format (default: toon)
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
- ## Commands
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
- Available services: ${o}.
1004
+ Servicios disponibles: ${t}.
625
1005
 
626
- Examples:
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 — Inspect query/mutation params and result metadata
1013
+ ### graphql info
634
1014
 
635
- Use this before writing the final GraphQL call when you only know the operation name, or when someone shares a curl and you need to understand the params expected by the resolver.
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
- What it returns:
642
- - \`operationType\` — whether Orion exposed it as query or mutation
643
- - \`info.params\` — serialized params schema, including optional fields and GraphQL scalar types
644
- - \`info.result\` — top-level result model/type name when available
645
- - \`info.basicResultQuery\` — a starter field selection you can reuse in the final GraphQL document
1021
+ Devuelve:
1022
+ - \`operationType\`
1023
+ - \`info.params\`
1024
+ - \`info.result\`
1025
+ - \`info.basicResultQuery\`
646
1026
 
647
- Examples:
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
- Recommended workflow for converting a curl into team-cli:
654
- 1. Identify the service from the GraphQL URL.
655
- 2. If you know the operation name, inspect it first with \`graphql <service> info <name>\`.
656
- 3. Use \`info.params\` to build the variables object.
657
- 4. Use \`info.basicResultQuery\` as the starting selection set.
658
- 5. Run the final command with \`graphql <service> '<queryOrMutation>' --variables '<json>'\`.
659
-
660
- ### GraphQL Service Map
661
-
662
- Use this when someone shares a GraphQL \`curl\` and you need to map the URL to the correct \`team-cli graphql <service>\` value.
663
-
664
- Rule:
665
- - If the curl points to \`https://something/.../graphql\`, match that URL against the list below and use the corresponding service name.
666
- - In \`team-cli\`, you pass the service name only, not the full URL.
667
-
668
- Service name to endpoint map:
669
- ${r}
670
-
671
- Example conversion:
672
- \`\`\`bash
673
- # curl
674
- curl 'https://tabs.service.getjusto.com/graphql' \\
675
- -H 'content-type: application/json' \\
676
- --data-raw '{"query":"query { tab(tabId: \\"t123\\") { _id status } }"}'
677
-
678
- # inspect the resolver first
679
- npx @getjusto/team-cli graphql tabs info tab
680
-
681
- # team-cli
682
- npx @getjusto/team-cli graphql tabs 'query { tab(tabId: "t123") { _id status } }'
683
- \`\`\`
684
-
685
- ### admin search — Search websites/brands in admin
686
-
687
- Use this when you need to find a website first before calling other admin commands.
688
-
689
- \`\`\`bash
690
- npx @getjusto/team-cli admin search <text> [--limit <n>] [--page <n>] [--only-active true|false]
691
- \`\`\`
692
-
693
- What it returns:
694
- - \`_id\`
695
- - \`name\`
696
- - \`active\`
697
- - \`baseURL\`
698
- - \`domain\`
699
- - \`countryCode\`
700
- - \`timezone\`
701
-
702
- Typical use:
703
- 1. Search the brand/site by name fragment.
704
- 2. Take either the returned \`_id\` or a known domain/baseURL.
705
- 3. Use that value in \`team-cli admin <websiteId|domain> ...\`.
706
-
707
- Examples:
708
- \`\`\`bash
709
- # find the website
710
- npx @getjusto/team-cli admin search milas --limit 5
711
-
712
- # then use the returned website id
713
- npx @getjusto/team-cli admin YRZjQ7L6whxfkezmF show
714
- npx @getjusto/team-cli admin YRZjQ7L6whxfkezmF stores list
715
- npx @getjusto/team-cli admin YRZjQ7L6whxfkezmF coupons list
716
-
717
- # or use a domain directly
718
- npx @getjusto/team-cli admin www.masmilas.com show
719
- \`\`\`
720
-
721
- ### data queries view View query metadata and required variables
722
-
723
- \`\`\`bash
724
- npx @getjusto/team-cli data queries view <queryId>
725
- \`\`\`
726
-
727
- Returns: _id, name, description, collection, currentVersionIndex, and variables (key, fieldType, fieldParams). Use this to understand what params a query expects before running preview or download.
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
- Opens a temporary JSON document in \`$VISUAL\`, \`$EDITOR\`, or \`vi\`. The editable payload includes:
744
- - \`name\`
745
- - \`description\`
746
- - \`collection\`
747
- - \`allowedUsersIds\`
748
- - \`tags\`
749
- - \`pipeline\`
750
- - \`variables\`
751
-
752
- Validation rules:
753
- - the file must remain valid JSON
754
- - \`pipeline\` must be a string containing the JavaScript array used by the aggregation query
755
- - \`variables\` must be an array of objects with \`key\`, \`fieldType\`, and optional \`fieldParams\`
756
-
757
- Example:
758
- \`\`\`bash
759
- EDITOR=nvim npx @getjusto/team-cli data queries edit 69b201547b944d8cc8b7e663
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
- ### data queries ai-edit Edit a query with AI
1141
+ Herramienta CLI para el equipo Justo.
763
1142
 
764
- \`\`\`bash
765
- npx @getjusto/team-cli data queries ai-edit <queryId> --prompt '<text>' [--params '<json>'] [--format toon|json]
766
- \`\`\`
1143
+ ${e}
767
1144
 
768
- Uses Messenger's \`generateAdminQuery\` flow to rewrite the collection, pipeline, variables, and, when appropriate, suggested name/description.
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
- Notes:
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
- Example:
1150
+ Pide el email al usuario que te esta hablando y usa el flujo no interactivo:
777
1151
  \`\`\`bash
778
- npx @getjusto/team-cli data queries ai-edit 69b201547b944d8cc8b7e663 \\
779
- --prompt 'Show the latest created users with _id, email and createdAt' \\
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
- ### data queries view-pipeline — View query pipeline code
1156
+ ## Opciones globales
784
1157
 
785
- \`\`\`bash
786
- npx @getjusto/team-cli data queries view-pipeline <queryId>
787
- \`\`\`
1158
+ - \`--env <local|develop|prod>\` — Environment (default: prod)
1159
+ - \`--format toon|json\` Output format (default: toon)
1160
+ - \`--version\`
1161
+ - \`--help\`
788
1162
 
789
- Returns the raw JavaScript pipeline code.
1163
+ ## Comandos
790
1164
 
791
- ### data queries preview Test-run a query (max 100 rows)
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
- \`\`\`bash
794
- npx @getjusto/team-cli data queries preview <queryId> [--params '<json>'] [--format toon|json]
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
- Executes the query with a 100-row limit. Use this to verify results before downloading.
1173
+ ## Tips
798
1174
 
799
- ### data queries download Download full query results as Excel
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 data queries download <queryId> --path <filepath> [--params '<json>']
1179
+ npx @getjusto/team-cli admin search <text> [--limit <n>] [--page <n>] [--only-active true|false]
803
1180
  \`\`\`
804
1181
 
805
- \`--path\` is required. Triggers an async report, polls until complete, then downloads the Excel file.
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
- get-skill
841
- Obtener skill para usar con Claude.
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
- Opciones globales:
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();