@trendify/cli 0.1.23 → 0.1.25

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.
@@ -1 +1 @@
1
- {"version":3,"file":"app.component.d.ts","sourceRoot":"","sources":["../src/app.component.tsx"],"names":[],"mappings":"AAYA,OAAO,EAAqB,KAAK,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AAMvG,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C,QAAQ,CAAC,uBAAuB,CAAC,EAAE,gBAAgB,CAAC;IACpD,QAAQ,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,oBAAoB,EAAE;QAAE,MAAM,EAAE,WAAW,CAAA;KAAE,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjH,CAAC;AA6DF,KAAK,gBAAgB,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;AAiFrD,wBAAgB,GAAG,CAAC,EAClB,UAAU,EACV,YAAY,EACZ,mBAA0B,EAC1B,uBAAmC,EACnC,YAAY,GACb,EAAE,QAAQ,2CAkhBV"}
1
+ {"version":3,"file":"app.component.d.ts","sourceRoot":"","sources":["../src/app.component.tsx"],"names":[],"mappings":"AAYA,OAAO,EAAqB,KAAK,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AAMvG,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C,QAAQ,CAAC,uBAAuB,CAAC,EAAE,gBAAgB,CAAC;IACpD,QAAQ,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,oBAAoB,EAAE;QAAE,MAAM,EAAE,WAAW,CAAA;KAAE,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjH,CAAC;AA6DF,KAAK,gBAAgB,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;AAiFrD,wBAAgB,GAAG,CAAC,EAClB,UAAU,EACV,YAAY,EACZ,mBAA0B,EAC1B,uBAAmC,EACnC,YAAY,GACb,EAAE,QAAQ,2CAqgBV"}
@@ -66,7 +66,7 @@ const MENU_ITEMS = [
66
66
  ],
67
67
  },
68
68
  ];
69
- const UPDATE_CHECK_DELAYS_MS = [15_000, 60_000, 180_000, 300_000, 600_000];
69
+ const UPDATE_CHECK_INTERVAL_MS = 600_000;
70
70
  const LOGOUT_OPTIONS = [
71
71
  {
72
72
  value: 'cancel',
@@ -232,22 +232,10 @@ export function App({ appVersion, initialInput, initialNotification = null, init
232
232
  });
233
233
  useEffect(() => {
234
234
  let active = true;
235
- let timeout = null;
236
- let delayIndex = 0;
235
+ let interval = null;
237
236
  let checking = false;
238
- const scheduleNextCheck = () => {
239
- if (!active) {
240
- return;
241
- }
242
- const delay = UPDATE_CHECK_DELAYS_MS[Math.min(delayIndex, UPDATE_CHECK_DELAYS_MS.length - 1)];
243
- timeout = setTimeout(() => {
244
- void checkUpdates();
245
- }, delay);
246
- delayIndex += 1;
247
- };
248
237
  const checkUpdates = async () => {
249
- if (checking) {
250
- scheduleNextCheck();
238
+ if (checking || !active) {
251
239
  return;
252
240
  }
253
241
  checking = true;
@@ -262,13 +250,15 @@ export function App({ appVersion, initialInput, initialNotification = null, init
262
250
  }
263
251
  return result;
264
252
  });
265
- scheduleNextCheck();
266
253
  };
267
254
  void checkUpdates();
255
+ interval = setInterval(() => {
256
+ void checkUpdates();
257
+ }, UPDATE_CHECK_INTERVAL_MS);
268
258
  return () => {
269
259
  active = false;
270
- if (timeout) {
271
- clearTimeout(timeout);
260
+ if (interval) {
261
+ clearInterval(interval);
272
262
  }
273
263
  };
274
264
  }, [appVersion]);
@@ -1 +1 @@
1
- {"version":3,"file":"cli-update.service.d.ts","sourceRoot":"","sources":["../../../src/shared/services/cli-update.service.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,oBAAoB,GAC5B;IACE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;CAC7B,GACD;IACE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;CAC9B,GACD;IACE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;CAC5B,GACD;IACE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEN,MAAM,MAAM,mBAAmB,GAC3B;IACE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;CACnB,GACD;IACE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;CACpB,CAAC;AAEN,KAAK,wBAAwB,GAAG;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC,CAAC;AA4CF,wBAAgB,uBAAuB,IAAI,wBAAwB,CAElE;AAwSD,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,oBAAoB,CAAC,CA6BvE;AAED,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAY/G"}
1
+ {"version":3,"file":"cli-update.service.d.ts","sourceRoot":"","sources":["../../../src/shared/services/cli-update.service.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,oBAAoB,GAC5B;IACE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;CAC7B,GACD;IACE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;CAC9B,GACD;IACE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;CAC5B,GACD;IACE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEN,MAAM,MAAM,mBAAmB,GAC3B;IACE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;CACnB,GACD;IACE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;CACpB,CAAC;AAEN,KAAK,wBAAwB,GAAG;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC,CAAC;AAgDF,wBAAgB,uBAAuB,IAAI,wBAAwB,CAElE;AAsLD,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,oBAAoB,CAAC,CA6BvE;AAED,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAY/G"}
@@ -1,10 +1,11 @@
1
- import { chmodSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
1
+ import { readFileSync } from 'node:fs';
2
2
  import { spawn, spawnSync } from 'node:child_process';
3
- import { tmpdir } from 'node:os';
4
- import { join } from 'node:path';
5
- import { randomUUID } from 'node:crypto';
3
+ import { fileURLToPath } from 'node:url';
6
4
  const DEFAULT_PACKAGE_NAME = '@trendify/cli';
7
5
  const DEFAULT_PACKAGE_VERSION = '0.0.0';
6
+ const DEFAULT_NPM_DIST_TAG = 'latest';
7
+ const DEFAULT_NPM_REGISTRY_URL = 'https://registry.npmjs.org';
8
+ const REGISTRY_REQUEST_TIMEOUT_MS = 8_000;
8
9
  const VERSION_PATTERN = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/u;
9
10
  function getPackageManifestPath() {
10
11
  return new URL('../../../package.json', import.meta.url);
@@ -82,67 +83,54 @@ function compareVersions(left, right) {
82
83
  sensitivity: 'base',
83
84
  });
84
85
  }
85
- function runCommand(command, args) {
86
- return new Promise((resolve, reject) => {
87
- const child = spawn(command, [...args], {
88
- env: process.env,
89
- stdio: ['ignore', 'pipe', 'pipe'],
90
- });
91
- let stdout = '';
92
- let stderr = '';
93
- child.stdout.on('data', (chunk) => {
94
- stdout += chunk.toString();
95
- });
96
- child.stderr.on('data', (chunk) => {
97
- stderr += chunk.toString();
98
- });
99
- child.on('error', (error) => {
100
- reject(error);
101
- });
102
- child.on('close', (code) => {
103
- resolve({
104
- code: code ?? 1,
105
- stderr,
106
- stdout,
107
- });
108
- });
86
+ function wait(milliseconds) {
87
+ return new Promise((resolve) => {
88
+ setTimeout(resolve, milliseconds);
109
89
  });
110
90
  }
111
91
  async function fetchLatestPublishedVersion(packageName) {
112
- const commandResult = await runCommand(getNpmCommand(), [
113
- 'view',
114
- packageName,
115
- 'version',
116
- '--json',
117
- '--silent',
118
- '--prefer-online',
119
- ]);
120
- if (commandResult.code !== 0) {
121
- const message = commandResult.stderr.trim() || commandResult.stdout.trim() || 'Falha ao consultar o npm.';
122
- throw new Error(message);
123
- }
124
- const stdout = commandResult.stdout.trim();
125
- if (!stdout) {
126
- throw new Error('O npm nao retornou a versao publicada mais recente.');
127
- }
128
- try {
129
- const parsedOutput = JSON.parse(stdout);
130
- if (typeof parsedOutput === 'string' && parsedOutput.trim()) {
131
- return parsedOutput.trim();
92
+ const packageUrl = new URL(`${DEFAULT_NPM_REGISTRY_URL}/${encodeURIComponent(packageName)}`);
93
+ packageUrl.searchParams.set('ts', Date.now().toString());
94
+ let lastError = null;
95
+ for (let attempt = 0; attempt < 2; attempt += 1) {
96
+ const controller = new AbortController();
97
+ const timeout = setTimeout(() => {
98
+ controller.abort();
99
+ }, REGISTRY_REQUEST_TIMEOUT_MS);
100
+ try {
101
+ const response = await fetch(packageUrl, {
102
+ method: 'GET',
103
+ headers: {
104
+ accept: 'application/json',
105
+ 'cache-control': 'no-cache',
106
+ pragma: 'no-cache',
107
+ },
108
+ cache: 'no-store',
109
+ signal: controller.signal,
110
+ });
111
+ clearTimeout(timeout);
112
+ if (!response.ok) {
113
+ throw new Error(`Registry respondeu com status ${response.status}.`);
114
+ }
115
+ const packument = (await response.json());
116
+ const latestVersion = packument['dist-tags']?.[DEFAULT_NPM_DIST_TAG];
117
+ if (typeof latestVersion === 'string' && latestVersion.trim()) {
118
+ return latestVersion.trim();
119
+ }
120
+ throw new Error(`O dist-tag "${DEFAULT_NPM_DIST_TAG}" nao foi encontrado no registry.`);
132
121
  }
133
- }
134
- catch {
135
- if (stdout) {
136
- return stdout.replace(/^"+|"+$/gu, '').trim();
122
+ catch (error) {
123
+ clearTimeout(timeout);
124
+ lastError = error;
125
+ if (attempt < 1) {
126
+ await wait(750);
127
+ }
137
128
  }
138
129
  }
139
- throw new Error('Nao foi possivel interpretar a versao publicada retornada pelo npm.');
130
+ throw new Error(`Nao foi possivel consultar o dist-tag "${DEFAULT_NPM_DIST_TAG}" no registry do npm. ${toErrorMessage(lastError)}`);
140
131
  }
141
- function getUpdaterScriptPath() {
142
- return join(tmpdir(), `trendify-cli-updater-${randomUUID()}.sh`);
143
- }
144
- function shellEscape(value) {
145
- return `'${value.replace(/'/gu, `'\\''`)}'`;
132
+ function getBundledUpdaterScriptPath() {
133
+ return fileURLToPath(new URL('../../../scripts/self-update.sh', import.meta.url));
146
134
  }
147
135
  function resolveTerminalPath() {
148
136
  if (!process.stdin.isTTY && !process.stdout.isTTY) {
@@ -161,113 +149,25 @@ function resolveTerminalPath() {
161
149
  }
162
150
  return ttyPath;
163
151
  }
164
- function buildShellCommand(command, args) {
165
- return [shellEscape(command), ...args.map((arg) => shellEscape(arg))].join(' ');
166
- }
167
- function buildUpdaterScriptFileContents(params) {
168
- const updateCommand = buildShellCommand(params.npmCommand, [
169
- 'install',
170
- '--global',
171
- `${params.packageName}@${params.latestVersion}`,
172
- ]);
173
- const relaunchCommand = buildShellCommand(params.nodePath, [
174
- ...params.execArgs,
175
- params.entrypoint,
176
- ...params.cliArgs,
177
- ]);
178
- return `#!/bin/sh
179
- set -eu
180
-
181
- PARENT_PID=${params.parentPid}
182
- TTY_PATH=${params.ttyPath ? shellEscape(params.ttyPath) : "''"}
183
- SCRIPT_PATH=${shellEscape(params.scriptPath)}
184
-
185
- cleanup() {
186
- rm -f "$SCRIPT_PATH" >/dev/null 2>&1 || true
187
- }
188
-
189
- wait_for_parent_exit() {
190
- while kill -0 "$PARENT_PID" >/dev/null 2>&1; do
191
- sleep 0.1
192
- done
193
- }
194
-
195
- bind_terminal() {
196
- if [ -z "$TTY_PATH" ] || [ ! -e "$TTY_PATH" ]; then
197
- return 0
198
- fi
199
-
200
- exec <"$TTY_PATH" >"$TTY_PATH" 2>"$TTY_PATH"
201
- }
202
-
203
- reset_terminal() {
204
- if [ -z "$TTY_PATH" ] || [ ! -e "$TTY_PATH" ]; then
205
- return 0
206
- fi
207
-
208
- stty sane <"$TTY_PATH" >/dev/null 2>&1 || true
209
- printf '\\033c'
210
- printf '\\033[2J\\033[3J\\033[H'
211
- }
212
-
213
- wait_for_parent_exit
214
- sleep 0.4
215
- bind_terminal
216
- reset_terminal
217
-
218
- printf 'Atualizando o CLI de v%s para v%s.\\n' ${shellEscape(params.currentVersion)} ${shellEscape(params.latestVersion)}
219
- printf 'Pacote npm: %s\\n\\n' ${shellEscape(params.packageName)}
220
-
221
- if ! ${updateCommand}; then
222
- printf '\\nFalha ao atualizar automaticamente.\\n' >&2
223
- cleanup
224
- exit 1
225
- fi
226
-
227
- sleep 0.4
228
- reset_terminal
229
- printf 'CLI atualizada com sucesso para v%s.\\n\\n' ${shellEscape(params.latestVersion)}
230
- sleep 0.5
231
-
232
- cleanup
233
- exec ${relaunchCommand}
234
- `;
235
- }
236
152
  async function spawnDetachedUpdaterProcess(packageName, currentVersion, latestVersion) {
237
- const entrypoint = process.argv[1];
238
- if (!entrypoint) {
239
- throw new Error('Nao foi possivel identificar o entrypoint atual da CLI para reiniciar o processo.');
240
- }
241
- const scriptPath = getUpdaterScriptPath();
242
153
  const ttyPath = resolveTerminalPath();
243
- const scriptContents = buildUpdaterScriptFileContents({
244
- cliArgs: process.argv.slice(2),
245
- currentVersion,
246
- entrypoint,
247
- execArgs: process.execArgv,
248
- latestVersion,
249
- nodePath: process.execPath,
250
- npmCommand: getNpmCommand(),
251
- packageName,
252
- parentPid: process.pid,
253
- scriptPath,
254
- ttyPath,
255
- });
256
- writeFileSync(scriptPath, scriptContents, 'utf8');
257
- if (process.platform !== 'win32') {
258
- chmodSync(scriptPath, 0o700);
259
- }
154
+ const updaterScriptPath = getBundledUpdaterScriptPath();
260
155
  await new Promise((resolve, reject) => {
261
- const child = spawn('/bin/sh', [scriptPath], {
156
+ const child = spawn('/bin/sh', [
157
+ updaterScriptPath,
158
+ packageName,
159
+ currentVersion,
160
+ latestVersion,
161
+ String(process.pid),
162
+ ttyPath ?? '',
163
+ 'trendify',
164
+ ...process.argv.slice(2),
165
+ ], {
262
166
  detached: true,
263
167
  env: process.env,
264
168
  stdio: 'ignore',
265
169
  });
266
170
  child.on('error', (error) => {
267
- try {
268
- unlinkSync(scriptPath);
269
- }
270
- catch { }
271
171
  reject(error);
272
172
  });
273
173
  child.on('spawn', () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trendify/cli",
3
- "version": "0.1.23",
3
+ "version": "0.1.25",
4
4
  "description": "CLI do Trendify para descoberta de temas e fluxos de conta.",
5
5
  "type": "module",
6
6
  "main": "dist/cli.entry.js",
@@ -10,6 +10,7 @@
10
10
  },
11
11
  "files": [
12
12
  "dist",
13
+ "scripts/self-update.sh",
13
14
  ".env",
14
15
  "README.md",
15
16
  ".env.example"