@wallavi/vercel-build 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1287 -0
- package/dist/index.js +1011 -0
- package/package.json +33 -3
- package/README.md +0 -3
package/dist/index.js
ADDED
|
@@ -0,0 +1,1011 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var crypto = require('crypto');
|
|
5
|
+
var fs = require('fs');
|
|
6
|
+
var path3 = require('path');
|
|
7
|
+
var zod = require('zod');
|
|
8
|
+
var child_process = require('child_process');
|
|
9
|
+
|
|
10
|
+
function _interopNamespace(e) {
|
|
11
|
+
if (e && e.__esModule) return e;
|
|
12
|
+
var n = Object.create(null);
|
|
13
|
+
if (e) {
|
|
14
|
+
Object.keys(e).forEach(function (k) {
|
|
15
|
+
if (k !== 'default') {
|
|
16
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
17
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
get: function () { return e[k]; }
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
n.default = e;
|
|
25
|
+
return Object.freeze(n);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
var path3__namespace = /*#__PURE__*/_interopNamespace(path3);
|
|
29
|
+
|
|
30
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
31
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
32
|
+
}) : x)(function(x) {
|
|
33
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
34
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
35
|
+
});
|
|
36
|
+
var API_VERCEL_URL = "https://api.vercel.com";
|
|
37
|
+
var LIMITE_PAGINA_VERCEL = 100;
|
|
38
|
+
var MAX_PAGINAS_VERCEL = 1e3;
|
|
39
|
+
var ESTADOS_DEPLOYMENT = [
|
|
40
|
+
"BUILDING",
|
|
41
|
+
"ERROR",
|
|
42
|
+
"INITIALIZING",
|
|
43
|
+
"QUEUED",
|
|
44
|
+
"READY",
|
|
45
|
+
"CANCELED"
|
|
46
|
+
];
|
|
47
|
+
var ErrorContratoVercel = class extends Error {
|
|
48
|
+
constructor(mensaje) {
|
|
49
|
+
super(mensaje);
|
|
50
|
+
this.name = "ErrorContratoVercel";
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
var ErrorRedVercel = class extends Error {
|
|
54
|
+
estado;
|
|
55
|
+
constructor(mensaje, estado) {
|
|
56
|
+
super(mensaje);
|
|
57
|
+
this.name = "ErrorRedVercel";
|
|
58
|
+
if (estado !== void 0) this.estado = estado;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
var esquemaPaginacion = zod.z.object({
|
|
62
|
+
count: zod.z.number().int().nonnegative(),
|
|
63
|
+
next: zod.z.number().finite().nullable(),
|
|
64
|
+
prev: zod.z.number().finite().nullable()
|
|
65
|
+
}).passthrough();
|
|
66
|
+
var esquemaEquipo = zod.z.object({
|
|
67
|
+
id: zod.z.string().regex(/^team_.+/),
|
|
68
|
+
slug: zod.z.string().min(1)
|
|
69
|
+
}).passthrough();
|
|
70
|
+
var esquemaPaginaTeams = zod.z.object({
|
|
71
|
+
teams: zod.z.array(esquemaEquipo),
|
|
72
|
+
pagination: esquemaPaginacion
|
|
73
|
+
}).passthrough();
|
|
74
|
+
var esquemaEstadoDeployment = zod.z.enum(ESTADOS_DEPLOYMENT);
|
|
75
|
+
var esquemaDeployment = zod.z.object({
|
|
76
|
+
uid: zod.z.string().min(1),
|
|
77
|
+
name: zod.z.string().min(1),
|
|
78
|
+
createdAt: zod.z.number().finite(),
|
|
79
|
+
state: esquemaEstadoDeployment.optional(),
|
|
80
|
+
readyState: esquemaEstadoDeployment.optional(),
|
|
81
|
+
buildingAt: zod.z.number().finite().optional(),
|
|
82
|
+
ready: zod.z.number().finite().optional()
|
|
83
|
+
}).passthrough().refine((d) => d.state !== void 0 || d.readyState !== void 0, {
|
|
84
|
+
message: "cada deployment debe incluir state o readyState"
|
|
85
|
+
});
|
|
86
|
+
var esquemaPaginaDeployments = zod.z.object({
|
|
87
|
+
deployments: zod.z.array(esquemaDeployment),
|
|
88
|
+
pagination: esquemaPaginacion
|
|
89
|
+
}).passthrough();
|
|
90
|
+
var esquemaArchivoDeployments = zod.z.object({
|
|
91
|
+
paginas: zod.z.array(esquemaPaginaDeployments).min(1)
|
|
92
|
+
}).passthrough();
|
|
93
|
+
var SCRIPT_FETCH = [
|
|
94
|
+
"const [u] = process.argv.slice(1), h = require('node:fs').readFileSync(0, 'utf8');",
|
|
95
|
+
"fetch(u, { method: 'GET', headers: JSON.parse(h) })",
|
|
96
|
+
" .then(async (r) => process.stdout.write(JSON.stringify({ estado: r.status, cuerpo: await r.text() })))",
|
|
97
|
+
" .catch((e) => { process.stderr.write(String(e?.message || e)); process.exit(1); });"
|
|
98
|
+
].join("\n");
|
|
99
|
+
var solicitarVercel = (url, headers) => {
|
|
100
|
+
const r = child_process.spawnSync(process.execPath, ["-e", SCRIPT_FETCH, url], {
|
|
101
|
+
input: JSON.stringify(headers),
|
|
102
|
+
shell: false,
|
|
103
|
+
encoding: "utf8",
|
|
104
|
+
maxBuffer: 64 * 1024 * 1024
|
|
105
|
+
});
|
|
106
|
+
if (r.error || r.status !== 0) {
|
|
107
|
+
throw new ErrorRedVercel(
|
|
108
|
+
r.error?.message ?? (r.stderr.trim() || `fallo de red en ${url}`)
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
return JSON.parse(r.stdout);
|
|
112
|
+
};
|
|
113
|
+
function pedirJsonVercel(rutaQuery, token, solicitar = solicitarVercel, baseUrl = API_VERCEL_URL) {
|
|
114
|
+
let respuesta;
|
|
115
|
+
try {
|
|
116
|
+
respuesta = solicitar(`${baseUrl}${rutaQuery}`, {
|
|
117
|
+
Authorization: `Bearer ${token}`
|
|
118
|
+
});
|
|
119
|
+
} catch (e) {
|
|
120
|
+
if (e instanceof ErrorRedVercel || e instanceof ErrorContratoVercel)
|
|
121
|
+
throw e;
|
|
122
|
+
throw new ErrorRedVercel(e.message);
|
|
123
|
+
}
|
|
124
|
+
if (respuesta.estado < 200 || respuesta.estado >= 300) {
|
|
125
|
+
throw new ErrorRedVercel(
|
|
126
|
+
`HTTP ${respuesta.estado} en GET ${rutaQuery}`,
|
|
127
|
+
respuesta.estado
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
return { estado: respuesta.estado, valor: JSON.parse(respuesta.cuerpo) };
|
|
132
|
+
} catch (e) {
|
|
133
|
+
throw new ErrorContratoVercel(
|
|
134
|
+
`JSON inv\xE1lido en GET ${rutaQuery}: ${e.message}`
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function resolverEquipo(equipo, token, solicitar = solicitarVercel, baseUrl = API_VERCEL_URL) {
|
|
139
|
+
if (/^team_.+/.test(equipo)) return equipo;
|
|
140
|
+
let until;
|
|
141
|
+
for (let pagina = 1; ; pagina++) {
|
|
142
|
+
const query = until === void 0 ? `limit=${LIMITE_PAGINA_VERCEL}` : `limit=${LIMITE_PAGINA_VERCEL}&until=${until}`;
|
|
143
|
+
const { valor } = pedirJsonVercel(
|
|
144
|
+
`/v2/teams?${query}`,
|
|
145
|
+
token,
|
|
146
|
+
solicitar,
|
|
147
|
+
baseUrl
|
|
148
|
+
);
|
|
149
|
+
const r = esquemaPaginaTeams.safeParse(valor);
|
|
150
|
+
if (!r.success) {
|
|
151
|
+
throw new ErrorContratoVercel(
|
|
152
|
+
`GET /v2/teams inv\xE1lido: ${r.error.message}`
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
const encontrado = r.data.teams.find((t) => t.slug === equipo);
|
|
156
|
+
if (encontrado) return encontrado.id;
|
|
157
|
+
const next = r.data.pagination.next;
|
|
158
|
+
if (next === null) {
|
|
159
|
+
throw new ErrorContratoVercel(`no se encontr\xF3 el equipo: ${equipo}`);
|
|
160
|
+
}
|
|
161
|
+
if (until !== void 0 && next >= until) {
|
|
162
|
+
throw new ErrorContratoVercel(`pagination.next (${next}) no decrece`);
|
|
163
|
+
}
|
|
164
|
+
if (pagina >= MAX_PAGINAS_VERCEL) {
|
|
165
|
+
throw new ErrorContratoVercel(`super\xF3 ${MAX_PAGINAS_VERCEL} p\xE1ginas`);
|
|
166
|
+
}
|
|
167
|
+
until = next;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function leerRespuestaDeployments(ruta, untilInicial) {
|
|
171
|
+
if (!fs.existsSync(ruta)) {
|
|
172
|
+
throw new ErrorContratoVercel(`no existe el archivo: ${ruta}`);
|
|
173
|
+
}
|
|
174
|
+
let crudo;
|
|
175
|
+
try {
|
|
176
|
+
crudo = JSON.parse(fs.readFileSync(ruta, "utf8"));
|
|
177
|
+
} catch (e) {
|
|
178
|
+
throw new ErrorContratoVercel(
|
|
179
|
+
`${ruta}: JSON inv\xE1lido: ${e.message}`
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
const rArchivo = esquemaArchivoDeployments.safeParse(crudo);
|
|
183
|
+
const rPagina = rArchivo.success ? null : esquemaPaginaDeployments.safeParse(crudo);
|
|
184
|
+
const paginas = rArchivo.success ? rArchivo.data.paginas : rPagina?.success ? [rPagina.data] : null;
|
|
185
|
+
if (!paginas || paginas.length > MAX_PAGINAS_VERCEL) {
|
|
186
|
+
throw new ErrorContratoVercel(
|
|
187
|
+
`${ruta}: estructura de deployments inv\xE1lida`
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
let cursorPrevio = untilInicial;
|
|
191
|
+
paginas.forEach((p, i) => {
|
|
192
|
+
const next = p.pagination.next;
|
|
193
|
+
const esUltima = i === paginas.length - 1;
|
|
194
|
+
if (!esUltima && next === null || esUltima && next !== null) {
|
|
195
|
+
throw new ErrorContratoVercel(
|
|
196
|
+
`paginaci\xF3n inconsistente en p\xE1gina ${i + 1}`
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
if (next !== null && cursorPrevio !== void 0 && next >= cursorPrevio) {
|
|
200
|
+
throw new ErrorContratoVercel(`pagination.next (${next}) no decrece`);
|
|
201
|
+
}
|
|
202
|
+
if (next !== null) cursorPrevio = next;
|
|
203
|
+
});
|
|
204
|
+
return paginas;
|
|
205
|
+
}
|
|
206
|
+
function calcularMinutosPorDia(paginas, desde, hasta) {
|
|
207
|
+
const dias = /* @__PURE__ */ new Map();
|
|
208
|
+
for (let t = Date.parse(`${desde}T00:00:00.000Z`); t <= Date.parse(`${hasta}T00:00:00.000Z`); t += 864e5) {
|
|
209
|
+
dias.set(new Date(t).toISOString().slice(0, 10), /* @__PURE__ */ new Map());
|
|
210
|
+
}
|
|
211
|
+
for (const pagina of paginas) {
|
|
212
|
+
for (const d of pagina.deployments) {
|
|
213
|
+
if (d.state !== "READY" && d.readyState !== "READY" || d.buildingAt === void 0 || d.ready === void 0)
|
|
214
|
+
continue;
|
|
215
|
+
const porProyecto = dias.get(
|
|
216
|
+
new Date(d.buildingAt).toISOString().slice(0, 10)
|
|
217
|
+
);
|
|
218
|
+
porProyecto?.set(
|
|
219
|
+
d.name,
|
|
220
|
+
(porProyecto.get(d.name) ?? 0) + (d.ready - d.buildingAt)
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
const r2 = (ms) => Math.round(ms / 6e4 * 100) / 100;
|
|
225
|
+
return {
|
|
226
|
+
dias: [...dias.entries()].map(([fecha, porProyecto]) => ({
|
|
227
|
+
fecha,
|
|
228
|
+
minutos: r2([...porProyecto.values()].reduce((a, b) => a + b, 0)),
|
|
229
|
+
porProyecto: Object.fromEntries(
|
|
230
|
+
[...porProyecto.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([nombre, ms]) => [nombre, r2(ms)])
|
|
231
|
+
)
|
|
232
|
+
}))
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
function leerArgumentosMedir(args) {
|
|
236
|
+
const f = leerFlagsCli(args, [
|
|
237
|
+
"--equipo",
|
|
238
|
+
"--desde",
|
|
239
|
+
"--hasta",
|
|
240
|
+
"--respuesta"
|
|
241
|
+
]);
|
|
242
|
+
if (!f.ok) return f;
|
|
243
|
+
const { equipo, desde, hasta, respuesta } = f.valores;
|
|
244
|
+
if (!equipo) return { ok: false, motivo: "falta --equipo <slug|team_id>" };
|
|
245
|
+
if (!desde) return { ok: false, motivo: "falta --desde <AAAA-MM-DD>" };
|
|
246
|
+
if (!hasta) return { ok: false, motivo: "falta --hasta <AAAA-MM-DD>" };
|
|
247
|
+
const rango = rangoFechasUtc(desde, hasta);
|
|
248
|
+
if (!rango.ok) return rango;
|
|
249
|
+
return {
|
|
250
|
+
ok: true,
|
|
251
|
+
valor: { equipo, desde, hasta, ...respuesta ? { respuesta } : {} }
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
function ejecutarMedir(opciones) {
|
|
255
|
+
const rango = rangoFechasUtc(opciones.desde, opciones.hasta);
|
|
256
|
+
if (!rango.ok) {
|
|
257
|
+
opciones.error(`wallavi-vercel medir: ${rango.motivo}`);
|
|
258
|
+
return 2;
|
|
259
|
+
}
|
|
260
|
+
const token = opciones.env.VERCEL_TOKEN?.trim() ?? "";
|
|
261
|
+
try {
|
|
262
|
+
let paginas;
|
|
263
|
+
if (opciones.respuesta !== void 0) {
|
|
264
|
+
paginas = leerRespuestaDeployments(
|
|
265
|
+
path3__namespace.resolve(opciones.cwd, opciones.respuesta),
|
|
266
|
+
rango.until
|
|
267
|
+
);
|
|
268
|
+
} else {
|
|
269
|
+
if (!token) {
|
|
270
|
+
opciones.error("wallavi-vercel medir: falta VERCEL_TOKEN");
|
|
271
|
+
return 2;
|
|
272
|
+
}
|
|
273
|
+
const baseUrl = opciones.baseUrl ?? opciones.env.VERCEL_API_URL?.trim() ?? API_VERCEL_URL;
|
|
274
|
+
const teamId = resolverEquipo(
|
|
275
|
+
opciones.equipo,
|
|
276
|
+
token,
|
|
277
|
+
opciones.solicitar,
|
|
278
|
+
baseUrl
|
|
279
|
+
);
|
|
280
|
+
paginas = consultarDeployments({
|
|
281
|
+
teamId,
|
|
282
|
+
since: rango.since,
|
|
283
|
+
until: rango.until,
|
|
284
|
+
token,
|
|
285
|
+
solicitar: opciones.solicitar,
|
|
286
|
+
baseUrl
|
|
287
|
+
}).paginas;
|
|
288
|
+
}
|
|
289
|
+
opciones.salida(
|
|
290
|
+
JSON.stringify(
|
|
291
|
+
calcularMinutosPorDia(paginas, opciones.desde, opciones.hasta),
|
|
292
|
+
null,
|
|
293
|
+
2
|
|
294
|
+
)
|
|
295
|
+
);
|
|
296
|
+
return 0;
|
|
297
|
+
} catch (e) {
|
|
298
|
+
opciones.error(
|
|
299
|
+
`wallavi-vercel medir: ${redactarToken(e.message, token)}`
|
|
300
|
+
);
|
|
301
|
+
return e instanceof ErrorContratoVercel ? 2 : 1;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
function comandoMedir(args, entorno) {
|
|
305
|
+
const leido = leerArgumentosMedir(args);
|
|
306
|
+
if (!leido.ok) {
|
|
307
|
+
entorno.error(`wallavi-vercel medir: ${leido.motivo}`);
|
|
308
|
+
return 2;
|
|
309
|
+
}
|
|
310
|
+
return ejecutarMedir({ ...entorno, ...leido.valor });
|
|
311
|
+
}
|
|
312
|
+
var medir = comandoMedir;
|
|
313
|
+
|
|
314
|
+
// src/comandos/capturar.ts
|
|
315
|
+
var ARCHIVO_DEPLOYMENTS_V6 = "deployments-v6.json";
|
|
316
|
+
var ARCHIVO_CAPTURA_V6 = "captura-v6.json";
|
|
317
|
+
var REFERENCIA_DEPLOYMENTS_V6 = "https://vercel.com/docs/rest-api/reference/endpoints/deployments/list-deployments";
|
|
318
|
+
function redactarToken(texto, token) {
|
|
319
|
+
const limpio = token?.trim();
|
|
320
|
+
return limpio ? texto.split(limpio).join("[REDACTED]") : texto;
|
|
321
|
+
}
|
|
322
|
+
function validarFechaIso(fecha) {
|
|
323
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(fecha)) return null;
|
|
324
|
+
const ms = Date.parse(`${fecha}T00:00:00.000Z`);
|
|
325
|
+
return !Number.isNaN(ms) && new Date(ms).toISOString().slice(0, 10) === fecha ? ms : null;
|
|
326
|
+
}
|
|
327
|
+
function rangoFechasUtc(desde, hasta) {
|
|
328
|
+
const desdeMs = validarFechaIso(desde);
|
|
329
|
+
if (desdeMs === null)
|
|
330
|
+
return { ok: false, motivo: `--desde inv\xE1lida: ${desde}` };
|
|
331
|
+
const hastaMs = validarFechaIso(hasta);
|
|
332
|
+
if (hastaMs === null)
|
|
333
|
+
return { ok: false, motivo: `--hasta inv\xE1lida: ${hasta}` };
|
|
334
|
+
if (desdeMs > hastaMs) {
|
|
335
|
+
return {
|
|
336
|
+
ok: false,
|
|
337
|
+
motivo: `--desde (${desde}) posterior a --hasta (${hasta})`
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
return {
|
|
341
|
+
ok: true,
|
|
342
|
+
since: desdeMs,
|
|
343
|
+
until: Date.parse(`${hasta}T23:59:59.999Z`)
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
function leerFlagsCli(args, permitidas) {
|
|
347
|
+
const valores = {};
|
|
348
|
+
for (let i = 0; i < args.length; i++) {
|
|
349
|
+
const arg = args[i] ?? "";
|
|
350
|
+
const flag = permitidas.find((p) => arg === p || arg.startsWith(`${p}=`));
|
|
351
|
+
if (!flag) return { ok: false, motivo: `argumento no reconocido: ${arg}` };
|
|
352
|
+
const v = arg === flag ? args[++i] : arg.slice(flag.length + 1);
|
|
353
|
+
if (!v || v.trim() === "" || v.startsWith("-")) {
|
|
354
|
+
return { ok: false, motivo: `falta el valor de ${flag}` };
|
|
355
|
+
}
|
|
356
|
+
valores[flag.slice(2)] = v.trim();
|
|
357
|
+
}
|
|
358
|
+
return { ok: true, valores };
|
|
359
|
+
}
|
|
360
|
+
function consultarDeployments(opciones) {
|
|
361
|
+
const solicitar = opciones.solicitar ?? solicitarVercel;
|
|
362
|
+
const baseUrl = opciones.baseUrl ?? API_VERCEL_URL;
|
|
363
|
+
const paginas = [];
|
|
364
|
+
const pedidos = [];
|
|
365
|
+
let untilActual = opciones.until;
|
|
366
|
+
for (let pagina = 1; ; pagina++) {
|
|
367
|
+
const since = String(opciones.since);
|
|
368
|
+
const until = String(untilActual);
|
|
369
|
+
const limit = String(LIMITE_PAGINA_VERCEL);
|
|
370
|
+
const query = `teamId=${encodeURIComponent(opciones.teamId)}&since=${since}&until=${until}&limit=${limit}`;
|
|
371
|
+
const { estado, valor } = pedirJsonVercel(
|
|
372
|
+
`/v6/deployments?${query}`,
|
|
373
|
+
opciones.token,
|
|
374
|
+
solicitar,
|
|
375
|
+
baseUrl
|
|
376
|
+
);
|
|
377
|
+
const r = esquemaPaginaDeployments.safeParse(valor);
|
|
378
|
+
if (!r.success) {
|
|
379
|
+
throw new ErrorContratoVercel(
|
|
380
|
+
`GET /v6/deployments inv\xE1lido: ${r.error.message}`
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
paginas.push(r.data);
|
|
384
|
+
pedidos.push({ query: { since, until, limit }, estado });
|
|
385
|
+
const next = r.data.pagination.next;
|
|
386
|
+
if (next === null) return { paginas, pedidos };
|
|
387
|
+
if (next >= untilActual) {
|
|
388
|
+
throw new ErrorContratoVercel(`pagination.next (${next}) no decrece`);
|
|
389
|
+
}
|
|
390
|
+
if (pagina >= MAX_PAGINAS_VERCEL) {
|
|
391
|
+
throw new ErrorContratoVercel(`super\xF3 ${MAX_PAGINAS_VERCEL} p\xE1ginas`);
|
|
392
|
+
}
|
|
393
|
+
untilActual = next;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
var esquemaPedidoCaptura = zod.z.object({
|
|
397
|
+
query: zod.z.object({
|
|
398
|
+
since: zod.z.string().min(1),
|
|
399
|
+
until: zod.z.string().min(1),
|
|
400
|
+
limit: zod.z.string().min(1)
|
|
401
|
+
}).strict(),
|
|
402
|
+
estado: zod.z.number().int()
|
|
403
|
+
}).passthrough();
|
|
404
|
+
var esquemaCapturaV6 = zod.z.object({
|
|
405
|
+
origen: zod.z.enum(["documentacion", "captura"]),
|
|
406
|
+
referencia: zod.z.string().min(1),
|
|
407
|
+
fecha: zod.z.string().min(1),
|
|
408
|
+
metodo: zod.z.literal("GET"),
|
|
409
|
+
ruta: zod.z.literal("/v6/deployments"),
|
|
410
|
+
desde: zod.z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
|
|
411
|
+
hasta: zod.z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
|
|
412
|
+
pedidos: zod.z.array(esquemaPedidoCaptura),
|
|
413
|
+
archivo: zod.z.string().min(1),
|
|
414
|
+
sha256: zod.z.string().regex(/^[0-9a-f]{64}$/),
|
|
415
|
+
transformaciones: zod.z.array(zod.z.string())
|
|
416
|
+
}).passthrough();
|
|
417
|
+
function leerArgumentosCapturar(args) {
|
|
418
|
+
const f = leerFlagsCli(args, ["--equipo", "--desde", "--hasta", "--salida"]);
|
|
419
|
+
if (!f.ok) return f;
|
|
420
|
+
const { equipo, desde, hasta, salida } = f.valores;
|
|
421
|
+
if (!equipo) return { ok: false, motivo: "falta --equipo <slug|team_id>" };
|
|
422
|
+
if (!desde) return { ok: false, motivo: "falta --desde <AAAA-MM-DD>" };
|
|
423
|
+
if (!hasta) return { ok: false, motivo: "falta --hasta <AAAA-MM-DD>" };
|
|
424
|
+
if (!salida) return { ok: false, motivo: "falta --salida <carpeta>" };
|
|
425
|
+
const rango = rangoFechasUtc(desde, hasta);
|
|
426
|
+
if (!rango.ok) return rango;
|
|
427
|
+
return { ok: true, valor: { equipo, desde, hasta, salida } };
|
|
428
|
+
}
|
|
429
|
+
function armarCapturaV6(opciones) {
|
|
430
|
+
const sha256 = crypto.createHash("sha256").update(opciones.contenidoDeployments, "utf8").digest("hex");
|
|
431
|
+
return {
|
|
432
|
+
origen: opciones.origen ?? "captura",
|
|
433
|
+
referencia: opciones.referencia ?? REFERENCIA_DEPLOYMENTS_V6,
|
|
434
|
+
fecha: opciones.fecha ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
435
|
+
metodo: "GET",
|
|
436
|
+
ruta: "/v6/deployments",
|
|
437
|
+
desde: opciones.desde,
|
|
438
|
+
hasta: opciones.hasta,
|
|
439
|
+
pedidos: opciones.pedidos.map((p) => ({
|
|
440
|
+
query: { ...p.query },
|
|
441
|
+
estado: p.estado
|
|
442
|
+
})),
|
|
443
|
+
archivo: ARCHIVO_DEPLOYMENTS_V6,
|
|
444
|
+
sha256,
|
|
445
|
+
transformaciones: opciones.transformaciones ?? []
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
function ejecutarCapturar(opciones) {
|
|
449
|
+
const rango = rangoFechasUtc(opciones.desde, opciones.hasta);
|
|
450
|
+
if (!rango.ok) {
|
|
451
|
+
opciones.error(`wallavi-vercel capturar: ${rango.motivo}`);
|
|
452
|
+
return 2;
|
|
453
|
+
}
|
|
454
|
+
const token = opciones.env.VERCEL_TOKEN?.trim() ?? "";
|
|
455
|
+
if (!token) {
|
|
456
|
+
opciones.error("wallavi-vercel capturar: falta VERCEL_TOKEN");
|
|
457
|
+
return 2;
|
|
458
|
+
}
|
|
459
|
+
try {
|
|
460
|
+
const baseUrl = opciones.baseUrl ?? opciones.env.VERCEL_API_URL?.trim() ?? API_VERCEL_URL;
|
|
461
|
+
const teamId = resolverEquipo(
|
|
462
|
+
opciones.equipo,
|
|
463
|
+
token,
|
|
464
|
+
opciones.solicitar,
|
|
465
|
+
baseUrl
|
|
466
|
+
);
|
|
467
|
+
const { paginas, pedidos } = consultarDeployments({
|
|
468
|
+
teamId,
|
|
469
|
+
since: rango.since,
|
|
470
|
+
until: rango.until,
|
|
471
|
+
token,
|
|
472
|
+
solicitar: opciones.solicitar,
|
|
473
|
+
baseUrl
|
|
474
|
+
});
|
|
475
|
+
const rutaCarpeta = path3__namespace.resolve(opciones.cwd, opciones.salida);
|
|
476
|
+
fs.mkdirSync(rutaCarpeta, { recursive: true });
|
|
477
|
+
const contenidoDeployments = `${JSON.stringify({ paginas }, null, 2)}
|
|
478
|
+
`;
|
|
479
|
+
fs.writeFileSync(
|
|
480
|
+
path3__namespace.join(rutaCarpeta, ARCHIVO_DEPLOYMENTS_V6),
|
|
481
|
+
contenidoDeployments,
|
|
482
|
+
"utf8"
|
|
483
|
+
);
|
|
484
|
+
const captura = armarCapturaV6({
|
|
485
|
+
desde: opciones.desde,
|
|
486
|
+
hasta: opciones.hasta,
|
|
487
|
+
pedidos,
|
|
488
|
+
contenidoDeployments,
|
|
489
|
+
origen: opciones.origen,
|
|
490
|
+
referencia: opciones.referencia,
|
|
491
|
+
fecha: opciones.fecha,
|
|
492
|
+
transformaciones: opciones.transformaciones
|
|
493
|
+
});
|
|
494
|
+
fs.writeFileSync(
|
|
495
|
+
path3__namespace.join(rutaCarpeta, ARCHIVO_CAPTURA_V6),
|
|
496
|
+
`${JSON.stringify(captura, null, 2)}
|
|
497
|
+
`,
|
|
498
|
+
"utf8"
|
|
499
|
+
);
|
|
500
|
+
opciones.salidaTexto?.(JSON.stringify(captura, null, 2));
|
|
501
|
+
return 0;
|
|
502
|
+
} catch (e) {
|
|
503
|
+
opciones.error(
|
|
504
|
+
`wallavi-vercel capturar: ${redactarToken(e.message, token)}`
|
|
505
|
+
);
|
|
506
|
+
return e instanceof ErrorContratoVercel ? 2 : 1;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
function comandoCapturar(args, entorno) {
|
|
510
|
+
const leido = leerArgumentosCapturar(args);
|
|
511
|
+
if (!leido.ok) {
|
|
512
|
+
entorno.error(`wallavi-vercel capturar: ${leido.motivo}`);
|
|
513
|
+
return 2;
|
|
514
|
+
}
|
|
515
|
+
return ejecutarCapturar({
|
|
516
|
+
cwd: entorno.cwd,
|
|
517
|
+
env: entorno.env,
|
|
518
|
+
error: entorno.error,
|
|
519
|
+
salidaTexto: entorno.salida,
|
|
520
|
+
...leido.valor
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
var capturar = comandoCapturar;
|
|
524
|
+
var ARCHIVO_CONFIG = "vercel-build.config.json";
|
|
525
|
+
function normalizarCarpeta(carpeta) {
|
|
526
|
+
let limpia = carpeta.trim();
|
|
527
|
+
while (limpia.startsWith("./")) limpia = limpia.slice(2);
|
|
528
|
+
while (limpia.length > 1 && limpia.endsWith("/"))
|
|
529
|
+
limpia = limpia.slice(0, -1);
|
|
530
|
+
return limpia === "" ? "." : limpia;
|
|
531
|
+
}
|
|
532
|
+
var esquemaCarpeta = zod.z.string().min(1).transform(normalizarCarpeta).refine((c) => !c.startsWith("/") && !c.split("/").includes(".."), {
|
|
533
|
+
message: "debe ser una ruta relativa a la ra\xEDz, sin .."
|
|
534
|
+
});
|
|
535
|
+
var esquemaProyecto = zod.z.object({
|
|
536
|
+
carpetas: zod.z.array(esquemaCarpeta),
|
|
537
|
+
carpetasExtra: zod.z.array(esquemaCarpeta).optional()
|
|
538
|
+
}).strict();
|
|
539
|
+
var esquemaConfig = zod.z.object({
|
|
540
|
+
ramasConPreview: zod.z.array(zod.z.string().min(1)),
|
|
541
|
+
proyectos: zod.z.record(zod.z.string().min(1), esquemaProyecto)
|
|
542
|
+
}).strict();
|
|
543
|
+
function configVacia() {
|
|
544
|
+
return { ramasConPreview: [], proyectos: {} };
|
|
545
|
+
}
|
|
546
|
+
function describirProblema(p) {
|
|
547
|
+
const ruta = p.path.join(".");
|
|
548
|
+
const llaves = p.code === "unrecognized_keys" ? p.keys.map((k) => ruta ? `${ruta}.${k}` : k).join(", ") : "";
|
|
549
|
+
return `${llaves || ruta || "(ra\xEDz)"}: ${p.message}`;
|
|
550
|
+
}
|
|
551
|
+
function validarConfig(valor, origen = ARCHIVO_CONFIG) {
|
|
552
|
+
const r = esquemaConfig.safeParse(valor);
|
|
553
|
+
if (!r.success) {
|
|
554
|
+
throw new Error(
|
|
555
|
+
`${origen}: ${r.error.issues.map(describirProblema).join("; ")}`
|
|
556
|
+
);
|
|
557
|
+
}
|
|
558
|
+
return r.data;
|
|
559
|
+
}
|
|
560
|
+
function leerConfig(ruta = ARCHIVO_CONFIG) {
|
|
561
|
+
if (!fs.existsSync(ruta)) return configVacia();
|
|
562
|
+
let valor;
|
|
563
|
+
try {
|
|
564
|
+
valor = JSON.parse(fs.readFileSync(ruta, "utf8"));
|
|
565
|
+
} catch (e) {
|
|
566
|
+
throw new Error(`${ruta}: JSON inv\xE1lido: ${e.message}`);
|
|
567
|
+
}
|
|
568
|
+
return validarConfig(valor, ruta);
|
|
569
|
+
}
|
|
570
|
+
function proyectoDeCarpeta(config, carpeta) {
|
|
571
|
+
const buscada = normalizarCarpeta(carpeta);
|
|
572
|
+
for (const [nombre, proyecto] of Object.entries(config.proyectos)) {
|
|
573
|
+
if (proyecto.carpetas.includes(buscada)) return { nombre, proyecto };
|
|
574
|
+
}
|
|
575
|
+
return null;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// src/cambios.ts
|
|
579
|
+
function ejecutar(comando, args, opciones) {
|
|
580
|
+
const r = child_process.spawnSync(comando, args, {
|
|
581
|
+
cwd: opciones.cwd,
|
|
582
|
+
env: opciones.env ?? process.env,
|
|
583
|
+
shell: false,
|
|
584
|
+
encoding: "utf8",
|
|
585
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
586
|
+
stdio: opciones.heredar ? "inherit" : "pipe"
|
|
587
|
+
});
|
|
588
|
+
const fallo = r.error?.message ?? (r.signal ? `termin\xF3 por la se\xF1al ${r.signal}` : void 0);
|
|
589
|
+
return {
|
|
590
|
+
codigo: r.status,
|
|
591
|
+
salida: r.stdout ?? "",
|
|
592
|
+
error: r.stderr ?? "",
|
|
593
|
+
...fallo ? { fallo } : {}
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
var incierto = (motivo) => ({
|
|
597
|
+
resultado: "incierto",
|
|
598
|
+
motivo
|
|
599
|
+
});
|
|
600
|
+
function salidaGit(ej, cwd, args) {
|
|
601
|
+
const r = ej("git", args, { cwd });
|
|
602
|
+
return r.codigo === 0 ? r.salida.trim() : null;
|
|
603
|
+
}
|
|
604
|
+
function ubicarEnRepo(carpeta, ej = ejecutar) {
|
|
605
|
+
const raiz = salidaGit(ej, carpeta, ["rev-parse", "--show-toplevel"]);
|
|
606
|
+
const prefijo = salidaGit(ej, carpeta, ["rev-parse", "--show-prefix"]);
|
|
607
|
+
if (!raiz || prefijo === null) return null;
|
|
608
|
+
return { raiz, prefijo: normalizarCarpeta(prefijo) };
|
|
609
|
+
}
|
|
610
|
+
function nombrePaquete(archivo) {
|
|
611
|
+
if (!fs.existsSync(archivo)) return null;
|
|
612
|
+
try {
|
|
613
|
+
const n = JSON.parse(fs.readFileSync(archivo, "utf8")).name;
|
|
614
|
+
return typeof n === "string" && n !== "" ? n : null;
|
|
615
|
+
} catch {
|
|
616
|
+
return null;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
function comandoTurbo(raiz) {
|
|
620
|
+
const local = path3__namespace.join(raiz, "node_modules", ".bin", "turbo");
|
|
621
|
+
if (fs.existsSync(local)) return [local, []];
|
|
622
|
+
let version = "latest";
|
|
623
|
+
try {
|
|
624
|
+
const pkg = JSON.parse(
|
|
625
|
+
fs.readFileSync(path3__namespace.join(raiz, "package.json"), "utf8")
|
|
626
|
+
);
|
|
627
|
+
const decl = pkg.devDependencies?.turbo;
|
|
628
|
+
if (typeof decl === "string" && decl !== "") version = decl;
|
|
629
|
+
} catch {
|
|
630
|
+
}
|
|
631
|
+
return ["npx", ["--yes", `turbo@${version}`]];
|
|
632
|
+
}
|
|
633
|
+
function paquetesDeTurbo(salida) {
|
|
634
|
+
const i = salida.indexOf("{");
|
|
635
|
+
if (i === -1) return null;
|
|
636
|
+
try {
|
|
637
|
+
const p = JSON.parse(salida.slice(i)).packages;
|
|
638
|
+
return Array.isArray(p) && p.every((x) => typeof x === "string") ? p : null;
|
|
639
|
+
} catch {
|
|
640
|
+
return null;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
function diffGit(ej, cwd, antes, rutas) {
|
|
644
|
+
const r = ej("git", ["diff", "--quiet", antes, "HEAD", "--", ...rutas], {
|
|
645
|
+
cwd
|
|
646
|
+
});
|
|
647
|
+
const lista = rutas.join(", ");
|
|
648
|
+
if (r.codigo === 0)
|
|
649
|
+
return { resultado: "sin-cambios", motivo: `git: sin cambios en ${lista}` };
|
|
650
|
+
if (r.codigo === 1)
|
|
651
|
+
return { resultado: "con-cambios", motivo: `git: hay cambios en ${lista}` };
|
|
652
|
+
return incierto(`git diff fall\xF3 (${r.fallo ?? `c\xF3digo ${r.codigo}`})`);
|
|
653
|
+
}
|
|
654
|
+
function evaluarCambios(opciones) {
|
|
655
|
+
const ej = opciones.ejecutar ?? ejecutar;
|
|
656
|
+
const env = opciones.env ?? process.env;
|
|
657
|
+
const carpeta = path3__namespace.resolve(opciones.carpeta);
|
|
658
|
+
const ubicacion = ubicarEnRepo(carpeta, ej);
|
|
659
|
+
if (!ubicacion) return incierto(`${carpeta} no est\xE1 en un repo de Git`);
|
|
660
|
+
const { raiz, prefijo } = ubicacion;
|
|
661
|
+
const head = salidaGit(ej, raiz, ["rev-parse", "HEAD"]);
|
|
662
|
+
if (!head) return incierto("no se pudo leer HEAD");
|
|
663
|
+
if (env.VERCEL_GIT_COMMIT_SHA && env.VERCEL_GIT_COMMIT_SHA !== head) {
|
|
664
|
+
return incierto(`VERCEL_GIT_COMMIT_SHA no coincide con HEAD (${head})`);
|
|
665
|
+
}
|
|
666
|
+
const antes = opciones.antes ?? env.VERCEL_GIT_PREVIOUS_SHA ?? "";
|
|
667
|
+
if (antes === "") return incierto("no hay commit anterior");
|
|
668
|
+
if (antes.startsWith("-"))
|
|
669
|
+
return incierto(`commit anterior inv\xE1lido: ${antes}`);
|
|
670
|
+
if (ej("git", ["cat-file", "-e", `${antes}^{commit}`], { cwd: raiz }).codigo !== 0) {
|
|
671
|
+
return incierto(`el commit anterior ${antes} no est\xE1 en el clon`);
|
|
672
|
+
}
|
|
673
|
+
let config;
|
|
674
|
+
try {
|
|
675
|
+
config = opciones.config ?? leerConfig(path3__namespace.join(raiz, ARCHIVO_CONFIG));
|
|
676
|
+
} catch (e) {
|
|
677
|
+
return incierto(e.message);
|
|
678
|
+
}
|
|
679
|
+
const proy = proyectoDeCarpeta(config, prefijo)?.proyecto;
|
|
680
|
+
const extras = [
|
|
681
|
+
.../* @__PURE__ */ new Set([...proy?.carpetas ?? [], ...proy?.carpetasExtra ?? []])
|
|
682
|
+
].filter((c) => c !== prefijo);
|
|
683
|
+
const nombre = nombrePaquete(path3__namespace.join(raiz, prefijo, "package.json"));
|
|
684
|
+
if (!fs.existsSync(path3__namespace.join(raiz, "turbo.json")) || !nombre) {
|
|
685
|
+
return diffGit(ej, raiz, antes, [prefijo, ...extras]);
|
|
686
|
+
}
|
|
687
|
+
const [turbo, base] = comandoTurbo(raiz);
|
|
688
|
+
const r = ej(
|
|
689
|
+
turbo,
|
|
690
|
+
[...base, "build", `--filter=${nombre}...[${antes}]`, "--dry=json"],
|
|
691
|
+
{
|
|
692
|
+
cwd: raiz,
|
|
693
|
+
env
|
|
694
|
+
}
|
|
695
|
+
);
|
|
696
|
+
if (r.codigo !== 0)
|
|
697
|
+
return incierto(`turbo fall\xF3 (${r.fallo ?? `c\xF3digo ${r.codigo}`})`);
|
|
698
|
+
const paquetes = paquetesDeTurbo(r.salida);
|
|
699
|
+
if (!paquetes) return incierto("la salida de turbo no trae packages");
|
|
700
|
+
const afectados = paquetes.filter((p) => p !== "//");
|
|
701
|
+
if (afectados.length > 0) {
|
|
702
|
+
return {
|
|
703
|
+
resultado: "con-cambios",
|
|
704
|
+
motivo: `turbo: afectados ${afectados.join(", ")}`
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
if (extras.length > 0) return diffGit(ej, raiz, antes, extras);
|
|
708
|
+
return {
|
|
709
|
+
resultado: "sin-cambios",
|
|
710
|
+
motivo: `turbo: ${nombre} sin paquetes afectados`
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// src/comandos/desplegar.ts
|
|
715
|
+
var VARIABLES_VERCEL = [
|
|
716
|
+
"VERCEL_TOKEN",
|
|
717
|
+
"VERCEL_ORG_ID",
|
|
718
|
+
"VERCEL_PROJECT_ID"
|
|
719
|
+
];
|
|
720
|
+
var PASOS_VERCEL = [
|
|
721
|
+
["pull", "--yes", "--environment=production"],
|
|
722
|
+
["build", "--prod"],
|
|
723
|
+
["deploy", "--prebuilt", "--prod"]
|
|
724
|
+
];
|
|
725
|
+
function leerArgumentosDesplegar(args) {
|
|
726
|
+
let carpeta;
|
|
727
|
+
let antes;
|
|
728
|
+
for (let i = 0; i < args.length; i++) {
|
|
729
|
+
const arg = args[i] ?? "";
|
|
730
|
+
if (arg === "--carpeta" || arg.startsWith("--carpeta=")) {
|
|
731
|
+
const valor = arg === "--carpeta" ? args[++i] : arg.slice("--carpeta=".length);
|
|
732
|
+
if (!valor || valor.trim() === "" || valor.startsWith("-")) {
|
|
733
|
+
return { ok: false, motivo: "falta el valor de --carpeta <ruta>" };
|
|
734
|
+
}
|
|
735
|
+
carpeta = valor.trim();
|
|
736
|
+
continue;
|
|
737
|
+
}
|
|
738
|
+
if (arg === "--antes" || arg.startsWith("--antes=")) {
|
|
739
|
+
const valor = arg === "--antes" ? args[++i] : arg.slice("--antes=".length);
|
|
740
|
+
if (!valor || valor.trim() === "" || valor.startsWith("-")) {
|
|
741
|
+
return { ok: false, motivo: "falta el valor de --antes <sha>" };
|
|
742
|
+
}
|
|
743
|
+
antes = valor.trim();
|
|
744
|
+
continue;
|
|
745
|
+
}
|
|
746
|
+
return { ok: false, motivo: `argumento no reconocido: ${arg}` };
|
|
747
|
+
}
|
|
748
|
+
if (!carpeta) {
|
|
749
|
+
return {
|
|
750
|
+
ok: false,
|
|
751
|
+
motivo: "falta la opci\xF3n obligatoria --carpeta <ruta>"
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
return {
|
|
755
|
+
ok: true,
|
|
756
|
+
valor: { carpeta, ...antes !== void 0 ? { antes } : {} }
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
function redactarCredenciales(texto, env) {
|
|
760
|
+
let limpio = texto;
|
|
761
|
+
for (const nombre of VARIABLES_VERCEL) {
|
|
762
|
+
const valor = env[nombre]?.trim();
|
|
763
|
+
if (valor) {
|
|
764
|
+
limpio = limpio.split(valor).join("[REDACTED]");
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
return limpio;
|
|
768
|
+
}
|
|
769
|
+
function ejecutarDesplegar(opciones) {
|
|
770
|
+
const ej = opciones.ejecutar ?? ejecutar;
|
|
771
|
+
const evaluar = opciones.evaluar ?? evaluarCambios;
|
|
772
|
+
const rutaCarpeta = path3__namespace.resolve(opciones.cwd, opciones.carpeta);
|
|
773
|
+
if (!fs.existsSync(rutaCarpeta) || !fs.statSync(rutaCarpeta).isDirectory()) {
|
|
774
|
+
opciones.error(
|
|
775
|
+
`wallavi-vercel desplegar: la carpeta no existe: ${opciones.carpeta}`
|
|
776
|
+
);
|
|
777
|
+
return 2;
|
|
778
|
+
}
|
|
779
|
+
const faltan = VARIABLES_VERCEL.filter(
|
|
780
|
+
(nombre) => !opciones.env[nombre]?.trim()
|
|
781
|
+
);
|
|
782
|
+
if (faltan.length > 0) {
|
|
783
|
+
opciones.error(`wallavi-vercel desplegar: faltan ${faltan.join(", ")}`);
|
|
784
|
+
return 2;
|
|
785
|
+
}
|
|
786
|
+
const evaluacion = evaluar({
|
|
787
|
+
carpeta: rutaCarpeta,
|
|
788
|
+
...opciones.antes !== void 0 ? { antes: opciones.antes } : {},
|
|
789
|
+
env: opciones.env,
|
|
790
|
+
ejecutar: ej
|
|
791
|
+
});
|
|
792
|
+
if (evaluacion.resultado === "sin-cambios") {
|
|
793
|
+
opciones.salida(
|
|
794
|
+
`wallavi-vercel desplegar: sin cambios (${evaluacion.motivo})`
|
|
795
|
+
);
|
|
796
|
+
return 0;
|
|
797
|
+
}
|
|
798
|
+
for (const paso of PASOS_VERCEL) {
|
|
799
|
+
const r = ej("vercel", paso, {
|
|
800
|
+
cwd: rutaCarpeta,
|
|
801
|
+
env: opciones.env
|
|
802
|
+
});
|
|
803
|
+
if (r.salida.trim() !== "") {
|
|
804
|
+
opciones.salida(redactarCredenciales(r.salida.trimEnd(), opciones.env));
|
|
805
|
+
}
|
|
806
|
+
if (r.error.trim() !== "") {
|
|
807
|
+
opciones.error(redactarCredenciales(r.error.trimEnd(), opciones.env));
|
|
808
|
+
}
|
|
809
|
+
if (r.codigo !== 0) {
|
|
810
|
+
const codigo = r.codigo ?? 127;
|
|
811
|
+
opciones.error(
|
|
812
|
+
redactarCredenciales(
|
|
813
|
+
`wallavi-vercel desplegar: vercel ${paso.join(" ")} fall\xF3 (${r.fallo ?? `c\xF3digo ${codigo}`})`,
|
|
814
|
+
opciones.env
|
|
815
|
+
)
|
|
816
|
+
);
|
|
817
|
+
return codigo;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
opciones.salida(
|
|
821
|
+
`wallavi-vercel desplegar: desplegado (${evaluacion.motivo})`
|
|
822
|
+
);
|
|
823
|
+
return 0;
|
|
824
|
+
}
|
|
825
|
+
function comandoDesplegar(args, entorno) {
|
|
826
|
+
const leido = leerArgumentosDesplegar(args);
|
|
827
|
+
if (!leido.ok) {
|
|
828
|
+
entorno.error(`wallavi-vercel desplegar: ${leido.motivo}`);
|
|
829
|
+
return 2;
|
|
830
|
+
}
|
|
831
|
+
return ejecutarDesplegar({
|
|
832
|
+
...entorno,
|
|
833
|
+
carpeta: leido.valor.carpeta,
|
|
834
|
+
...leido.valor.antes !== void 0 ? { antes: leido.valor.antes } : {}
|
|
835
|
+
});
|
|
836
|
+
}
|
|
837
|
+
var desplegar = comandoDesplegar;
|
|
838
|
+
var RAMA_PRINCIPAL = "main";
|
|
839
|
+
var PREFIJO_PREVIEW = "preview/";
|
|
840
|
+
function ramaPermitida(rama, config) {
|
|
841
|
+
return rama === RAMA_PRINCIPAL || rama.startsWith(PREFIJO_PREVIEW) || config.ramasConPreview.includes(rama);
|
|
842
|
+
}
|
|
843
|
+
function ejecutarIgnorar(opciones) {
|
|
844
|
+
const ej = opciones.ejecutar ?? ejecutar;
|
|
845
|
+
const evaluar = opciones.evaluar ?? evaluarCambios;
|
|
846
|
+
const decidir = (codigo, motivo) => {
|
|
847
|
+
opciones.salida(
|
|
848
|
+
`wallavi-vercel ignorar: ${codigo === 0 ? "no compilar" : "compilar"} (${motivo})`
|
|
849
|
+
);
|
|
850
|
+
return codigo;
|
|
851
|
+
};
|
|
852
|
+
const rama = opciones.env.VERCEL_GIT_COMMIT_REF?.trim() ?? "";
|
|
853
|
+
if (!rama) {
|
|
854
|
+
return decidir(1, "falta VERCEL_GIT_COMMIT_REF");
|
|
855
|
+
}
|
|
856
|
+
let config = opciones.config;
|
|
857
|
+
if (!config) {
|
|
858
|
+
const carpeta = path3__namespace.resolve(opciones.cwd);
|
|
859
|
+
const ubicacion = ubicarEnRepo(carpeta, ej);
|
|
860
|
+
if (!ubicacion) {
|
|
861
|
+
return decidir(1, `${carpeta} no est\xE1 en un repo de Git`);
|
|
862
|
+
}
|
|
863
|
+
try {
|
|
864
|
+
config = leerConfig(path3__namespace.join(ubicacion.raiz, ARCHIVO_CONFIG));
|
|
865
|
+
} catch (e) {
|
|
866
|
+
return decidir(1, e.message);
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
if (!ramaPermitida(rama, config)) {
|
|
870
|
+
return decidir(0, `rama ${rama} fuera de las permitidas`);
|
|
871
|
+
}
|
|
872
|
+
const shaActual = opciones.env.VERCEL_GIT_COMMIT_SHA?.trim() ?? "";
|
|
873
|
+
if (!shaActual) {
|
|
874
|
+
return decidir(1, "falta VERCEL_GIT_COMMIT_SHA");
|
|
875
|
+
}
|
|
876
|
+
const shaAnterior = opciones.env.VERCEL_GIT_PREVIOUS_SHA?.trim() ?? "";
|
|
877
|
+
if (!shaAnterior) {
|
|
878
|
+
return decidir(1, "falta VERCEL_GIT_PREVIOUS_SHA");
|
|
879
|
+
}
|
|
880
|
+
const evaluacion = evaluar({
|
|
881
|
+
carpeta: opciones.cwd,
|
|
882
|
+
antes: shaAnterior,
|
|
883
|
+
env: opciones.env,
|
|
884
|
+
config,
|
|
885
|
+
ejecutar: ej
|
|
886
|
+
});
|
|
887
|
+
if (evaluacion.resultado === "sin-cambios") {
|
|
888
|
+
return decidir(0, evaluacion.motivo);
|
|
889
|
+
}
|
|
890
|
+
return decidir(1, evaluacion.motivo);
|
|
891
|
+
}
|
|
892
|
+
function comandoIgnorar(args, entorno) {
|
|
893
|
+
if (args.length > 0) {
|
|
894
|
+
entorno.error(
|
|
895
|
+
`wallavi-vercel ignorar: argumentos no reconocidos: ${args.join(" ")}`
|
|
896
|
+
);
|
|
897
|
+
return 2;
|
|
898
|
+
}
|
|
899
|
+
return ejecutarIgnorar(entorno);
|
|
900
|
+
}
|
|
901
|
+
var ignorar = comandoIgnorar;
|
|
902
|
+
|
|
903
|
+
// src/index.ts
|
|
904
|
+
var USO = `Uso: wallavi-vercel <comando> [opciones]
|
|
905
|
+
|
|
906
|
+
Comandos:
|
|
907
|
+
ignorar decide si Vercel debe omitir el build
|
|
908
|
+
desplegar --carpeta <ruta> [--antes <sha>] compila y despliega a producci\xF3n si hay cambios
|
|
909
|
+
medir --equipo <slug|team_id> --desde <AAAA-MM-DD> --hasta <AAAA-MM-DD> [...] calcula los minutos de build por d\xEDa en UTC
|
|
910
|
+
capturar --equipo <slug|team_id> --desde <AAAA-MM-DD> --hasta <AAAA-MM-DD> ... descarga deployments de Vercel y escribe su captura
|
|
911
|
+
|
|
912
|
+
Opciones:
|
|
913
|
+
-h, --help muestra esta ayuda
|
|
914
|
+
`;
|
|
915
|
+
var COMANDOS = {
|
|
916
|
+
ignorar: comandoIgnorar,
|
|
917
|
+
desplegar: comandoDesplegar,
|
|
918
|
+
medir: comandoMedir,
|
|
919
|
+
capturar: comandoCapturar
|
|
920
|
+
};
|
|
921
|
+
function principal(argv, entorno) {
|
|
922
|
+
const [nombre, ...args] = argv;
|
|
923
|
+
if (nombre === void 0 || nombre === "--help" || nombre === "-h") {
|
|
924
|
+
(nombre === void 0 ? entorno.error : entorno.salida)(USO);
|
|
925
|
+
return nombre === void 0 ? 2 : 0;
|
|
926
|
+
}
|
|
927
|
+
const comando = Object.hasOwn(COMANDOS, nombre) && COMANDOS[nombre];
|
|
928
|
+
if (!comando) {
|
|
929
|
+
entorno.error(`wallavi-vercel: comando desconocido: ${nombre}
|
|
930
|
+
${USO}`);
|
|
931
|
+
return 2;
|
|
932
|
+
}
|
|
933
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
934
|
+
entorno.salida(USO);
|
|
935
|
+
return 0;
|
|
936
|
+
}
|
|
937
|
+
return comando(args, entorno);
|
|
938
|
+
}
|
|
939
|
+
if (__require.main === module) {
|
|
940
|
+
process.exitCode = principal(process.argv.slice(2), {
|
|
941
|
+
cwd: process.cwd(),
|
|
942
|
+
env: process.env,
|
|
943
|
+
salida: (t) => console.log(t),
|
|
944
|
+
error: (t) => console.error(t)
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
exports.API_VERCEL_URL = API_VERCEL_URL;
|
|
949
|
+
exports.ARCHIVO_CAPTURA_V6 = ARCHIVO_CAPTURA_V6;
|
|
950
|
+
exports.ARCHIVO_CONFIG = ARCHIVO_CONFIG;
|
|
951
|
+
exports.ARCHIVO_DEPLOYMENTS_V6 = ARCHIVO_DEPLOYMENTS_V6;
|
|
952
|
+
exports.COMANDOS = COMANDOS;
|
|
953
|
+
exports.ESTADOS_DEPLOYMENT = ESTADOS_DEPLOYMENT;
|
|
954
|
+
exports.ErrorContratoVercel = ErrorContratoVercel;
|
|
955
|
+
exports.ErrorRedVercel = ErrorRedVercel;
|
|
956
|
+
exports.LIMITE_PAGINA_VERCEL = LIMITE_PAGINA_VERCEL;
|
|
957
|
+
exports.MAX_PAGINAS_VERCEL = MAX_PAGINAS_VERCEL;
|
|
958
|
+
exports.PASOS_VERCEL = PASOS_VERCEL;
|
|
959
|
+
exports.PREFIJO_PREVIEW = PREFIJO_PREVIEW;
|
|
960
|
+
exports.RAMA_PRINCIPAL = RAMA_PRINCIPAL;
|
|
961
|
+
exports.REFERENCIA_DEPLOYMENTS_V6 = REFERENCIA_DEPLOYMENTS_V6;
|
|
962
|
+
exports.USO = USO;
|
|
963
|
+
exports.VARIABLES_VERCEL = VARIABLES_VERCEL;
|
|
964
|
+
exports.armarCapturaV6 = armarCapturaV6;
|
|
965
|
+
exports.calcularMinutosPorDia = calcularMinutosPorDia;
|
|
966
|
+
exports.capturar = capturar;
|
|
967
|
+
exports.comandoCapturar = comandoCapturar;
|
|
968
|
+
exports.comandoDesplegar = comandoDesplegar;
|
|
969
|
+
exports.comandoIgnorar = comandoIgnorar;
|
|
970
|
+
exports.comandoMedir = comandoMedir;
|
|
971
|
+
exports.comandoTurbo = comandoTurbo;
|
|
972
|
+
exports.configVacia = configVacia;
|
|
973
|
+
exports.consultarDeployments = consultarDeployments;
|
|
974
|
+
exports.desplegar = desplegar;
|
|
975
|
+
exports.ejecutar = ejecutar;
|
|
976
|
+
exports.ejecutarCapturar = ejecutarCapturar;
|
|
977
|
+
exports.ejecutarDesplegar = ejecutarDesplegar;
|
|
978
|
+
exports.ejecutarIgnorar = ejecutarIgnorar;
|
|
979
|
+
exports.ejecutarMedir = ejecutarMedir;
|
|
980
|
+
exports.esquemaArchivoDeployments = esquemaArchivoDeployments;
|
|
981
|
+
exports.esquemaCapturaV6 = esquemaCapturaV6;
|
|
982
|
+
exports.esquemaConfig = esquemaConfig;
|
|
983
|
+
exports.esquemaDeployment = esquemaDeployment;
|
|
984
|
+
exports.esquemaEquipo = esquemaEquipo;
|
|
985
|
+
exports.esquemaEstadoDeployment = esquemaEstadoDeployment;
|
|
986
|
+
exports.esquemaPaginaDeployments = esquemaPaginaDeployments;
|
|
987
|
+
exports.esquemaPaginaTeams = esquemaPaginaTeams;
|
|
988
|
+
exports.esquemaPaginacion = esquemaPaginacion;
|
|
989
|
+
exports.esquemaPedidoCaptura = esquemaPedidoCaptura;
|
|
990
|
+
exports.evaluarCambios = evaluarCambios;
|
|
991
|
+
exports.ignorar = ignorar;
|
|
992
|
+
exports.leerArgumentosCapturar = leerArgumentosCapturar;
|
|
993
|
+
exports.leerArgumentosDesplegar = leerArgumentosDesplegar;
|
|
994
|
+
exports.leerArgumentosMedir = leerArgumentosMedir;
|
|
995
|
+
exports.leerConfig = leerConfig;
|
|
996
|
+
exports.leerFlagsCli = leerFlagsCli;
|
|
997
|
+
exports.leerRespuestaDeployments = leerRespuestaDeployments;
|
|
998
|
+
exports.medir = medir;
|
|
999
|
+
exports.normalizarCarpeta = normalizarCarpeta;
|
|
1000
|
+
exports.paquetesDeTurbo = paquetesDeTurbo;
|
|
1001
|
+
exports.pedirJsonVercel = pedirJsonVercel;
|
|
1002
|
+
exports.principal = principal;
|
|
1003
|
+
exports.proyectoDeCarpeta = proyectoDeCarpeta;
|
|
1004
|
+
exports.ramaPermitida = ramaPermitida;
|
|
1005
|
+
exports.rangoFechasUtc = rangoFechasUtc;
|
|
1006
|
+
exports.redactarToken = redactarToken;
|
|
1007
|
+
exports.resolverEquipo = resolverEquipo;
|
|
1008
|
+
exports.solicitarVercel = solicitarVercel;
|
|
1009
|
+
exports.ubicarEnRepo = ubicarEnRepo;
|
|
1010
|
+
exports.validarConfig = validarConfig;
|
|
1011
|
+
exports.validarFechaIso = validarFechaIso;
|