@trendify/cli 0.1.7 → 0.1.9

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 (67) hide show
  1. package/README.md +26 -0
  2. package/dist/app.component.d.ts +14 -0
  3. package/dist/app.component.d.ts.map +1 -0
  4. package/dist/app.component.js +448 -0
  5. package/dist/cli.entry.d.ts +3 -0
  6. package/dist/cli.entry.d.ts.map +1 -0
  7. package/dist/cli.entry.js +75 -0
  8. package/dist/modules/auth/pages/login.page.d.ts +12 -0
  9. package/dist/modules/auth/pages/login.page.d.ts.map +1 -0
  10. package/dist/modules/auth/pages/login.page.js +22 -0
  11. package/dist/modules/auth/pages/profile.page.d.ts +12 -0
  12. package/dist/modules/auth/pages/profile.page.d.ts.map +1 -0
  13. package/dist/modules/auth/pages/profile.page.js +180 -0
  14. package/dist/modules/auth/services/auth-storage.service.d.ts +11 -0
  15. package/dist/modules/auth/services/auth-storage.service.d.ts.map +1 -0
  16. package/dist/modules/auth/services/auth-storage.service.js +65 -0
  17. package/dist/modules/auth/services/auth.service.d.ts +60 -0
  18. package/dist/modules/auth/services/auth.service.d.ts.map +1 -0
  19. package/dist/modules/auth/services/auth.service.js +494 -0
  20. package/dist/modules/auth/utils/auth-user.util.d.ts +3 -0
  21. package/dist/modules/auth/utils/auth-user.util.d.ts.map +1 -0
  22. package/dist/modules/auth/utils/auth-user.util.js +10 -0
  23. package/dist/modules/discovery/components/discovery-step-header.component.d.ts +7 -0
  24. package/dist/modules/discovery/components/discovery-step-header.component.d.ts.map +1 -0
  25. package/dist/modules/discovery/components/discovery-step-header.component.js +5 -0
  26. package/dist/modules/discovery/pages/discovery.page.d.ts +11 -0
  27. package/dist/modules/discovery/pages/discovery.page.d.ts.map +1 -0
  28. package/dist/modules/discovery/pages/discovery.page.js +58 -0
  29. package/dist/modules/profile/pages/profile.page.d.ts +12 -0
  30. package/dist/modules/profile/pages/profile.page.d.ts.map +1 -0
  31. package/dist/modules/profile/pages/profile.page.js +180 -0
  32. package/dist/shared/components/action-menu.component.d.ts +13 -0
  33. package/dist/shared/components/action-menu.component.d.ts.map +1 -0
  34. package/dist/shared/components/action-menu.component.js +7 -0
  35. package/dist/shared/components/app-logo.component.d.ts +2 -0
  36. package/dist/shared/components/app-logo.component.d.ts.map +1 -0
  37. package/dist/shared/components/app-logo.component.js +13 -0
  38. package/dist/shared/components/app-menu.component.d.ts +17 -0
  39. package/dist/shared/components/app-menu.component.d.ts.map +1 -0
  40. package/dist/shared/components/app-menu.component.js +85 -0
  41. package/dist/shared/components/app-shell.component.d.ts +12 -0
  42. package/dist/shared/components/app-shell.component.d.ts.map +1 -0
  43. package/dist/shared/components/app-shell.component.js +15 -0
  44. package/dist/shared/components/radio-select.component.d.ts +12 -0
  45. package/dist/shared/components/radio-select.component.d.ts.map +1 -0
  46. package/dist/shared/components/radio-select.component.js +16 -0
  47. package/dist/shared/components/step-header.component.d.ts +7 -0
  48. package/dist/shared/components/step-header.component.d.ts.map +1 -0
  49. package/dist/shared/components/step-header.component.js +5 -0
  50. package/dist/shared/components/text-field.component.d.ts +12 -0
  51. package/dist/shared/components/text-field.component.d.ts.map +1 -0
  52. package/dist/shared/components/text-field.component.js +6 -0
  53. package/dist/shared/config/app-paths.config.d.ts +4 -0
  54. package/dist/shared/config/app-paths.config.d.ts.map +1 -0
  55. package/dist/shared/config/app-paths.config.js +5 -0
  56. package/dist/shared/config/env.config.d.ts +14 -0
  57. package/dist/shared/config/env.config.d.ts.map +1 -0
  58. package/dist/shared/config/env.config.js +58 -0
  59. package/dist/shared/constants/app-version.constant.d.ts +2 -0
  60. package/dist/shared/constants/app-version.constant.d.ts.map +1 -0
  61. package/dist/shared/constants/app-version.constant.js +1 -0
  62. package/dist/shared/services/cli-update.service.d.ts +29 -0
  63. package/dist/shared/services/cli-update.service.d.ts.map +1 -0
  64. package/dist/shared/services/cli-update.service.js +266 -0
  65. package/dist/version.d.ts +1 -1
  66. package/dist/version.js +1 -1
  67. package/package.json +4 -4
@@ -0,0 +1,180 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { Box, Text, useInput } from 'ink';
3
+ import { useEffect, useState } from 'react';
4
+ import { getUserDisplayName } from '../utils/auth-user.util.js';
5
+ import { ActionMenuPage } from '../../../shared/components/action-menu.component.js';
6
+ import { StepHeader } from '../../../shared/components/step-header.component.js';
7
+ import { TextField } from '../../../shared/components/text-field.component.js';
8
+ const PROFILE_ACTIONS = [
9
+ {
10
+ value: 'change-display-name',
11
+ label: 'Alterar display name',
12
+ description: 'Atualiza o nome exibido diretamente no Supabase.',
13
+ },
14
+ {
15
+ value: 'change-password',
16
+ label: 'Alterar senha',
17
+ description: 'Troca a senha da conta autenticada.',
18
+ },
19
+ {
20
+ value: 'back',
21
+ label: 'Voltar ao menu',
22
+ description: 'Retorna ao menu principal da CLI.',
23
+ },
24
+ ];
25
+ function isReauthenticationRequired(errorCode) {
26
+ return errorCode === 'reauthentication_needed' || errorCode === 'reauth_nonce_missing';
27
+ }
28
+ export function ProfilePage({ authService, onBack, onNotificationChange, user }) {
29
+ const currentDisplayName = getUserDisplayName(user);
30
+ const [step, setStep] = useState('menu');
31
+ const [selectedActionIndex, setSelectedActionIndex] = useState(0);
32
+ const [displayName, setDisplayName] = useState(currentDisplayName ?? '');
33
+ const [newPassword, setNewPassword] = useState('');
34
+ const [confirmPassword, setConfirmPassword] = useState('');
35
+ const [passwordFocus, setPasswordFocus] = useState('new-password');
36
+ const [nonce, setNonce] = useState('');
37
+ const [pendingPassword, setPendingPassword] = useState('');
38
+ const [busy, setBusy] = useState(false);
39
+ useEffect(() => {
40
+ setDisplayName(currentDisplayName ?? '');
41
+ }, [currentDisplayName]);
42
+ function resetPasswordFlow() {
43
+ setNewPassword('');
44
+ setConfirmPassword('');
45
+ setNonce('');
46
+ setPendingPassword('');
47
+ setPasswordFocus('new-password');
48
+ }
49
+ function returnToProfileMenu() {
50
+ setStep('menu');
51
+ setSelectedActionIndex(0);
52
+ resetPasswordFlow();
53
+ setDisplayName(currentDisplayName ?? '');
54
+ }
55
+ async function handleDisplayNameSubmit() {
56
+ const trimmedDisplayName = displayName.trim();
57
+ if (!trimmedDisplayName) {
58
+ onNotificationChange('Informe um display name valido para continuar.', 'error');
59
+ return;
60
+ }
61
+ if (trimmedDisplayName === currentDisplayName) {
62
+ onNotificationChange('O display name informado ja esta em uso na sua conta.', 'info');
63
+ returnToProfileMenu();
64
+ return;
65
+ }
66
+ setBusy(true);
67
+ const result = await authService.updateDisplayName(trimmedDisplayName);
68
+ setBusy(false);
69
+ if (result.error) {
70
+ onNotificationChange(result.error, 'error');
71
+ return;
72
+ }
73
+ onNotificationChange(`Display name atualizado para "${trimmedDisplayName}".`, 'success');
74
+ returnToProfileMenu();
75
+ }
76
+ async function requestPasswordReauthentication(password) {
77
+ const reauthenticationResult = await authService.sendPasswordReauthenticationCode();
78
+ if (reauthenticationResult.error) {
79
+ onNotificationChange(reauthenticationResult.error, 'error');
80
+ return;
81
+ }
82
+ setPendingPassword(password);
83
+ setNonce('');
84
+ setStep('confirm-password-code');
85
+ onNotificationChange('O Supabase enviou um codigo de verificacao. Digite esse codigo para concluir a troca de senha.', 'info');
86
+ }
87
+ async function handlePasswordSubmit(password, currentNonce) {
88
+ if (!password.trim()) {
89
+ onNotificationChange('Informe a nova senha para continuar.', 'error');
90
+ return;
91
+ }
92
+ setBusy(true);
93
+ const result = await authService.updatePassword(password, currentNonce);
94
+ setBusy(false);
95
+ if (result.error) {
96
+ if (isReauthenticationRequired(result.errorCode) && !currentNonce) {
97
+ await requestPasswordReauthentication(password);
98
+ return;
99
+ }
100
+ onNotificationChange(result.error, 'error');
101
+ return;
102
+ }
103
+ onNotificationChange('Senha atualizada com sucesso.', 'success');
104
+ returnToProfileMenu();
105
+ }
106
+ async function handleNewPasswordSubmit() {
107
+ if (!newPassword.trim() || !confirmPassword.trim()) {
108
+ onNotificationChange('Preencha a nova senha e a confirmacao.', 'error');
109
+ return;
110
+ }
111
+ if (newPassword !== confirmPassword) {
112
+ onNotificationChange('A confirmacao de senha nao confere.', 'error');
113
+ return;
114
+ }
115
+ await handlePasswordSubmit(newPassword);
116
+ }
117
+ async function handlePasswordNonceSubmit() {
118
+ const trimmedNonce = nonce.trim();
119
+ if (!trimmedNonce) {
120
+ onNotificationChange('Informe o codigo de verificacao enviado pelo Supabase.', 'error');
121
+ return;
122
+ }
123
+ await handlePasswordSubmit(pendingPassword, trimmedNonce);
124
+ }
125
+ useInput((_input, key) => {
126
+ if (busy) {
127
+ return;
128
+ }
129
+ if (step === 'menu') {
130
+ if (key.escape) {
131
+ onBack();
132
+ return;
133
+ }
134
+ if (key.upArrow) {
135
+ setSelectedActionIndex((current) => (current === 0 ? PROFILE_ACTIONS.length - 1 : current - 1));
136
+ return;
137
+ }
138
+ if (key.downArrow) {
139
+ setSelectedActionIndex((current) => (current === PROFILE_ACTIONS.length - 1 ? 0 : current + 1));
140
+ return;
141
+ }
142
+ if (key.return) {
143
+ const action = PROFILE_ACTIONS[selectedActionIndex];
144
+ if (!action || action.value === 'back') {
145
+ onBack();
146
+ return;
147
+ }
148
+ onNotificationChange(null);
149
+ setStep(action.value);
150
+ }
151
+ return;
152
+ }
153
+ if (key.escape) {
154
+ onNotificationChange(null);
155
+ returnToProfileMenu();
156
+ return;
157
+ }
158
+ if (step === 'change-password' && (key.tab || key.upArrow || key.downArrow)) {
159
+ setPasswordFocus((current) => (current === 'new-password' ? 'confirm-password' : 'new-password'));
160
+ }
161
+ });
162
+ if (step === 'menu') {
163
+ return (_jsxs(ActionMenuPage, { title: "Profile", subtitle: "Escolha uma acao para gerenciar sua conta autenticada.", options: PROFILE_ACTIONS, selectedIndex: selectedActionIndex, hintText: "Use as setas para navegar. Enter confirma. Esc volta ao menu.", children: [_jsxs(Text, { children: ["Email: ", user.email ?? 'nao informado'] }), _jsxs(Text, { children: ["Display name: ", currentDisplayName ?? 'nao definido'] })] }));
164
+ }
165
+ if (step === 'change-display-name') {
166
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(StepHeader, { title: "Alterar display name", subtitle: `Atual: ${currentDisplayName ?? 'nao definido'}. Digite o novo nome e pressione Enter.` }), _jsx(TextField, { placeholder: "Ex.: Leonardo", value: displayName, onChange: setDisplayName, onSubmit: () => {
167
+ void handleDisplayNameSubmit();
168
+ } }), _jsx(Text, { dimColor: true, children: "Esc volta para o menu de profile." })] }));
169
+ }
170
+ if (step === 'confirm-password-code') {
171
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(StepHeader, { title: "Confirmar troca de senha", subtitle: "Digite o codigo recebido por email ou telefone para concluir a troca da senha." }), _jsx(TextField, { placeholder: "Codigo de verificacao", value: nonce, onChange: setNonce, onSubmit: () => {
172
+ void handlePasswordNonceSubmit();
173
+ } }), _jsx(Text, { dimColor: true, children: "Esc volta para o menu de profile." })] }));
174
+ }
175
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(StepHeader, { title: "Alterar senha", subtitle: "Defina a nova senha. Se o Supabase pedir reautenticacao, um codigo sera enviado automaticamente." }), _jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { color: passwordFocus === 'new-password' ? 'greenBright' : 'white', children: "Nova senha" }), _jsx(TextField, { focus: passwordFocus === 'new-password', mask: "*", placeholder: "Digite a nova senha", value: newPassword, onChange: setNewPassword, onSubmit: () => {
176
+ setPasswordFocus('confirm-password');
177
+ } })] }), _jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: passwordFocus === 'confirm-password' ? 'greenBright' : 'white', children: "Confirmar senha" }), _jsx(TextField, { focus: passwordFocus === 'confirm-password', mask: "*", placeholder: "Repita a nova senha", value: confirmPassword, onChange: setConfirmPassword, onSubmit: () => {
178
+ void handleNewPasswordSubmit();
179
+ } })] }), _jsx(Text, { dimColor: true, children: "Tab ou setas alternam o campo ativo. Enter envia. Esc volta ao menu de profile." })] }));
180
+ }
@@ -0,0 +1,11 @@
1
+ import { type SupportedStorage } from '@supabase/supabase-js';
2
+ export declare class FileStorage implements SupportedStorage {
3
+ private readonly filePath;
4
+ private queue;
5
+ constructor(filePath: string);
6
+ getItem(key: string): Promise<string | null>;
7
+ removeItem(key: string): Promise<void>;
8
+ setItem(key: string, value: string): Promise<void>;
9
+ private runExclusive;
10
+ }
11
+ //# sourceMappingURL=auth-storage.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-storage.service.d.ts","sourceRoot":"","sources":["../../../../src/modules/auth/services/auth-storage.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AA0C9D,qBAAa,WAAY,YAAW,gBAAgB;IAG/B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAF5C,OAAO,CAAC,KAAK,CAAuC;gBAEhB,QAAQ,EAAE,MAAM;IAEvC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAQ5C,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAatC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS/D,OAAO,CAAC,YAAY;CAUrB"}
@@ -0,0 +1,65 @@
1
+ import { chmod, mkdir, readFile, rename, writeFile } from 'node:fs/promises';
2
+ import { dirname } from 'node:path';
3
+ async function ensureParentDirectory(filePath) {
4
+ await mkdir(dirname(filePath), { recursive: true });
5
+ }
6
+ async function readStorageMap(filePath) {
7
+ try {
8
+ const fileContents = await readFile(filePath, 'utf8');
9
+ const parsedContents = JSON.parse(fileContents);
10
+ if (!parsedContents || typeof parsedContents !== 'object' || Array.isArray(parsedContents)) {
11
+ return {};
12
+ }
13
+ return Object.fromEntries(Object.entries(parsedContents).filter((entry) => typeof entry[1] === 'string'));
14
+ }
15
+ catch (error) {
16
+ if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
17
+ return {};
18
+ }
19
+ return {};
20
+ }
21
+ }
22
+ async function writeStorageMap(filePath, data) {
23
+ await ensureParentDirectory(filePath);
24
+ const tempFilePath = `${filePath}.tmp`;
25
+ await writeFile(tempFilePath, JSON.stringify(data, null, 2), 'utf8');
26
+ await rename(tempFilePath, filePath);
27
+ if (process.platform !== 'win32') {
28
+ await chmod(filePath, 0o600).catch(() => undefined);
29
+ }
30
+ }
31
+ export class FileStorage {
32
+ filePath;
33
+ queue = Promise.resolve();
34
+ constructor(filePath) {
35
+ this.filePath = filePath;
36
+ }
37
+ async getItem(key) {
38
+ return this.runExclusive(async () => {
39
+ const data = await readStorageMap(this.filePath);
40
+ return data[key] ?? null;
41
+ });
42
+ }
43
+ async removeItem(key) {
44
+ await this.runExclusive(async () => {
45
+ const data = await readStorageMap(this.filePath);
46
+ if (!(key in data)) {
47
+ return;
48
+ }
49
+ delete data[key];
50
+ await writeStorageMap(this.filePath, data);
51
+ });
52
+ }
53
+ async setItem(key, value) {
54
+ await this.runExclusive(async () => {
55
+ const data = await readStorageMap(this.filePath);
56
+ data[key] = value;
57
+ await writeStorageMap(this.filePath, data);
58
+ });
59
+ }
60
+ runExclusive(operation) {
61
+ const nextOperation = this.queue.then(operation, operation);
62
+ this.queue = nextOperation.then(() => undefined, () => undefined);
63
+ return nextOperation;
64
+ }
65
+ }
@@ -0,0 +1,60 @@
1
+ import { type AuthSession, type AuthUser, type SupabaseClient } from '@supabase/supabase-js';
2
+ import { type CliEnv } from '../../../shared/config/env.config.js';
3
+ export type WorkspaceRole = 'admin' | 'member' | 'owner';
4
+ export type WorkspaceMembership = {
5
+ readonly id: string;
6
+ readonly name: string;
7
+ readonly role: WorkspaceRole;
8
+ readonly slug: string;
9
+ };
10
+ export type AuthSnapshot = {
11
+ readonly activeWorkspace: WorkspaceMembership | null;
12
+ readonly requiresWorkspaceSelection: boolean;
13
+ readonly session: AuthSession | null;
14
+ readonly user: AuthUser | null;
15
+ readonly workspaces: readonly WorkspaceMembership[];
16
+ };
17
+ export type AuthActionResult<TData> = {
18
+ readonly data: TData | null;
19
+ readonly error: string | null;
20
+ readonly errorCode: string | null;
21
+ };
22
+ export type AuthBootstrapResult = {
23
+ readonly authService: AuthService;
24
+ readonly env: CliEnv;
25
+ readonly ok: true;
26
+ } | {
27
+ readonly error: string;
28
+ readonly ok: false;
29
+ };
30
+ export declare class AuthService {
31
+ private readonly client;
32
+ private readonly storage;
33
+ private readonly env;
34
+ private readonly storageFilePath;
35
+ static create(env: CliEnv): AuthService;
36
+ private constructor();
37
+ private activeWorkspaceId;
38
+ getSessionStorageFilePath(): string;
39
+ onAuthStateChange(listener: (snapshot: AuthSnapshot) => void): {
40
+ data: {
41
+ subscription: import("@supabase/supabase-js").Subscription;
42
+ };
43
+ };
44
+ getActiveWorkspaceId(): string | null;
45
+ getWorkspaceScopedClient(): Promise<AuthActionResult<SupabaseClient>>;
46
+ restoreSession(): Promise<AuthActionResult<AuthSnapshot>>;
47
+ signInWithPassword(email: string, password: string): Promise<AuthActionResult<AuthSnapshot>>;
48
+ signOut(): Promise<AuthActionResult<null>>;
49
+ selectWorkspace(workspaceId: string): Promise<AuthActionResult<WorkspaceMembership>>;
50
+ updateDisplayName(displayName: string): Promise<AuthActionResult<AuthUser>>;
51
+ sendPasswordReauthenticationCode(): Promise<AuthActionResult<null>>;
52
+ updatePassword(password: string, nonce?: string): Promise<AuthActionResult<AuthUser>>;
53
+ private buildAuthenticatedSnapshot;
54
+ private listMyWorkspaces;
55
+ private readStoredActiveWorkspaceId;
56
+ private storeActiveWorkspaceId;
57
+ private clearStoredActiveWorkspaceId;
58
+ }
59
+ export declare function getAuthBootstrapResult(): AuthBootstrapResult;
60
+ //# sourceMappingURL=auth.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.service.d.ts","sourceRoot":"","sources":["../../../../src/modules/auth/services/auth.service.ts"],"names":[],"mappings":"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"}