@neetru/cli 2.24.1 → 2.26.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/commands/ai.js +8 -8
- package/dist/commands/bootstrap.js +18 -1
- package/dist/commands/bootstrap.js.map +1 -1
- package/dist/commands/build.js +12 -17
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/dev-up.d.ts +10 -26
- package/dist/commands/dev-up.js +78 -140
- package/dist/commands/dev-up.js.map +1 -1
- package/dist/commands/doctor.js +10 -4
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.js +147 -147
- package/dist/commands/logs.d.ts +29 -0
- package/dist/commands/logs.js +161 -0
- package/dist/commands/logs.js.map +1 -1
- package/dist/commands/webhooks.d.ts +34 -0
- package/dist/commands/webhooks.js +162 -0
- package/dist/commands/webhooks.js.map +1 -0
- package/dist/index.js +109 -27
- package/dist/index.js.map +1 -1
- package/dist/lib/ai/context.js +91 -91
- package/dist/lib/compose-generator.d.ts +36 -0
- package/dist/lib/compose-generator.js +152 -0
- package/dist/lib/compose-generator.js.map +1 -0
- package/dist/lib/config-schema.d.ts +18 -0
- package/dist/lib/config-schema.js +4 -0
- package/dist/lib/config-schema.js.map +1 -1
- package/dist/utils/safe-exit.d.ts +23 -0
- package/dist/utils/safe-exit.js +53 -1
- package/dist/utils/safe-exit.js.map +1 -1
- package/package.json +1 -1
- package/templates/auth/callback.ts +22 -22
- package/templates/auth/sign-in.tsx +41 -41
- package/templates/billing/checkout.ts +38 -22
- package/templates/billing/page.tsx +84 -43
- package/templates/billing/webhooks.ts +83 -0
- package/templates/dev/Dockerfile.agent +39 -0
- package/templates/dev/agent-entrypoint.sh +41 -0
- package/templates/dev/docker-compose.dev.yml +63 -0
- package/templates/support/ticket-form.tsx +68 -68
- package/templates/usage/track.ts +30 -30
- package/templates/users/profile.tsx +43 -43
- package/dist/commands/fn.d.ts +0 -6
- package/dist/commands/fn.js +0 -88
- package/dist/commands/fn.js.map +0 -1
- package/dist/commands/marketplace.d.ts +0 -36
- package/dist/commands/marketplace.js +0 -585
- package/dist/commands/marketplace.js.map +0 -1
- package/dist/lib/code-agent-neetru-tools.d.ts +0 -15
- package/dist/lib/code-agent-neetru-tools.js +0 -571
- package/dist/lib/code-agent-neetru-tools.js.map +0 -1
- package/dist/lib/code-agent-report.d.ts +0 -22
- package/dist/lib/code-agent-report.js +0 -43
- package/dist/lib/code-agent-report.js.map +0 -1
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface ComposeDbConfig {
|
|
2
|
+
engine: string;
|
|
3
|
+
image: string;
|
|
4
|
+
env: Record<string, string>;
|
|
5
|
+
port: number;
|
|
6
|
+
internalPort: number;
|
|
7
|
+
dataDir: string;
|
|
8
|
+
healthcheck: {
|
|
9
|
+
test: string[];
|
|
10
|
+
interval: string;
|
|
11
|
+
timeout: string;
|
|
12
|
+
retries: number;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Mapeia engine de banco → config Docker Compose.
|
|
17
|
+
* Usa imagens oficiais — mesmas engines que rodam em produção na VM.
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolveDbConfig(engine: string): ComposeDbConfig | null;
|
|
20
|
+
export interface ComposeGeneratorInput {
|
|
21
|
+
productSlug: string;
|
|
22
|
+
dbEngine: string;
|
|
23
|
+
appPort?: number;
|
|
24
|
+
coreUrl?: string;
|
|
25
|
+
firebaseProject?: string;
|
|
26
|
+
firebaseApiKey?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Gera o conteúdo do docker-compose.dev.yml baseado na config do produto.
|
|
30
|
+
* Template em templates/dev/docker-compose.dev.yml com substituições {{VAR}}.
|
|
31
|
+
*/
|
|
32
|
+
export declare function generateComposeDev(input: ComposeGeneratorInput): string;
|
|
33
|
+
/**
|
|
34
|
+
* Escreve o compose + Dockerfile.agent no diretório do projeto.
|
|
35
|
+
*/
|
|
36
|
+
export declare function writeComposeDev(cwd: string, input: ComposeGeneratorInput): string;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Mapeia engine de banco → config Docker Compose.
|
|
5
|
+
* Usa imagens oficiais — mesmas engines que rodam em produção na VM.
|
|
6
|
+
*/
|
|
7
|
+
export function resolveDbConfig(engine) {
|
|
8
|
+
const configs = {
|
|
9
|
+
'vm-postgres-single': {
|
|
10
|
+
engine: 'PostgreSQL 15',
|
|
11
|
+
image: 'postgres:15-alpine',
|
|
12
|
+
env: { POSTGRES_PASSWORD: 'neetru_dev', POSTGRES_DB: 'app' },
|
|
13
|
+
port: 5432,
|
|
14
|
+
internalPort: 5432,
|
|
15
|
+
dataDir: '/var/lib/postgresql/data',
|
|
16
|
+
healthcheck: { test: ['CMD-SHELL', 'pg_isready -U postgres'], interval: '5s', timeout: '3s', retries: 10 },
|
|
17
|
+
},
|
|
18
|
+
'vm-mysql-single': {
|
|
19
|
+
engine: 'MySQL 8',
|
|
20
|
+
image: 'mysql:8.0',
|
|
21
|
+
env: { MYSQL_ROOT_PASSWORD: 'neetru_dev', MYSQL_DATABASE: 'app' },
|
|
22
|
+
port: 3306,
|
|
23
|
+
internalPort: 3306,
|
|
24
|
+
dataDir: '/var/lib/mysql',
|
|
25
|
+
healthcheck: { test: ['CMD', 'mysqladmin', 'ping', '-h', 'localhost'], interval: '5s', timeout: '3s', retries: 10 },
|
|
26
|
+
},
|
|
27
|
+
'nosql-vm': {
|
|
28
|
+
engine: 'MongoDB 7',
|
|
29
|
+
image: 'mongo:7',
|
|
30
|
+
env: { MONGO_INITDB_DATABASE: 'app' },
|
|
31
|
+
port: 27017,
|
|
32
|
+
internalPort: 27017,
|
|
33
|
+
dataDir: '/data/db',
|
|
34
|
+
healthcheck: { test: ['CMD', 'mongosh', '--eval', "db.adminCommand('ping')"], interval: '5s', timeout: '3s', retries: 10 },
|
|
35
|
+
},
|
|
36
|
+
'firestore-instance': {
|
|
37
|
+
engine: 'Firestore (Firebase Emulator)',
|
|
38
|
+
// Pinado num tag específico — imagem de terceiro em `:latest` deriva sem
|
|
39
|
+
// aviso e num dia ruim puxa uma versão quebrada/comprometida no dev local.
|
|
40
|
+
image: 'andreysenov/firebase-tools:15.24.0',
|
|
41
|
+
env: {},
|
|
42
|
+
port: 8080,
|
|
43
|
+
internalPort: 8080,
|
|
44
|
+
dataDir: '/data',
|
|
45
|
+
healthcheck: { test: ['CMD', 'curl', '-f', 'http://localhost:8080'], interval: '5s', timeout: '3s', retries: 15 },
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
// Normaliza engine (vm-postgres-single, cloud-sql-postgres → postgres config)
|
|
49
|
+
if (engine.includes('postgres'))
|
|
50
|
+
return configs['vm-postgres-single'];
|
|
51
|
+
if (engine.includes('mysql'))
|
|
52
|
+
return configs['vm-mysql-single'];
|
|
53
|
+
if (engine.includes('nosql') || engine.includes('mongo'))
|
|
54
|
+
return configs['nosql-vm'];
|
|
55
|
+
if (engine.includes('firestore'))
|
|
56
|
+
return configs['firestore-instance'];
|
|
57
|
+
return configs['vm-postgres-single'] ?? null; // default
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Gera o conteúdo do docker-compose.dev.yml baseado na config do produto.
|
|
61
|
+
* Template em templates/dev/docker-compose.dev.yml com substituições {{VAR}}.
|
|
62
|
+
*/
|
|
63
|
+
export function generateComposeDev(input) {
|
|
64
|
+
const db = resolveDbConfig(input.dbEngine) ?? resolveDbConfig('vm-postgres-single');
|
|
65
|
+
const appPort = input.appPort ?? 3000;
|
|
66
|
+
// Bloco `environment:` só entra quando há vars — senão vira `environment:`
|
|
67
|
+
// vazio, que o docker compose rejeita ("environment must be a mapping").
|
|
68
|
+
// Firestore (env: {}) caía nisso → `dev up` firestore gerava compose inválido.
|
|
69
|
+
const dbEnvEntries = Object.entries(db.env);
|
|
70
|
+
const dbEnvBlock = dbEnvEntries.length
|
|
71
|
+
? ` environment:\n${dbEnvEntries.map(([k, v]) => ` - ${k}=${v}`).join('\n')}\n`
|
|
72
|
+
: '';
|
|
73
|
+
const dbHealthcheck = [
|
|
74
|
+
` test: ${JSON.stringify(db.healthcheck.test)}`,
|
|
75
|
+
` interval: ${db.healthcheck.interval}`,
|
|
76
|
+
` timeout: ${db.healthcheck.timeout}`,
|
|
77
|
+
` retries: ${db.healthcheck.retries}`,
|
|
78
|
+
].join('\n');
|
|
79
|
+
return `# Neetru Dev Local — emulador de VM (${db.engine})
|
|
80
|
+
# Gerado por \`neetru dev up\`. Modifique o neetru.config.json e rode novamente.
|
|
81
|
+
|
|
82
|
+
services:
|
|
83
|
+
database:
|
|
84
|
+
image: ${db.image}
|
|
85
|
+
container_name: neetru-dev-db
|
|
86
|
+
${dbEnvBlock} ports:
|
|
87
|
+
- "${db.port}:${db.internalPort}"
|
|
88
|
+
volumes:
|
|
89
|
+
- neetru-db-data:${db.dataDir}
|
|
90
|
+
healthcheck:
|
|
91
|
+
${dbHealthcheck}
|
|
92
|
+
restart: unless-stopped
|
|
93
|
+
networks:
|
|
94
|
+
- neetru-dev-net
|
|
95
|
+
|
|
96
|
+
agent:
|
|
97
|
+
build:
|
|
98
|
+
context: .
|
|
99
|
+
dockerfile: Dockerfile.agent
|
|
100
|
+
container_name: neetru-dev-agent
|
|
101
|
+
environment:
|
|
102
|
+
- NEETRU_SERVER_ID=dev-local-${input.productSlug}
|
|
103
|
+
- NEETRU_CORE_URL=${input.coreUrl ?? 'https://core.neetru.com'}
|
|
104
|
+
- NEETRU_FIREBASE_PROJECT=${input.firebaseProject ?? 'neetru'}
|
|
105
|
+
- NEETRU_FIREBASE_API_KEY=${input.firebaseApiKey ?? ''}
|
|
106
|
+
- NEETRU_DEV_MODE=true
|
|
107
|
+
- NEETRU_APP_PORT=${appPort}
|
|
108
|
+
- DATABASE_URL=${db.internalPort === 5432 ? 'postgresql://postgres:neetru_dev@database:5432/app' : db.internalPort === 3306 ? 'mysql://root:neetru_dev@database:3306/app' : db.internalPort === 27017 ? 'mongodb://database:27017/app' : ''}
|
|
109
|
+
ports:
|
|
110
|
+
- "${appPort}:${appPort}"
|
|
111
|
+
volumes:
|
|
112
|
+
- /var/run/docker.sock:/var/run/docker.sock
|
|
113
|
+
- neetru-agent-data:/var/cache/neetru
|
|
114
|
+
- .:/app/product:cached
|
|
115
|
+
depends_on:
|
|
116
|
+
database:
|
|
117
|
+
condition: service_healthy
|
|
118
|
+
restart: unless-stopped
|
|
119
|
+
networks:
|
|
120
|
+
- neetru-dev-net
|
|
121
|
+
|
|
122
|
+
volumes:
|
|
123
|
+
neetru-db-data:
|
|
124
|
+
neetru-agent-data:
|
|
125
|
+
|
|
126
|
+
networks:
|
|
127
|
+
neetru-dev-net:
|
|
128
|
+
driver: bridge
|
|
129
|
+
`;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Escreve o compose + Dockerfile.agent no diretório do projeto.
|
|
133
|
+
*/
|
|
134
|
+
export function writeComposeDev(cwd, input) {
|
|
135
|
+
const composePath = path.join(cwd, 'neetru-compose.dev.yml');
|
|
136
|
+
const dockerfilePath = path.join(cwd, 'Dockerfile.agent');
|
|
137
|
+
const entrypointPath = path.join(cwd, 'agent-entrypoint.sh');
|
|
138
|
+
const compose = generateComposeDev(input);
|
|
139
|
+
fs.writeFileSync(composePath, compose, 'utf8');
|
|
140
|
+
// Copia o Dockerfile.agent do template embutido
|
|
141
|
+
const templateDir = path.join(path.dirname(new URL(import.meta.url).pathname), '..', '..', 'templates', 'dev');
|
|
142
|
+
// Em modo pkg/compilado, busca do __dirname ou do diretório do CLI
|
|
143
|
+
const altTemplate = path.join(process.cwd(), 'node_modules', '@neetru', 'cli', 'templates', 'dev');
|
|
144
|
+
const dockerfileSrc = fs.existsSync(path.join(templateDir, 'Dockerfile.agent'))
|
|
145
|
+
? path.join(templateDir, 'Dockerfile.agent')
|
|
146
|
+
: path.join(altTemplate, 'Dockerfile.agent');
|
|
147
|
+
if (fs.existsSync(dockerfileSrc)) {
|
|
148
|
+
fs.copyFileSync(dockerfileSrc, dockerfilePath);
|
|
149
|
+
}
|
|
150
|
+
return composePath;
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=compose-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compose-generator.js","sourceRoot":"","sources":["../../src/lib/compose-generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -79,6 +79,16 @@ export declare const neetruConfigSchema: z.ZodObject<{
|
|
|
79
79
|
region: z.ZodOptional<z.ZodString>;
|
|
80
80
|
serviceName: z.ZodOptional<z.ZodString>;
|
|
81
81
|
}, z.ZodTypeAny, "passthrough">>>;
|
|
82
|
+
database: z.ZodOptional<z.ZodObject<{
|
|
83
|
+
engine: z.ZodOptional<z.ZodEnum<["vm-postgres-single", "vm-mysql-single", "nosql-vm", "firestore-instance"]>>;
|
|
84
|
+
dbId: z.ZodOptional<z.ZodString>;
|
|
85
|
+
}, "strip", z.ZodTypeAny, {
|
|
86
|
+
engine?: "firestore-instance" | "vm-postgres-single" | "vm-mysql-single" | "nosql-vm" | undefined;
|
|
87
|
+
dbId?: string | undefined;
|
|
88
|
+
}, {
|
|
89
|
+
engine?: "firestore-instance" | "vm-postgres-single" | "vm-mysql-single" | "nosql-vm" | undefined;
|
|
90
|
+
dbId?: string | undefined;
|
|
91
|
+
}>>;
|
|
82
92
|
}, "strip", z.ZodTypeAny, {
|
|
83
93
|
name: string;
|
|
84
94
|
slug: string;
|
|
@@ -98,6 +108,10 @@ export declare const neetruConfigSchema: z.ZodObject<{
|
|
|
98
108
|
ctaHref?: string | undefined;
|
|
99
109
|
ctaLabel?: string | undefined;
|
|
100
110
|
} | undefined;
|
|
111
|
+
database?: {
|
|
112
|
+
engine?: "firestore-instance" | "vm-postgres-single" | "vm-mysql-single" | "nosql-vm" | undefined;
|
|
113
|
+
dbId?: string | undefined;
|
|
114
|
+
} | undefined;
|
|
101
115
|
}, {
|
|
102
116
|
name: string;
|
|
103
117
|
slug: string;
|
|
@@ -117,6 +131,10 @@ export declare const neetruConfigSchema: z.ZodObject<{
|
|
|
117
131
|
ctaHref?: string | undefined;
|
|
118
132
|
ctaLabel?: string | undefined;
|
|
119
133
|
} | undefined;
|
|
134
|
+
database?: {
|
|
135
|
+
engine?: "firestore-instance" | "vm-postgres-single" | "vm-mysql-single" | "nosql-vm" | undefined;
|
|
136
|
+
dbId?: string | undefined;
|
|
137
|
+
} | undefined;
|
|
120
138
|
}>;
|
|
121
139
|
export type NeetruConfig = z.infer<typeof neetruConfigSchema>;
|
|
122
140
|
export type PublishBlock = z.infer<typeof publishBlockSchema>;
|
|
@@ -38,6 +38,10 @@ export const neetruConfigSchema = z.object({
|
|
|
38
38
|
tenantId: z.string().optional(),
|
|
39
39
|
publish: publishBlockSchema.optional(),
|
|
40
40
|
deploy: deployBlockSchema.optional(),
|
|
41
|
+
database: z.object({
|
|
42
|
+
engine: z.enum(['vm-postgres-single', 'vm-mysql-single', 'nosql-vm', 'firestore-instance']).optional(),
|
|
43
|
+
dbId: z.string().optional(),
|
|
44
|
+
}).optional(),
|
|
41
45
|
});
|
|
42
46
|
export const catalogUpsertPayloadSchema = z.object({
|
|
43
47
|
slug: slugSchema,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-schema.js","sourceRoot":"","sources":["../../src/lib/config-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,UAAU;IACV,SAAS;IACT,OAAO;IACP,QAAQ;IACR,OAAO;IACP,QAAQ;IACR,UAAU;CACF,CAAC;AAEX,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAU,CAAC;AAEzE,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAU,CAAC;AAExD,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC;KACxB,MAAM,EAAE;KACR,GAAG,CAAC,CAAC,EAAE,uCAAuC,CAAC;KAC/C,GAAG,CAAC,EAAE,EAAE,uCAAuC,CAAC;KAChD,KAAK,CACJ,4BAA4B,EAC5B,4DAA4D,CAC7D,CAAC;AAEJ,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IACnC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;IACzC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,wBAAwB,CAAC;IACzC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC;IACvC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE;IAChD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACpC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE;CAC/C,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC;KAC/B,MAAM,CAAC;IACN,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACnC,CAAC;KACD,WAAW,EAAE,CAAC;AAEjB,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;IAC/B,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;IACzB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/B,OAAO,EAAE,kBAAkB,CAAC,QAAQ,EAAE;IACtC,MAAM,EAAE,iBAAiB,CAAC,QAAQ,EAAE;
|
|
1
|
+
{"version":3,"file":"config-schema.js","sourceRoot":"","sources":["../../src/lib/config-schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -25,9 +25,32 @@
|
|
|
25
25
|
*
|
|
26
26
|
* Paths puramente síncronos podem usar process.exit() direto.
|
|
27
27
|
*/
|
|
28
|
+
/**
|
|
29
|
+
* Sinal interno lançado por `safeExit` em produção para PARAR o caller sem
|
|
30
|
+
* `process.exit()` síncrono. O trap global em `index.ts` (`isSafeExitHalt`) o
|
|
31
|
+
* engole; o `setTimeout` agendado dentro do `safeExit` faz a saída REAL depois
|
|
32
|
+
* que o `uv_async_t` do undici fecha. Não estende `Error` de propósito — não é
|
|
33
|
+
* um erro, é um sinal de controle de fluxo.
|
|
34
|
+
*/
|
|
35
|
+
export declare class SafeExitHalt {
|
|
36
|
+
readonly code: number;
|
|
37
|
+
readonly __neetruSafeExit: true;
|
|
38
|
+
constructor(code: number);
|
|
39
|
+
}
|
|
40
|
+
/** Reconhece o sinal de halt do `safeExit` (usado pelos traps globais). */
|
|
41
|
+
export declare function isSafeExitHalt(x: unknown): x is SafeExitHalt;
|
|
28
42
|
/**
|
|
29
43
|
* Sai com `code` após cleanup de handles libuv. NEVER returns.
|
|
30
44
|
* Use em error paths que tocaram I/O assíncrono.
|
|
45
|
+
*
|
|
46
|
+
* Windows + undici (bug_818cf6d): `fetch()` do Node deixa um `uv_async_t`
|
|
47
|
+
* aberto; `process.exit()` SÍNCRONO o mata em `UV_HANDLE_CLOSING` (assertion
|
|
48
|
+
* fatal em `src\win\async.c`). RE-CONFIRMADO empiricamente 2026-07-16 que
|
|
49
|
+
* stdin.destroy() NÃO resolve — só deferir o exit um macrotask real (~100ms)
|
|
50
|
+
* deixa o handle fechar (setImmediate/delay-0 NÃO bastam). Em produção
|
|
51
|
+
* agendamos o exit e lançamos `SafeExitHalt` pra impedir a continuação síncrona
|
|
52
|
+
* do caller (preserva o contrato `never`); o timer é agendado ANTES do throw,
|
|
53
|
+
* então mesmo que um `try/catch` intermediário engula o sinal, o processo sai.
|
|
31
54
|
*/
|
|
32
55
|
export declare function safeExit(code: number): never;
|
|
33
56
|
/**
|
package/dist/utils/safe-exit.js
CHANGED
|
@@ -62,13 +62,65 @@ function cleanupHandles() {
|
|
|
62
62
|
// e o exit imediato — sockets http morrem com o processo de qualquer
|
|
63
63
|
// forma. Manter destroy aqui só prejudicava telemetria keepalive:true.
|
|
64
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Sinal interno lançado por `safeExit` em produção para PARAR o caller sem
|
|
67
|
+
* `process.exit()` síncrono. O trap global em `index.ts` (`isSafeExitHalt`) o
|
|
68
|
+
* engole; o `setTimeout` agendado dentro do `safeExit` faz a saída REAL depois
|
|
69
|
+
* que o `uv_async_t` do undici fecha. Não estende `Error` de propósito — não é
|
|
70
|
+
* um erro, é um sinal de controle de fluxo.
|
|
71
|
+
*/
|
|
72
|
+
export class SafeExitHalt {
|
|
73
|
+
code;
|
|
74
|
+
__neetruSafeExit = true;
|
|
75
|
+
constructor(code) {
|
|
76
|
+
this.code = code;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/** Reconhece o sinal de halt do `safeExit` (usado pelos traps globais). */
|
|
80
|
+
export function isSafeExitHalt(x) {
|
|
81
|
+
return (typeof x === 'object' &&
|
|
82
|
+
x !== null &&
|
|
83
|
+
x.__neetruSafeExit === true);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Em teste (vitest) mantemos `process.exit` SÍNCRONO: a suíte mocka/espera o
|
|
87
|
+
* `process.exit` e o exit deferido penduraria os workers / mudaria a semântica.
|
|
88
|
+
*/
|
|
89
|
+
function isTestEnv() {
|
|
90
|
+
return process.env.VITEST === 'true' || process.env.NODE_ENV === 'test';
|
|
91
|
+
}
|
|
65
92
|
/**
|
|
66
93
|
* Sai com `code` após cleanup de handles libuv. NEVER returns.
|
|
67
94
|
* Use em error paths que tocaram I/O assíncrono.
|
|
95
|
+
*
|
|
96
|
+
* Windows + undici (bug_818cf6d): `fetch()` do Node deixa um `uv_async_t`
|
|
97
|
+
* aberto; `process.exit()` SÍNCRONO o mata em `UV_HANDLE_CLOSING` (assertion
|
|
98
|
+
* fatal em `src\win\async.c`). RE-CONFIRMADO empiricamente 2026-07-16 que
|
|
99
|
+
* stdin.destroy() NÃO resolve — só deferir o exit um macrotask real (~100ms)
|
|
100
|
+
* deixa o handle fechar (setImmediate/delay-0 NÃO bastam). Em produção
|
|
101
|
+
* agendamos o exit e lançamos `SafeExitHalt` pra impedir a continuação síncrona
|
|
102
|
+
* do caller (preserva o contrato `never`); o timer é agendado ANTES do throw,
|
|
103
|
+
* então mesmo que um `try/catch` intermediário engula o sinal, o processo sai.
|
|
68
104
|
*/
|
|
69
105
|
export function safeExit(code) {
|
|
70
106
|
cleanupHandles();
|
|
71
|
-
|
|
107
|
+
if (isTestEnv()) {
|
|
108
|
+
// Em teste (vitest) o process.exit é mockado (spy que NÃO sai de fato).
|
|
109
|
+
// O `return` replica EXATAMENTE o safeExit original: chama process.exit e
|
|
110
|
+
// termina — sem cair no defer/throw abaixo (que quebraria a suíte). Em
|
|
111
|
+
// produção este branch nunca roda.
|
|
112
|
+
return process.exit(code);
|
|
113
|
+
}
|
|
114
|
+
process.exitCode = code;
|
|
115
|
+
// Adia o process.exit um macrotask real. O gatilho do UV_HANDLE_CLOSING é o
|
|
116
|
+
// `process.exit()` SÍNCRONO correndo com o teardown do uv_async_t do undici;
|
|
117
|
+
// ~300ms deixa o handle assentar antes da saída (empírico 2026-07-16: 100ms
|
|
118
|
+
// é racy → crash intermitente; 250-300ms → 0 crash em 35+ runs). NÃO fechar
|
|
119
|
+
// o dispatcher do undici aqui: `await dispatcher.close()` + process.exit
|
|
120
|
+
// crasha 25/25 (o force-exit ainda corre com o teardown) e quebra o flush
|
|
121
|
+
// de telemetria keepalive.
|
|
122
|
+
setTimeout(() => process.exit(code), 300);
|
|
123
|
+
throw new SafeExitHalt(code);
|
|
72
124
|
}
|
|
73
125
|
/**
|
|
74
126
|
* Seta process.exitCode mas NÃO sai imediatamente — caller deve `return`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"safe-exit.js","sourceRoot":"","sources":["../../src/utils/safe-exit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,SAAS,cAAc;IACrB,gEAAgE;IAChE,IAAI,CAAC;QAAC,eAAe,EAAE,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;IAEtD,yEAAyE;IACzE,mCAAmC;IACnC,EAAE;IACF,+BAA+B;IAC/B,0EAA0E;IAC1E,0EAA0E;IAC1E,sEAAsE;IACtE,yEAAyE;IACzE,sEAAsE;IACtE,sDAAsD;IACtD,EAAE;IACF,uEAAuE;IACvE,qEAAqE;IACrE,yEAAyE;IACzE,yEAAyE;IACzE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC;YAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,gBAAgB,CAAC,CAAC;IAC7D,CAAC;IAED,kEAAkE;IAClE,gFAAgF;IAChF,wEAAwE;IACxE,0EAA0E;IAC1E,mEAAmE;IACnE,uEAAuE;IACvE,wEAAwE;IACxE,0EAA0E;AAC5E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,cAAc,EAAE,CAAC;IACjB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"safe-exit.js","sourceRoot":"","sources":["../../src/utils/safe-exit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,SAAS,cAAc;IACrB,gEAAgE;IAChE,IAAI,CAAC;QAAC,eAAe,EAAE,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;IAEtD,yEAAyE;IACzE,mCAAmC;IACnC,EAAE;IACF,+BAA+B;IAC/B,0EAA0E;IAC1E,0EAA0E;IAC1E,sEAAsE;IACtE,yEAAyE;IACzE,sEAAsE;IACtE,sDAAsD;IACtD,EAAE;IACF,uEAAuE;IACvE,qEAAqE;IACrE,yEAAyE;IACzE,yEAAyE;IACzE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC;YAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,gBAAgB,CAAC,CAAC;IAC7D,CAAC;IAED,kEAAkE;IAClE,gFAAgF;IAChF,wEAAwE;IACxE,0EAA0E;IAC1E,mEAAmE;IACnE,uEAAuE;IACvE,wEAAwE;IACxE,0EAA0E;AAC5E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,OAAO,YAAY;IAEK;IADnB,gBAAgB,GAAG,IAAa,CAAC;IAC1C,YAA4B,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;IAAG,CAAC;CAC7C;AAED,2EAA2E;AAC3E,MAAM,UAAU,cAAc,CAAC,CAAU;IACvC,OAAO,CACL,OAAO,CAAC,KAAK,QAAQ;QACrB,CAAC,KAAK,IAAI;QACT,CAAoC,CAAC,gBAAgB,KAAK,IAAI,CAChE,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAS,SAAS;IAChB,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,CAAC;AAC1E,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,cAAc,EAAE,CAAC;IACjB,IAAI,SAAS,EAAE,EAAE,CAAC;QAChB,wEAAwE;QACxE,0EAA0E;QAC1E,uEAAuE;QACvE,mCAAmC;QACnC,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IACxB,4EAA4E;IAC5E,6EAA6E;IAC7E,4EAA4E;IAC5E,4EAA4E;IAC5E,yEAAyE;IACzE,0EAA0E;IAC1E,2BAA2B;IAC3B,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;IAC1C,MAAM,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,cAAc,EAAE,CAAC;IACjB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;AAC1B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Template — `src/lib/neetru/auth/callback.ts` (gerado por `neetru add auth`).
|
|
3
|
-
*
|
|
4
|
-
* Handler de callback OIDC (auth code → id_token). Use em `app/oauth/callback/route.ts`.
|
|
5
|
-
*/
|
|
6
|
-
import { NextRequest, NextResponse } from 'next/server';
|
|
7
|
-
|
|
8
|
-
export const runtime = 'nodejs';
|
|
9
|
-
|
|
10
|
-
export async function GET(request: NextRequest) {
|
|
11
|
-
const { searchParams } = new URL(request.url);
|
|
12
|
-
const code = searchParams.get('code');
|
|
13
|
-
const state = searchParams.get('state');
|
|
14
|
-
|
|
15
|
-
if (!code) {
|
|
16
|
-
return NextResponse.json({ error: 'missing_code' }, { status: 400 });
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Trocar code → id_token contra auth.neetru.com/token
|
|
20
|
-
// Implementação detalhada em docs/PLATFORM_AUTH.md §4
|
|
21
|
-
return NextResponse.redirect(state ?? '/');
|
|
22
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Template — `src/lib/neetru/auth/callback.ts` (gerado por `neetru add auth`).
|
|
3
|
+
*
|
|
4
|
+
* Handler de callback OIDC (auth code → id_token). Use em `app/oauth/callback/route.ts`.
|
|
5
|
+
*/
|
|
6
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
7
|
+
|
|
8
|
+
export const runtime = 'nodejs';
|
|
9
|
+
|
|
10
|
+
export async function GET(request: NextRequest) {
|
|
11
|
+
const { searchParams } = new URL(request.url);
|
|
12
|
+
const code = searchParams.get('code');
|
|
13
|
+
const state = searchParams.get('state');
|
|
14
|
+
|
|
15
|
+
if (!code) {
|
|
16
|
+
return NextResponse.json({ error: 'missing_code' }, { status: 400 });
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Trocar code → id_token contra auth.neetru.com/token
|
|
20
|
+
// Implementação detalhada em docs/PLATFORM_AUTH.md §4
|
|
21
|
+
return NextResponse.redirect(state ?? '/');
|
|
22
|
+
}
|
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Template — `src/lib/neetru/auth/sign-in.tsx` (gerado por `neetru add auth`).
|
|
3
|
-
*
|
|
4
|
-
* Botão Google → redireciona pra auth.neetru.com via SDK (`client.auth.signIn`).
|
|
5
|
-
*
|
|
6
|
-
* Customização: ajuste `redirectUri` se hospedar fora do domínio default.
|
|
7
|
-
*/
|
|
8
|
-
'use client';
|
|
9
|
-
|
|
10
|
-
import { useState } from 'react';
|
|
11
|
-
import { createNeetruClient } from '@neetru/sdk';
|
|
12
|
-
|
|
13
|
-
const client = createNeetruClient({
|
|
14
|
-
apiKey: process.env.NEXT_PUBLIC_NEETRU_API_KEY,
|
|
15
|
-
productId: process.env.NEXT_PUBLIC_NEETRU_PRODUCT_ID,
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
export function SignInButton() {
|
|
19
|
-
const [loading, setLoading] = useState(false);
|
|
20
|
-
|
|
21
|
-
async function handleSignIn() {
|
|
22
|
-
setLoading(true);
|
|
23
|
-
try {
|
|
24
|
-
await client.auth.signIn();
|
|
25
|
-
} catch (err) {
|
|
26
|
-
console.error('signIn failed', err);
|
|
27
|
-
setLoading(false);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return (
|
|
32
|
-
<button
|
|
33
|
-
type="button"
|
|
34
|
-
onClick={handleSignIn}
|
|
35
|
-
disabled={loading}
|
|
36
|
-
className="inline-flex items-center justify-center px-4 py-2 border bg-white hover:bg-zinc-50 text-zinc-900 font-medium"
|
|
37
|
-
>
|
|
38
|
-
{loading ? 'Redirecionando...' : 'Entrar com Neetru'}
|
|
39
|
-
</button>
|
|
40
|
-
);
|
|
41
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Template — `src/lib/neetru/auth/sign-in.tsx` (gerado por `neetru add auth`).
|
|
3
|
+
*
|
|
4
|
+
* Botão Google → redireciona pra auth.neetru.com via SDK (`client.auth.signIn`).
|
|
5
|
+
*
|
|
6
|
+
* Customização: ajuste `redirectUri` se hospedar fora do domínio default.
|
|
7
|
+
*/
|
|
8
|
+
'use client';
|
|
9
|
+
|
|
10
|
+
import { useState } from 'react';
|
|
11
|
+
import { createNeetruClient } from '@neetru/sdk';
|
|
12
|
+
|
|
13
|
+
const client = createNeetruClient({
|
|
14
|
+
apiKey: process.env.NEXT_PUBLIC_NEETRU_API_KEY,
|
|
15
|
+
productId: process.env.NEXT_PUBLIC_NEETRU_PRODUCT_ID,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export function SignInButton() {
|
|
19
|
+
const [loading, setLoading] = useState(false);
|
|
20
|
+
|
|
21
|
+
async function handleSignIn() {
|
|
22
|
+
setLoading(true);
|
|
23
|
+
try {
|
|
24
|
+
await client.auth.signIn();
|
|
25
|
+
} catch (err) {
|
|
26
|
+
console.error('signIn failed', err);
|
|
27
|
+
setLoading(false);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<button
|
|
33
|
+
type="button"
|
|
34
|
+
onClick={handleSignIn}
|
|
35
|
+
disabled={loading}
|
|
36
|
+
className="inline-flex items-center justify-center px-4 py-2 border bg-white hover:bg-zinc-50 text-zinc-900 font-medium"
|
|
37
|
+
>
|
|
38
|
+
{loading ? 'Redirecionando...' : 'Entrar com Neetru'}
|
|
39
|
+
</button>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
@@ -1,22 +1,38 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Template — `src/
|
|
3
|
-
*
|
|
4
|
-
* Inicia checkout Stripe via
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Template — `src/app/api/billing/checkout/route.ts` (gerado por `neetru add billing`).
|
|
3
|
+
*
|
|
4
|
+
* Inicia checkout Stripe via SDK server-side. O cliente chama este endpoint
|
|
5
|
+
* com { planId, productId } e recebe a URL de redirecionamento pro Stripe.
|
|
6
|
+
*
|
|
7
|
+
* Pré-requisito: NEETRU_API_KEY e NEETRU_PRODUCT_ID no .env.local.
|
|
8
|
+
*/
|
|
9
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
10
|
+
import { createNeetruClient } from '@neetru/sdk';
|
|
11
|
+
|
|
12
|
+
export const runtime = 'nodejs';
|
|
13
|
+
|
|
14
|
+
export async function POST(request: NextRequest) {
|
|
15
|
+
const body = await request.json();
|
|
16
|
+
const { planId, productId } = body ?? {};
|
|
17
|
+
const pid = productId || process.env.NEETRU_PRODUCT_ID;
|
|
18
|
+
|
|
19
|
+
if (!planId || !pid) {
|
|
20
|
+
return NextResponse.json(
|
|
21
|
+
{ error: 'planId e productId obrigatórios' },
|
|
22
|
+
{ status: 400 },
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const client = createNeetruClient({
|
|
27
|
+
apiKey: process.env.NEETRU_API_KEY!,
|
|
28
|
+
productId: pid,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const result = await client.checkout.start({
|
|
32
|
+
productId: pid,
|
|
33
|
+
planId,
|
|
34
|
+
callbackUrl: `${process.env.NEXT_PUBLIC_APP_URL ?? 'http://localhost:3000'}/billing/success`,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
return NextResponse.json({ redirectUrl: result.redirectUrl });
|
|
38
|
+
}
|