@neetru/cli 1.0.1 → 2.0.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.
Files changed (135) hide show
  1. package/CHANGELOG.md +136 -0
  2. package/README.md +109 -152
  3. package/dist/commands/add.d.ts +8 -3
  4. package/dist/commands/add.js +70 -143
  5. package/dist/commands/add.js.map +1 -1
  6. package/dist/commands/ai.d.ts +4 -0
  7. package/dist/commands/ai.js +88 -0
  8. package/dist/commands/ai.js.map +1 -0
  9. package/dist/commands/autocomplete.d.ts +7 -0
  10. package/dist/commands/autocomplete.js +107 -0
  11. package/dist/commands/autocomplete.js.map +1 -0
  12. package/dist/commands/build.d.ts +18 -0
  13. package/dist/commands/build.js +288 -0
  14. package/dist/commands/build.js.map +1 -0
  15. package/dist/commands/config.d.ts +3 -0
  16. package/dist/commands/config.js +70 -0
  17. package/dist/commands/config.js.map +1 -0
  18. package/dist/commands/db.d.ts +14 -0
  19. package/dist/commands/db.js +187 -0
  20. package/dist/commands/db.js.map +1 -0
  21. package/dist/commands/deploy.d.ts +16 -3
  22. package/dist/commands/deploy.js +400 -180
  23. package/dist/commands/deploy.js.map +1 -1
  24. package/dist/commands/doctor.d.ts +27 -0
  25. package/dist/commands/doctor.js +211 -0
  26. package/dist/commands/doctor.js.map +1 -0
  27. package/dist/commands/env.d.ts +15 -0
  28. package/dist/commands/env.js +56 -0
  29. package/dist/commands/env.js.map +1 -0
  30. package/dist/commands/fn.d.ts +6 -0
  31. package/dist/commands/fn.js +87 -0
  32. package/dist/commands/fn.js.map +1 -0
  33. package/dist/commands/init.d.ts +10 -3
  34. package/dist/commands/init.js +212 -143
  35. package/dist/commands/init.js.map +1 -1
  36. package/dist/commands/login.d.ts +6 -3
  37. package/dist/commands/login.js +222 -92
  38. package/dist/commands/login.js.map +1 -1
  39. package/dist/commands/logout.d.ts +1 -0
  40. package/dist/commands/logout.js +28 -0
  41. package/dist/commands/logout.js.map +1 -0
  42. package/dist/commands/logs.d.ts +14 -3
  43. package/dist/commands/logs.js +132 -106
  44. package/dist/commands/logs.js.map +1 -1
  45. package/dist/commands/mocks.d.ts +5 -0
  46. package/dist/commands/mocks.js +23 -0
  47. package/dist/commands/mocks.js.map +1 -0
  48. package/dist/commands/open.d.ts +4 -3
  49. package/dist/commands/open.js +53 -85
  50. package/dist/commands/open.js.map +1 -1
  51. package/dist/commands/promote.d.ts +9 -0
  52. package/dist/commands/promote.js +114 -0
  53. package/dist/commands/promote.js.map +1 -0
  54. package/dist/commands/publish.d.ts +14 -0
  55. package/dist/commands/publish.js +180 -0
  56. package/dist/commands/publish.js.map +1 -0
  57. package/dist/commands/status.d.ts +5 -3
  58. package/dist/commands/status.js +91 -93
  59. package/dist/commands/status.js.map +1 -1
  60. package/dist/commands/upgrade.d.ts +12 -0
  61. package/dist/commands/upgrade.js +77 -0
  62. package/dist/commands/upgrade.js.map +1 -0
  63. package/dist/commands/validate.d.ts +1 -3
  64. package/dist/commands/validate.js +83 -91
  65. package/dist/commands/validate.js.map +1 -1
  66. package/dist/commands/whoami.d.ts +5 -3
  67. package/dist/commands/whoami.js +76 -28
  68. package/dist/commands/whoami.js.map +1 -1
  69. package/dist/index.d.ts +0 -1
  70. package/dist/index.js +337 -36
  71. package/dist/index.js.map +1 -1
  72. package/dist/lib/ai/context.d.ts +11 -0
  73. package/dist/lib/ai/context.js +112 -0
  74. package/dist/lib/ai/context.js.map +1 -0
  75. package/dist/lib/ai/orchestrator.d.ts +10 -0
  76. package/dist/lib/ai/orchestrator.js +92 -0
  77. package/dist/lib/ai/orchestrator.js.map +1 -0
  78. package/dist/lib/api-client.d.ts +21 -0
  79. package/dist/lib/api-client.js +65 -0
  80. package/dist/lib/api-client.js.map +1 -0
  81. package/dist/lib/auth.d.ts +15 -0
  82. package/dist/lib/auth.js +98 -0
  83. package/dist/lib/auth.js.map +1 -0
  84. package/dist/lib/config-schema.d.ts +165 -0
  85. package/dist/lib/config-schema.js +57 -0
  86. package/dist/lib/config-schema.js.map +1 -0
  87. package/dist/lib/config.d.ts +15 -0
  88. package/dist/lib/config.js +33 -0
  89. package/dist/lib/config.js.map +1 -0
  90. package/dist/utils/logger.d.ts +13 -0
  91. package/dist/utils/logger.js +27 -0
  92. package/dist/utils/logger.js.map +1 -0
  93. package/package.json +35 -33
  94. package/templates/auth/callback.ts +22 -0
  95. package/templates/auth/sign-in.tsx +41 -0
  96. package/templates/billing/checkout.ts +22 -0
  97. package/templates/billing/page.tsx +43 -0
  98. package/templates/support/ticket-form.tsx +68 -0
  99. package/templates/usage/track.ts +30 -0
  100. package/templates/users/profile.tsx +43 -0
  101. package/LICENSE +0 -21
  102. package/dist/commands/add.d.ts.map +0 -1
  103. package/dist/commands/deploy.d.ts.map +0 -1
  104. package/dist/commands/generate-types.d.ts +0 -3
  105. package/dist/commands/generate-types.d.ts.map +0 -1
  106. package/dist/commands/generate-types.js +0 -150
  107. package/dist/commands/generate-types.js.map +0 -1
  108. package/dist/commands/init.d.ts.map +0 -1
  109. package/dist/commands/login.d.ts.map +0 -1
  110. package/dist/commands/logs.d.ts.map +0 -1
  111. package/dist/commands/open.d.ts.map +0 -1
  112. package/dist/commands/status.d.ts.map +0 -1
  113. package/dist/commands/validate.d.ts.map +0 -1
  114. package/dist/commands/whoami.d.ts.map +0 -1
  115. package/dist/config.d.ts +0 -14
  116. package/dist/config.d.ts.map +0 -1
  117. package/dist/config.js +0 -83
  118. package/dist/config.js.map +0 -1
  119. package/dist/index.d.ts.map +0 -1
  120. package/dist/scaffold/auth.d.ts +0 -3
  121. package/dist/scaffold/auth.d.ts.map +0 -1
  122. package/dist/scaffold/auth.js +0 -228
  123. package/dist/scaffold/auth.js.map +0 -1
  124. package/dist/scaffold/billing.d.ts +0 -3
  125. package/dist/scaffold/billing.d.ts.map +0 -1
  126. package/dist/scaffold/billing.js +0 -184
  127. package/dist/scaffold/billing.js.map +0 -1
  128. package/dist/scaffold/usage.d.ts +0 -3
  129. package/dist/scaffold/usage.d.ts.map +0 -1
  130. package/dist/scaffold/usage.js +0 -173
  131. package/dist/scaffold/usage.js.map +0 -1
  132. package/dist/scaffold/users.d.ts +0 -3
  133. package/dist/scaffold/users.d.ts.map +0 -1
  134. package/dist/scaffold/users.js +0 -135
  135. package/dist/scaffold/users.js.map +0 -1
@@ -1,228 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.scaffoldAuth = scaffoldAuth;
37
- const fs = __importStar(require("fs-extra"));
38
- const path = __importStar(require("path"));
39
- async function scaffoldAuth(config, outDir) {
40
- const files = [
41
- {
42
- name: 'auth.ts',
43
- content: `/**
44
- * Neetru Auth — gerado por neetru add auth
45
- * Fluxo OAuth 2.0 / OIDC via Neetru Core
46
- */
47
-
48
- const NEETRU_CORE_URL = process.env.NEETRU_CORE_URL ?? '${config.coreUrl}';
49
- const CLIENT_ID = process.env.NEETRU_CLIENT_ID ?? '${config.clientId}';
50
- const CLIENT_SECRET = process.env.NEETRU_CLIENT_SECRET ?? '';
51
-
52
- export interface NeetruTokens {
53
- access_token: string;
54
- refresh_token: string;
55
- token_type: string;
56
- expires_in: number;
57
- scope: string;
58
- }
59
-
60
- export interface NeetruUser {
61
- uid: string;
62
- email: string;
63
- displayName?: string;
64
- photoURL?: string;
65
- tenantId?: string;
66
- }
67
-
68
- /**
69
- * Gera a URL de autorização OAuth para redirecionar o usuário ao Neetru Core.
70
- */
71
- export function getAuthorizationUrl(redirectUri: string, state?: string): string {
72
- const params = new URLSearchParams({
73
- client_id: CLIENT_ID,
74
- redirect_uri: redirectUri,
75
- response_type: 'code',
76
- scope: 'openid profile email',
77
- ...(state ? { state } : {}),
78
- });
79
- return \`\${NEETRU_CORE_URL}/api/oauth/authorize?\${params.toString()}\`;
80
- }
81
-
82
- /**
83
- * Troca o authorization code por tokens de acesso.
84
- * Chamar no callback route após o redirect do Neetru Core.
85
- */
86
- export async function exchangeCodeForTokens(
87
- code: string,
88
- redirectUri: string
89
- ): Promise<NeetruTokens> {
90
- const res = await fetch(\`\${NEETRU_CORE_URL}/api/oauth/token\`, {
91
- method: 'POST',
92
- headers: { 'Content-Type': 'application/json' },
93
- body: JSON.stringify({
94
- code,
95
- client_id: CLIENT_ID,
96
- client_secret: CLIENT_SECRET,
97
- redirect_uri: redirectUri,
98
- grant_type: 'authorization_code',
99
- }),
100
- });
101
-
102
- if (!res.ok) {
103
- const err = await res.text();
104
- throw new Error(\`Token exchange failed: \${res.status} — \${err}\`);
105
- }
106
-
107
- return res.json() as Promise<NeetruTokens>;
108
- }
109
-
110
- /**
111
- * Renova o access token usando o refresh token.
112
- */
113
- export async function refreshAccessToken(refreshToken: string): Promise<NeetruTokens> {
114
- const res = await fetch(\`\${NEETRU_CORE_URL}/api/oauth/token\`, {
115
- method: 'POST',
116
- headers: { 'Content-Type': 'application/json' },
117
- body: JSON.stringify({
118
- grant_type: 'refresh_token',
119
- refresh_token: refreshToken,
120
- client_id: CLIENT_ID,
121
- client_secret: CLIENT_SECRET,
122
- }),
123
- });
124
-
125
- if (!res.ok) {
126
- throw new Error(\`Token refresh failed: \${res.status}\`);
127
- }
128
-
129
- return res.json() as Promise<NeetruTokens>;
130
- }
131
-
132
- /**
133
- * Revoga um refresh token (logout).
134
- */
135
- export async function revokeToken(refreshToken: string): Promise<void> {
136
- await fetch(\`\${NEETRU_CORE_URL}/api/oauth/revoke\`, {
137
- method: 'POST',
138
- headers: { 'Content-Type': 'application/json' },
139
- body: JSON.stringify({ token: refreshToken, client_id: CLIENT_ID }),
140
- });
141
- }
142
-
143
- /**
144
- * Busca o perfil do usuário autenticado.
145
- */
146
- export async function getUserProfile(accessToken: string): Promise<NeetruUser> {
147
- const res = await fetch(\`\${NEETRU_CORE_URL}/api/userinfo\`, {
148
- headers: { Authorization: \`Bearer \${accessToken}\` },
149
- });
150
-
151
- if (!res.ok) {
152
- throw new Error(\`Failed to fetch user profile: \${res.status}\`);
153
- }
154
-
155
- return res.json() as Promise<NeetruUser>;
156
- }
157
- `,
158
- },
159
- {
160
- name: 'auth-middleware.ts',
161
- content: `/**
162
- * Neetru Auth Middleware — Next.js App Router
163
- * Protege rotas que requerem autenticação Neetru.
164
- */
165
-
166
- import { cookies } from 'next/headers';
167
- import { getUserProfile, refreshAccessToken, type NeetruUser } from './auth';
168
-
169
- export interface NeetruSession {
170
- user: NeetruUser;
171
- accessToken: string;
172
- }
173
-
174
- /**
175
- * Obtém a sessão Neetru do cookie httpOnly.
176
- * Retorna null se não autenticado ou sessão expirada.
177
- */
178
- export async function getNeetruSession(): Promise<NeetruSession | null> {
179
- const cookieStore = await cookies();
180
- const accessToken = cookieStore.get('neetru_access_token')?.value;
181
- const refreshToken = cookieStore.get('neetru_refresh_token')?.value;
182
-
183
- if (!accessToken && !refreshToken) return null;
184
-
185
- try {
186
- const user = await getUserProfile(accessToken ?? '');
187
- return { user, accessToken: accessToken ?? '' };
188
- } catch {
189
- // Try refreshing
190
- if (!refreshToken) return null;
191
-
192
- try {
193
- const tokens = await refreshAccessToken(refreshToken);
194
- const user = await getUserProfile(tokens.access_token);
195
- // Note: caller should update cookies with new tokens
196
- return { user, accessToken: tokens.access_token };
197
- } catch {
198
- return null;
199
- }
200
- }
201
- }
202
-
203
- /**
204
- * HOF para Server Actions — exige sessão Neetru válida.
205
- */
206
- export function requireNeetruSession<TInput, TOutput>(
207
- fn: (session: NeetruSession, input: TInput) => Promise<TOutput>
208
- ) {
209
- return async (input: TInput): Promise<TOutput> => {
210
- const session = await getNeetruSession();
211
- if (!session) {
212
- throw new Error('Não autenticado. Faça login com Neetru.');
213
- }
214
- return fn(session, input);
215
- };
216
- }
217
- `,
218
- },
219
- ];
220
- const created = [];
221
- for (const file of files) {
222
- const filePath = path.join(outDir, file.name);
223
- await fs.writeFile(filePath, file.content, 'utf-8');
224
- created.push(path.relative(process.cwd(), filePath));
225
- }
226
- return created;
227
- }
228
- //# sourceMappingURL=auth.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/scaffold/auth.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIA,oCA6LC;AAjMD,6CAA+B;AAC/B,2CAA6B;AAGtB,KAAK,UAAU,YAAY,CAAC,MAAoB,EAAE,MAAc;IACrE,MAAM,KAAK,GAA6C;QACtD;YACE,IAAI,EAAE,SAAS;YACf,OAAO,EAAE;;;;;0DAK2C,MAAM,CAAC,OAAO;qDACnB,MAAM,CAAC,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4GnE;SACI;QACD;YACE,IAAI,EAAE,oBAAoB;YAC1B,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwDd;SACI;KACF,CAAC;IAEF,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9C,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACpD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -1,3 +0,0 @@
1
- import type { NeetruConfig } from '../config';
2
- export declare function scaffoldBilling(config: NeetruConfig, outDir: string): Promise<string[]>;
3
- //# sourceMappingURL=billing.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"billing.d.ts","sourceRoot":"","sources":["../../src/scaffold/billing.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C,wBAAsB,eAAe,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAiJ7F"}
@@ -1,184 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.scaffoldBilling = scaffoldBilling;
37
- const fs = __importStar(require("fs-extra"));
38
- const path = __importStar(require("path"));
39
- async function scaffoldBilling(config, outDir) {
40
- const files = [
41
- {
42
- name: 'billing.ts',
43
- content: `/**
44
- * Neetru Billing — gerado por neetru add billing
45
- * Client para consulta de assinaturas, planos e entitlements.
46
- */
47
-
48
- const NEETRU_CORE_URL = process.env.NEETRU_CORE_URL ?? '${config.coreUrl}';
49
- const CLIENT_ID = process.env.NEETRU_CLIENT_ID ?? '${config.clientId}';
50
-
51
- export interface NeetruSubscription {
52
- id: string;
53
- status: 'active' | 'cancelled' | 'past_due' | 'trialing';
54
- planId: string;
55
- planName: string;
56
- priceMonthly: number;
57
- currentPeriodEnd: string;
58
- autoRenew: boolean;
59
- }
60
-
61
- export interface NeetruPlan {
62
- id: string;
63
- name: string;
64
- priceMonthly: number;
65
- features: string[];
66
- limits: Record<string, number>;
67
- }
68
-
69
- export interface NeetruEntitlement {
70
- featureKey: string;
71
- allowed: boolean;
72
- limit?: number;
73
- used?: number;
74
- }
75
-
76
- async function apiRequest<T>(
77
- endpoint: string,
78
- accessToken: string,
79
- options?: RequestInit
80
- ): Promise<T> {
81
- const res = await fetch(\`\${NEETRU_CORE_URL}\${endpoint}\`, {
82
- ...options,
83
- headers: {
84
- 'Authorization': \`Bearer \${accessToken}\`,
85
- 'X-Client-ID': CLIENT_ID,
86
- 'Content-Type': 'application/json',
87
- ...(options?.headers ?? {}),
88
- },
89
- });
90
-
91
- if (!res.ok) {
92
- const err = await res.text().catch(() => res.statusText);
93
- throw new Error(\`Neetru API error \${res.status}: \${err}\`);
94
- }
95
-
96
- return res.json() as Promise<T>;
97
- }
98
-
99
- export const neetruBilling = {
100
- /**
101
- * Retorna a assinatura ativa do usuário autenticado.
102
- * Retorna null se sem assinatura ativa.
103
- */
104
- async getSubscription(accessToken: string): Promise<NeetruSubscription | null> {
105
- try {
106
- return await apiRequest<NeetruSubscription>('/api/v1/billing/subscription', accessToken);
107
- } catch (e) {
108
- if ((e as Error).message.includes('404')) return null;
109
- throw e;
110
- }
111
- },
112
-
113
- /**
114
- * Lista todos os planos disponíveis (não requer autenticação).
115
- */
116
- async listPlans(): Promise<NeetruPlan[]> {
117
- const res = await fetch(\`\${NEETRU_CORE_URL}/api/v1/plans?clientId=\${CLIENT_ID}\`);
118
- if (!res.ok) throw new Error('Falha ao buscar planos');
119
- return res.json() as Promise<NeetruPlan[]>;
120
- },
121
-
122
- /**
123
- * Verifica se uma feature está disponível no plano do usuário.
124
- */
125
- async checkEntitlement(
126
- accessToken: string,
127
- featureKey: string
128
- ): Promise<NeetruEntitlement> {
129
- return apiRequest<NeetruEntitlement>(
130
- \`/api/v1/billing/entitlements/\${encodeURIComponent(featureKey)}\`,
131
- accessToken
132
- );
133
- },
134
-
135
- /**
136
- * Verifica múltiplos entitlements de uma vez.
137
- */
138
- async checkEntitlements(
139
- accessToken: string,
140
- featureKeys: string[]
141
- ): Promise<Record<string, NeetruEntitlement>> {
142
- const params = new URLSearchParams();
143
- featureKeys.forEach((k) => params.append('feature', k));
144
- return apiRequest<Record<string, NeetruEntitlement>>(
145
- \`/api/v1/billing/entitlements?\${params.toString()}\`,
146
- accessToken
147
- );
148
- },
149
-
150
- /**
151
- * Gera URL de checkout para upgrade de plano.
152
- */
153
- async getCheckoutUrl(accessToken: string, planId: string, returnUrl: string): Promise<string> {
154
- const result = await apiRequest<{ checkoutUrl: string }>(
155
- '/api/v1/billing/checkout',
156
- accessToken,
157
- {
158
- method: 'POST',
159
- body: JSON.stringify({ planId, returnUrl }),
160
- }
161
- );
162
- return result.checkoutUrl;
163
- },
164
-
165
- /**
166
- * Gera URL do portal de billing self-service (Minha Conta Neetru).
167
- */
168
- getPortalUrl(returnUrl: string): string {
169
- const params = new URLSearchParams({ clientId: CLIENT_ID, returnUrl });
170
- return \`\${NEETRU_CORE_URL}/minhaconta?\${params.toString()}\`;
171
- },
172
- };
173
- `,
174
- },
175
- ];
176
- const created = [];
177
- for (const file of files) {
178
- const filePath = path.join(outDir, file.name);
179
- await fs.writeFile(filePath, file.content, 'utf-8');
180
- created.push(path.relative(process.cwd(), filePath));
181
- }
182
- return created;
183
- }
184
- //# sourceMappingURL=billing.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"billing.js","sourceRoot":"","sources":["../../src/scaffold/billing.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIA,0CAiJC;AArJD,6CAA+B;AAC/B,2CAA6B;AAGtB,KAAK,UAAU,eAAe,CAAC,MAAoB,EAAE,MAAc;IACxE,MAAM,KAAK,GAA6C;QACtD;YACE,IAAI,EAAE,YAAY;YAClB,OAAO,EAAE;;;;;0DAK2C,MAAM,CAAC,OAAO;qDACnB,MAAM,CAAC,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4HnE;SACI;KACF,CAAC;IAEF,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9C,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACpD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -1,3 +0,0 @@
1
- import type { NeetruConfig } from '../config';
2
- export declare function scaffoldUsage(config: NeetruConfig, outDir: string): Promise<string[]>;
3
- //# sourceMappingURL=usage.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../src/scaffold/usage.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C,wBAAsB,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAsI3F"}
@@ -1,173 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.scaffoldUsage = scaffoldUsage;
37
- const fs = __importStar(require("fs-extra"));
38
- const path = __importStar(require("path"));
39
- async function scaffoldUsage(config, outDir) {
40
- const content = `/**
41
- * Neetru Usage Reporter — gerado por neetru add usage
42
- * Envia eventos de uso para metered billing via Neetru Core.
43
- * Eventos são acumulados em memória e enviados em batch a cada 60s.
44
- */
45
-
46
- const NEETRU_CORE_URL = process.env.NEETRU_CORE_URL ?? '${config.coreUrl}';
47
- const CLIENT_ID = process.env.NEETRU_CLIENT_ID ?? '${config.clientId}';
48
-
49
- export interface UsageEvent {
50
- eventType: string;
51
- quantity: number;
52
- tenantId?: string;
53
- metadata?: Record<string, string | number | boolean>;
54
- timestamp?: number;
55
- }
56
-
57
- export class NeetruUsageReporter {
58
- private queue: UsageEvent[] = [];
59
- private flushInterval: ReturnType<typeof setInterval> | null = null;
60
- private accessToken: string;
61
- private readonly batchSize: number;
62
- private readonly flushIntervalMs: number;
63
-
64
- constructor(options: {
65
- accessToken: string;
66
- batchSize?: number;
67
- flushIntervalMs?: number;
68
- }) {
69
- this.accessToken = options.accessToken;
70
- this.batchSize = options.batchSize ?? 50;
71
- this.flushIntervalMs = options.flushIntervalMs ?? 60_000;
72
- this.startAutoFlush();
73
- }
74
-
75
- /**
76
- * Registra um evento de uso.
77
- * Os eventos são enviados automaticamente em batch.
78
- */
79
- track(eventType: string, quantity: number = 1, metadata?: UsageEvent['metadata']): void {
80
- this.queue.push({
81
- eventType,
82
- quantity,
83
- metadata,
84
- timestamp: Date.now(),
85
- });
86
-
87
- if (this.queue.length >= this.batchSize) {
88
- this.flush().catch(console.error);
89
- }
90
- }
91
-
92
- /**
93
- * Envia todos os eventos pendentes imediatamente.
94
- */
95
- async flush(): Promise<void> {
96
- if (this.queue.length === 0) return;
97
-
98
- const batch = this.queue.splice(0, this.batchSize);
99
-
100
- try {
101
- const res = await fetch(\`\${NEETRU_CORE_URL}/api/v1/usage\`, {
102
- method: 'POST',
103
- headers: {
104
- 'Authorization': \`Bearer \${this.accessToken}\`,
105
- 'X-Client-ID': CLIENT_ID,
106
- 'Content-Type': 'application/json',
107
- },
108
- body: JSON.stringify({ events: batch }),
109
- });
110
-
111
- if (!res.ok) {
112
- // Put events back in queue to retry
113
- this.queue.unshift(...batch);
114
- console.error(\`[NeetruUsage] Flush failed: \${res.status}\`);
115
- }
116
- } catch (err) {
117
- // Network error — put events back
118
- this.queue.unshift(...batch);
119
- console.error('[NeetruUsage] Network error during flush:', err);
120
- }
121
- }
122
-
123
- /**
124
- * Atualiza o access token (ex: após refresh).
125
- */
126
- updateToken(newToken: string): void {
127
- this.accessToken = newToken;
128
- }
129
-
130
- /**
131
- * Para o auto-flush e envia eventos pendentes.
132
- * Chamar ao encerrar a aplicação (process.on('beforeExit')).
133
- */
134
- async destroy(): Promise<void> {
135
- if (this.flushInterval) {
136
- clearInterval(this.flushInterval);
137
- this.flushInterval = null;
138
- }
139
- await this.flush();
140
- }
141
-
142
- private startAutoFlush(): void {
143
- this.flushInterval = setInterval(() => {
144
- this.flush().catch(console.error);
145
- }, this.flushIntervalMs);
146
-
147
- // Don't block process exit
148
- if (this.flushInterval.unref) {
149
- this.flushInterval.unref();
150
- }
151
- }
152
- }
153
-
154
- // Singleton for convenience
155
- let _instance: NeetruUsageReporter | null = null;
156
-
157
- export function initUsageReporter(accessToken: string): NeetruUsageReporter {
158
- _instance = new NeetruUsageReporter({ accessToken });
159
- return _instance;
160
- }
161
-
162
- export function getUsageReporter(): NeetruUsageReporter {
163
- if (!_instance) {
164
- throw new Error('UsageReporter não inicializado. Chame initUsageReporter(accessToken) primeiro.');
165
- }
166
- return _instance;
167
- }
168
- `;
169
- const filePath = path.join(outDir, 'usage-reporter.ts');
170
- await fs.writeFile(filePath, content, 'utf-8');
171
- return [path.relative(process.cwd(), filePath)];
172
- }
173
- //# sourceMappingURL=usage.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"usage.js","sourceRoot":"","sources":["../../src/scaffold/usage.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIA,sCAsIC;AA1ID,6CAA+B;AAC/B,2CAA6B;AAGtB,KAAK,UAAU,aAAa,CAAC,MAAoB,EAAE,MAAc;IACtE,MAAM,OAAO,GAAG;;;;;;0DAMwC,MAAM,CAAC,OAAO;qDACnB,MAAM,CAAC,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyHnE,CAAC;IAEA,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IACxD,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC/C,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC;AAClD,CAAC"}
@@ -1,3 +0,0 @@
1
- import type { NeetruConfig } from '../config';
2
- export declare function scaffoldUsers(config: NeetruConfig, outDir: string): Promise<string[]>;
3
- //# sourceMappingURL=users.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../src/scaffold/users.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C,wBAAsB,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAgG3F"}