@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,494 @@
1
+ import { createClient, } from '@supabase/supabase-js';
2
+ import { TRENDIFY_AUTH_STORAGE_FILE } from '../../../shared/config/app-paths.config.js';
3
+ import { getCliEnvValidationResult } from '../../../shared/config/env.config.js';
4
+ import { FileStorage } from './auth-storage.service.js';
5
+ const AUTH_STORAGE_KEY = 'trendify.auth.token';
6
+ const ACTIVE_WORKSPACE_STORAGE_KEY = 'trendify.auth.active-workspace-id';
7
+ function toAuthErrorMessage(error, fallbackMessage) {
8
+ if (error && typeof error === 'object' && 'message' in error && typeof error.message === 'string') {
9
+ return error.message;
10
+ }
11
+ return fallbackMessage;
12
+ }
13
+ function isWorkspaceRole(value) {
14
+ return value === 'owner' || value === 'admin' || value === 'member';
15
+ }
16
+ function normalizeWorkspaceMembership(value) {
17
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
18
+ return null;
19
+ }
20
+ const candidate = value;
21
+ const id = typeof candidate.workspace_id === 'string' ? candidate.workspace_id.trim() : '';
22
+ const name = typeof candidate.workspace_name === 'string' ? candidate.workspace_name.trim() : '';
23
+ const slug = typeof candidate.workspace_slug === 'string' ? candidate.workspace_slug.trim() : '';
24
+ const role = candidate.role;
25
+ if (!id || !name || !slug || !isWorkspaceRole(role)) {
26
+ return null;
27
+ }
28
+ return {
29
+ id,
30
+ name,
31
+ role,
32
+ slug,
33
+ };
34
+ }
35
+ export class AuthService {
36
+ client;
37
+ storage;
38
+ env;
39
+ storageFilePath;
40
+ static create(env) {
41
+ const storage = new FileStorage(TRENDIFY_AUTH_STORAGE_FILE);
42
+ const client = createClient(env.supabaseUrl, env.supabasePublishableDefaultKey, {
43
+ auth: {
44
+ autoRefreshToken: true,
45
+ detectSessionInUrl: false,
46
+ persistSession: true,
47
+ storage,
48
+ storageKey: AUTH_STORAGE_KEY,
49
+ },
50
+ });
51
+ return new AuthService(client, storage, env, TRENDIFY_AUTH_STORAGE_FILE);
52
+ }
53
+ constructor(client, storage, env, storageFilePath) {
54
+ this.client = client;
55
+ this.storage = storage;
56
+ this.env = env;
57
+ this.storageFilePath = storageFilePath;
58
+ this.activeWorkspaceId = null;
59
+ }
60
+ activeWorkspaceId;
61
+ getSessionStorageFilePath() {
62
+ return this.storageFilePath;
63
+ }
64
+ onAuthStateChange(listener) {
65
+ return this.client.auth.onAuthStateChange((_event, session) => {
66
+ listener({
67
+ activeWorkspace: null,
68
+ requiresWorkspaceSelection: false,
69
+ session,
70
+ user: session?.user ?? null,
71
+ workspaces: [],
72
+ });
73
+ });
74
+ }
75
+ getActiveWorkspaceId() {
76
+ return this.activeWorkspaceId;
77
+ }
78
+ async getWorkspaceScopedClient() {
79
+ try {
80
+ const { data: { session }, error, } = await this.client.auth.getSession();
81
+ if (error) {
82
+ return {
83
+ data: null,
84
+ error: error.message,
85
+ errorCode: error.code ?? null,
86
+ };
87
+ }
88
+ if (!session?.access_token) {
89
+ return {
90
+ data: null,
91
+ error: 'Nao existe uma sessao ativa para criar um cliente com espaco de trabalho.',
92
+ errorCode: null,
93
+ };
94
+ }
95
+ const activeWorkspaceId = this.activeWorkspaceId ?? (await this.readStoredActiveWorkspaceId());
96
+ if (!activeWorkspaceId) {
97
+ return {
98
+ data: null,
99
+ error: 'Selecione um espaco de trabalho antes de consultar dados protegidos.',
100
+ errorCode: null,
101
+ };
102
+ }
103
+ const workspaceClient = createClient(this.env.supabaseUrl, this.env.supabasePublishableDefaultKey, {
104
+ auth: {
105
+ autoRefreshToken: false,
106
+ detectSessionInUrl: false,
107
+ persistSession: false,
108
+ },
109
+ global: {
110
+ headers: {
111
+ Authorization: `Bearer ${session.access_token}`,
112
+ 'x-tenant-id': activeWorkspaceId,
113
+ },
114
+ },
115
+ });
116
+ return {
117
+ data: workspaceClient,
118
+ error: null,
119
+ errorCode: null,
120
+ };
121
+ }
122
+ catch (error) {
123
+ return {
124
+ data: null,
125
+ error: toAuthErrorMessage(error, 'Nao foi possivel preparar o cliente do espaco de trabalho atual.'),
126
+ errorCode: null,
127
+ };
128
+ }
129
+ }
130
+ async restoreSession() {
131
+ try {
132
+ const { data: { session }, error: sessionError, } = await this.client.auth.getSession();
133
+ if (sessionError) {
134
+ return {
135
+ data: null,
136
+ error: sessionError.message,
137
+ errorCode: sessionError.code ?? null,
138
+ };
139
+ }
140
+ if (!session) {
141
+ return {
142
+ data: {
143
+ activeWorkspace: null,
144
+ requiresWorkspaceSelection: false,
145
+ session: null,
146
+ user: null,
147
+ workspaces: [],
148
+ },
149
+ error: null,
150
+ errorCode: null,
151
+ };
152
+ }
153
+ const { data: { user }, error: userError, } = await this.client.auth.getUser();
154
+ if (userError || !user) {
155
+ await this.client.auth.signOut({ scope: 'local' });
156
+ await this.clearStoredActiveWorkspaceId();
157
+ return {
158
+ data: {
159
+ activeWorkspace: null,
160
+ requiresWorkspaceSelection: false,
161
+ session: null,
162
+ user: null,
163
+ workspaces: [],
164
+ },
165
+ error: userError?.message ?? 'Sua sessao expirou. Faca login novamente.',
166
+ errorCode: userError?.code ?? null,
167
+ };
168
+ }
169
+ return await this.buildAuthenticatedSnapshot(session, user);
170
+ }
171
+ catch (error) {
172
+ return {
173
+ data: null,
174
+ error: toAuthErrorMessage(error, 'Nao foi possivel restaurar a sessao atual.'),
175
+ errorCode: null,
176
+ };
177
+ }
178
+ }
179
+ async signInWithPassword(email, password) {
180
+ try {
181
+ const { data, error } = await this.client.auth.signInWithPassword({
182
+ email,
183
+ password,
184
+ });
185
+ if (error) {
186
+ return {
187
+ data: null,
188
+ error: error.message,
189
+ errorCode: error.code ?? null,
190
+ };
191
+ }
192
+ if (!data.session || !data.user) {
193
+ return {
194
+ data: null,
195
+ error: 'O Supabase nao retornou uma sessao valida para este usuario.',
196
+ errorCode: null,
197
+ };
198
+ }
199
+ return await this.buildAuthenticatedSnapshot(data.session, data.user);
200
+ }
201
+ catch (error) {
202
+ return {
203
+ data: null,
204
+ error: toAuthErrorMessage(error, 'Nao foi possivel concluir o login agora.'),
205
+ errorCode: null,
206
+ };
207
+ }
208
+ }
209
+ async signOut() {
210
+ try {
211
+ const { error } = await this.client.auth.signOut({ scope: 'local' });
212
+ if (error) {
213
+ return {
214
+ data: null,
215
+ error: error.message,
216
+ errorCode: error.code ?? null,
217
+ };
218
+ }
219
+ await this.clearStoredActiveWorkspaceId();
220
+ return {
221
+ data: null,
222
+ error: null,
223
+ errorCode: null,
224
+ };
225
+ }
226
+ catch (error) {
227
+ return {
228
+ data: null,
229
+ error: toAuthErrorMessage(error, 'Nao foi possivel encerrar a sessao atual.'),
230
+ errorCode: null,
231
+ };
232
+ }
233
+ }
234
+ async selectWorkspace(workspaceId) {
235
+ const trimmedWorkspaceId = workspaceId.trim();
236
+ if (!trimmedWorkspaceId) {
237
+ return {
238
+ data: null,
239
+ error: 'Informe um espaco de trabalho valido para continuar.',
240
+ errorCode: null,
241
+ };
242
+ }
243
+ try {
244
+ const workspaceResult = await this.listMyWorkspaces();
245
+ if (workspaceResult.error || !workspaceResult.data) {
246
+ return {
247
+ data: null,
248
+ error: workspaceResult.error ?? 'Nao foi possivel carregar os espacos de trabalho disponiveis.',
249
+ errorCode: workspaceResult.errorCode,
250
+ };
251
+ }
252
+ const selectedWorkspace = workspaceResult.data.find((workspace) => workspace.id === trimmedWorkspaceId);
253
+ if (!selectedWorkspace) {
254
+ return {
255
+ data: null,
256
+ error: 'Esse espaco de trabalho nao esta disponivel para a sua conta.',
257
+ errorCode: null,
258
+ };
259
+ }
260
+ await this.storeActiveWorkspaceId(selectedWorkspace.id);
261
+ return {
262
+ data: selectedWorkspace,
263
+ error: null,
264
+ errorCode: null,
265
+ };
266
+ }
267
+ catch (error) {
268
+ return {
269
+ data: null,
270
+ error: toAuthErrorMessage(error, 'Nao foi possivel selecionar o espaco de trabalho agora.'),
271
+ errorCode: null,
272
+ };
273
+ }
274
+ }
275
+ async updateDisplayName(displayName) {
276
+ try {
277
+ const { data: { user: currentUser }, error: currentUserError, } = await this.client.auth.getUser();
278
+ if (currentUserError) {
279
+ return {
280
+ data: null,
281
+ error: currentUserError.message,
282
+ errorCode: currentUserError.code ?? null,
283
+ };
284
+ }
285
+ if (!currentUser) {
286
+ return {
287
+ data: null,
288
+ error: 'Nao existe um usuario autenticado para atualizar o profile.',
289
+ errorCode: null,
290
+ };
291
+ }
292
+ const currentMetadata = currentUser.user_metadata &&
293
+ typeof currentUser.user_metadata === 'object' &&
294
+ !Array.isArray(currentUser.user_metadata)
295
+ ? currentUser.user_metadata
296
+ : {};
297
+ const { data, error } = await this.client.auth.updateUser({
298
+ data: {
299
+ ...currentMetadata,
300
+ display_name: displayName,
301
+ },
302
+ });
303
+ if (error) {
304
+ return {
305
+ data: null,
306
+ error: error.message,
307
+ errorCode: error.code ?? null,
308
+ };
309
+ }
310
+ if (!data.user) {
311
+ return {
312
+ data: null,
313
+ error: 'O Supabase nao retornou o usuario atualizado.',
314
+ errorCode: null,
315
+ };
316
+ }
317
+ return {
318
+ data: data.user,
319
+ error: null,
320
+ errorCode: null,
321
+ };
322
+ }
323
+ catch (error) {
324
+ return {
325
+ data: null,
326
+ error: toAuthErrorMessage(error, 'Nao foi possivel atualizar o display name agora.'),
327
+ errorCode: null,
328
+ };
329
+ }
330
+ }
331
+ async sendPasswordReauthenticationCode() {
332
+ try {
333
+ const { error } = await this.client.auth.reauthenticate();
334
+ if (error) {
335
+ return {
336
+ data: null,
337
+ error: error.message,
338
+ errorCode: error.code ?? null,
339
+ };
340
+ }
341
+ return {
342
+ data: null,
343
+ error: null,
344
+ errorCode: null,
345
+ };
346
+ }
347
+ catch (error) {
348
+ return {
349
+ data: null,
350
+ error: toAuthErrorMessage(error, 'Nao foi possivel solicitar o codigo de verificacao.'),
351
+ errorCode: null,
352
+ };
353
+ }
354
+ }
355
+ async updatePassword(password, nonce) {
356
+ try {
357
+ const { data, error } = await this.client.auth.updateUser(nonce
358
+ ? {
359
+ nonce,
360
+ password,
361
+ }
362
+ : {
363
+ password,
364
+ });
365
+ if (error) {
366
+ return {
367
+ data: null,
368
+ error: error.message,
369
+ errorCode: error.code ?? null,
370
+ };
371
+ }
372
+ if (!data.user) {
373
+ return {
374
+ data: null,
375
+ error: 'O Supabase nao retornou o usuario atualizado apos trocar a senha.',
376
+ errorCode: null,
377
+ };
378
+ }
379
+ return {
380
+ data: data.user,
381
+ error: null,
382
+ errorCode: null,
383
+ };
384
+ }
385
+ catch (error) {
386
+ return {
387
+ data: null,
388
+ error: toAuthErrorMessage(error, 'Nao foi possivel atualizar a senha agora.'),
389
+ errorCode: null,
390
+ };
391
+ }
392
+ }
393
+ async buildAuthenticatedSnapshot(session, user) {
394
+ const workspaceResult = await this.listMyWorkspaces();
395
+ if (workspaceResult.error || !workspaceResult.data) {
396
+ return {
397
+ data: null,
398
+ error: workspaceResult.error ?? 'Nao foi possivel carregar os espacos de trabalho desta conta.',
399
+ errorCode: workspaceResult.errorCode,
400
+ };
401
+ }
402
+ if (workspaceResult.data.length === 0) {
403
+ await this.clearStoredActiveWorkspaceId();
404
+ return {
405
+ data: null,
406
+ error: 'Sua conta nao esta vinculada a nenhum espaco de trabalho. Fale com um administrador.',
407
+ errorCode: 'workspace_membership_missing',
408
+ };
409
+ }
410
+ const storedActiveWorkspaceId = await this.readStoredActiveWorkspaceId();
411
+ const storedWorkspace = storedActiveWorkspaceId
412
+ ? workspaceResult.data.find((workspace) => workspace.id === storedActiveWorkspaceId)
413
+ : null;
414
+ const singleWorkspace = workspaceResult.data.length === 1 ? workspaceResult.data[0] ?? null : null;
415
+ const activeWorkspace = storedWorkspace ?? singleWorkspace;
416
+ const requiresWorkspaceSelection = activeWorkspace === null;
417
+ if (activeWorkspace) {
418
+ await this.storeActiveWorkspaceId(activeWorkspace.id);
419
+ }
420
+ else {
421
+ await this.clearStoredActiveWorkspaceId();
422
+ }
423
+ return {
424
+ data: {
425
+ activeWorkspace,
426
+ requiresWorkspaceSelection,
427
+ session,
428
+ user,
429
+ workspaces: workspaceResult.data,
430
+ },
431
+ error: null,
432
+ errorCode: null,
433
+ };
434
+ }
435
+ async listMyWorkspaces() {
436
+ try {
437
+ const { data, error } = await this.client.rpc('list_my_workspaces');
438
+ if (error) {
439
+ return {
440
+ data: null,
441
+ error: error.message,
442
+ errorCode: error.code ?? null,
443
+ };
444
+ }
445
+ const workspaces = Array.isArray(data)
446
+ ? data
447
+ .map(normalizeWorkspaceMembership)
448
+ .filter((workspace) => workspace !== null)
449
+ : [];
450
+ return {
451
+ data: workspaces,
452
+ error: null,
453
+ errorCode: null,
454
+ };
455
+ }
456
+ catch (error) {
457
+ return {
458
+ data: null,
459
+ error: toAuthErrorMessage(error, 'Nao foi possivel consultar os espacos de trabalho desta conta.'),
460
+ errorCode: null,
461
+ };
462
+ }
463
+ }
464
+ async readStoredActiveWorkspaceId() {
465
+ const storedValue = await this.storage.getItem(ACTIVE_WORKSPACE_STORAGE_KEY);
466
+ const trimmedValue = storedValue?.trim() ?? '';
467
+ return trimmedValue ? trimmedValue : null;
468
+ }
469
+ async storeActiveWorkspaceId(workspaceId) {
470
+ this.activeWorkspaceId = workspaceId;
471
+ await this.storage.setItem(ACTIVE_WORKSPACE_STORAGE_KEY, workspaceId);
472
+ }
473
+ async clearStoredActiveWorkspaceId() {
474
+ this.activeWorkspaceId = null;
475
+ await this.storage.removeItem(ACTIVE_WORKSPACE_STORAGE_KEY);
476
+ }
477
+ }
478
+ let cachedAuthBootstrap = null;
479
+ export function getAuthBootstrapResult() {
480
+ if (cachedAuthBootstrap) {
481
+ return cachedAuthBootstrap;
482
+ }
483
+ const envValidation = getCliEnvValidationResult();
484
+ if (!envValidation.ok) {
485
+ cachedAuthBootstrap = envValidation;
486
+ return cachedAuthBootstrap;
487
+ }
488
+ cachedAuthBootstrap = {
489
+ ok: true,
490
+ env: envValidation.env,
491
+ authService: AuthService.create(envValidation.env),
492
+ };
493
+ return cachedAuthBootstrap;
494
+ }
@@ -0,0 +1,3 @@
1
+ import { type AuthUser } from '@supabase/supabase-js';
2
+ export declare function getUserDisplayName(user: Pick<AuthUser, 'user_metadata'> | null | undefined): string | null;
3
+ //# sourceMappingURL=auth-user.util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-user.util.d.ts","sourceRoot":"","sources":["../../../../src/modules/auth/utils/auth-user.util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAa1G"}
@@ -0,0 +1,10 @@
1
+ export function getUserDisplayName(user) {
2
+ const value = user && user.user_metadata && typeof user.user_metadata === 'object' && !Array.isArray(user.user_metadata)
3
+ ? user.user_metadata.display_name
4
+ : null;
5
+ if (typeof value !== 'string') {
6
+ return null;
7
+ }
8
+ const trimmedValue = value.trim();
9
+ return trimmedValue ? trimmedValue : null;
10
+ }
@@ -0,0 +1,7 @@
1
+ type DiscoveryStepHeaderProps = {
2
+ readonly subtitle: string;
3
+ readonly title: string;
4
+ };
5
+ export declare function DiscoveryStepHeader({ subtitle, title }: DiscoveryStepHeaderProps): import("react/jsx-runtime").JSX.Element;
6
+ export {};
7
+ //# sourceMappingURL=discovery-step-header.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery-step-header.component.d.ts","sourceRoot":"","sources":["../../../../src/modules/discovery/components/discovery-step-header.component.tsx"],"names":[],"mappings":"AAEA,KAAK,wBAAwB,GAAG;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,wBAAwB,2CAOhF"}
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from 'ink';
3
+ export function DiscoveryStepHeader({ subtitle, title }) {
4
+ return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { color: "yellow", children: title }), _jsx(Text, { dimColor: true, children: subtitle })] }));
5
+ }
@@ -0,0 +1,11 @@
1
+ type DiscoveryScope = 'amplo' | 'restrito';
2
+ type DiscoveryPageProps = {
3
+ readonly onCancel: () => void;
4
+ readonly onComplete: (result: {
5
+ scope: DiscoveryScope;
6
+ theme: string;
7
+ }) => void;
8
+ };
9
+ export declare function DiscoveryPage({ onCancel, onComplete }: DiscoveryPageProps): import("react/jsx-runtime").JSX.Element;
10
+ export {};
11
+ //# sourceMappingURL=discovery.page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.page.d.ts","sourceRoot":"","sources":["../../../../src/modules/discovery/pages/discovery.page.tsx"],"names":[],"mappings":"AAOA,KAAK,cAAc,GAAG,OAAO,GAAG,UAAU,CAAC;AAE3C,KAAK,kBAAkB,GAAG;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,cAAc,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CACjF,CAAC;AAeF,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,kBAAkB,2CAsEzE"}
@@ -0,0 +1,58 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { Box, Text, useInput } from 'ink';
4
+ import { ActionMenuPage } from '../../../shared/components/action-menu.component.js';
5
+ import { StepHeader } from '../../../shared/components/step-header.component.js';
6
+ import { TextField } from '../../../shared/components/text-field.component.js';
7
+ const SCOPE_OPTIONS = [
8
+ {
9
+ value: 'amplo',
10
+ label: 'Mais ampla',
11
+ description: 'Busca caminhos mais abrangentes em torno do tema informado.',
12
+ },
13
+ {
14
+ value: 'restrito',
15
+ label: 'Mais restrita',
16
+ description: 'Foca em recortes mais especificos e direcionados do tema.',
17
+ },
18
+ ];
19
+ export function DiscoveryPage({ onCancel, onComplete }) {
20
+ const [step, setStep] = useState('theme');
21
+ const [theme, setTheme] = useState('');
22
+ const [selectedIndex, setSelectedIndex] = useState(0);
23
+ useInput((input, key) => {
24
+ if (key.escape) {
25
+ onCancel();
26
+ return;
27
+ }
28
+ if (step !== 'scope') {
29
+ return;
30
+ }
31
+ if (key.upArrow) {
32
+ setSelectedIndex((current) => current === 0 ? SCOPE_OPTIONS.length - 1 : current - 1);
33
+ return;
34
+ }
35
+ if (key.downArrow) {
36
+ setSelectedIndex((current) => current === SCOPE_OPTIONS.length - 1 ? 0 : current + 1);
37
+ return;
38
+ }
39
+ if (key.return) {
40
+ const option = SCOPE_OPTIONS[selectedIndex];
41
+ if (option) {
42
+ onComplete({
43
+ scope: option.value,
44
+ theme: theme.trim(),
45
+ });
46
+ }
47
+ }
48
+ });
49
+ if (step === 'theme') {
50
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(StepHeader, { title: "Qual e o tema da descoberta?", subtitle: "Digite o tema e pressione Enter para continuar." }), _jsx(TextField, { placeholder: "Ex.: IA generativa", value: theme, onChange: setTheme, onSubmit: (value) => {
51
+ if (value.trim()) {
52
+ setTheme(value);
53
+ setStep('scope');
54
+ }
55
+ } }), _jsx(Text, { dimColor: true, children: "Esc volta para o menu inicial." })] }));
56
+ }
57
+ return (_jsx(ActionMenuPage, { title: "Como voce quer seguir com esse tema?", subtitle: `Tema selecionado: "${theme.trim()}". Escolha o tipo de exploracao.`, options: SCOPE_OPTIONS, selectedIndex: selectedIndex, hintText: "Use as setas para navegar. Enter confirma. Esc volta ao menu." }));
58
+ }
@@ -0,0 +1,12 @@
1
+ import { type AuthUser } from '@supabase/supabase-js';
2
+ import { type AuthService } from '../../auth/services/auth.service.js';
3
+ type NotificationTone = 'error' | 'info' | 'success';
4
+ type ProfilePageProps = {
5
+ readonly authService: AuthService;
6
+ readonly onBack: () => void;
7
+ readonly onNotificationChange: (notification: string | null, tone?: NotificationTone) => void;
8
+ readonly user: AuthUser;
9
+ };
10
+ export declare function ProfilePage({ authService, onBack, onNotificationChange, user }: ProfilePageProps): import("react/jsx-runtime").JSX.Element;
11
+ export {};
12
+ //# sourceMappingURL=profile.page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile.page.d.ts","sourceRoot":"","sources":["../../../../src/modules/profile/pages/profile.page.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGtD,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,qCAAqC,CAAC;AAOvE,KAAK,gBAAgB,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;AAKrD,KAAK,gBAAgB,GAAG;IACtB,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC;IAC5B,QAAQ,CAAC,oBAAoB,EAAE,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,CAAC,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC9F,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;CACzB,CAAC;AAwBF,wBAAgB,WAAW,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,oBAAoB,EAAE,IAAI,EAAE,EAAE,gBAAgB,2CAwQhG"}