@neetru/cli 2.24.1 → 2.25.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/dev-up.js +82 -12
- 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/index.js +5 -10
- 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 +148 -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/package.json +1 -1
- package/templates/auth/callback.ts +22 -22
- package/templates/auth/sign-in.tsx +41 -41
- package/templates/billing/checkout.ts +22 -22
- package/templates/billing/page.tsx +43 -43
- 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,148 @@
|
|
|
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
|
+
image: 'andreysenov/firebase-tools:latest',
|
|
39
|
+
env: {},
|
|
40
|
+
port: 8080,
|
|
41
|
+
internalPort: 8080,
|
|
42
|
+
dataDir: '/data',
|
|
43
|
+
healthcheck: { test: ['CMD', 'curl', '-f', 'http://localhost:8080'], interval: '5s', timeout: '3s', retries: 15 },
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
// Normaliza engine (vm-postgres-single, cloud-sql-postgres → postgres config)
|
|
47
|
+
if (engine.includes('postgres'))
|
|
48
|
+
return configs['vm-postgres-single'];
|
|
49
|
+
if (engine.includes('mysql'))
|
|
50
|
+
return configs['vm-mysql-single'];
|
|
51
|
+
if (engine.includes('nosql') || engine.includes('mongo'))
|
|
52
|
+
return configs['nosql-vm'];
|
|
53
|
+
if (engine.includes('firestore'))
|
|
54
|
+
return configs['firestore-instance'];
|
|
55
|
+
return configs['vm-postgres-single'] ?? null; // default
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Gera o conteúdo do docker-compose.dev.yml baseado na config do produto.
|
|
59
|
+
* Template em templates/dev/docker-compose.dev.yml com substituições {{VAR}}.
|
|
60
|
+
*/
|
|
61
|
+
export function generateComposeDev(input) {
|
|
62
|
+
const db = resolveDbConfig(input.dbEngine) ?? resolveDbConfig('vm-postgres-single');
|
|
63
|
+
const appPort = input.appPort ?? 3000;
|
|
64
|
+
const dbEnv = Object.entries(db.env)
|
|
65
|
+
.map(([k, v]) => ` - ${k}=${v}`)
|
|
66
|
+
.join('\n');
|
|
67
|
+
const dbHealthcheck = [
|
|
68
|
+
` test: ${JSON.stringify(db.healthcheck.test)}`,
|
|
69
|
+
` interval: ${db.healthcheck.interval}`,
|
|
70
|
+
` timeout: ${db.healthcheck.timeout}`,
|
|
71
|
+
` retries: ${db.healthcheck.retries}`,
|
|
72
|
+
].join('\n');
|
|
73
|
+
return `# Neetru Dev Local — emulador de VM (${db.engine})
|
|
74
|
+
# Gerado por \`neetru dev up\`. Modifique o neetru.config.json e rode novamente.
|
|
75
|
+
|
|
76
|
+
services:
|
|
77
|
+
database:
|
|
78
|
+
image: ${db.image}
|
|
79
|
+
container_name: neetru-dev-db
|
|
80
|
+
environment:
|
|
81
|
+
${dbEnv}
|
|
82
|
+
ports:
|
|
83
|
+
- "${db.port}:${db.internalPort}"
|
|
84
|
+
volumes:
|
|
85
|
+
- neetru-db-data:${db.dataDir}
|
|
86
|
+
healthcheck:
|
|
87
|
+
${dbHealthcheck}
|
|
88
|
+
restart: unless-stopped
|
|
89
|
+
networks:
|
|
90
|
+
- neetru-dev-net
|
|
91
|
+
|
|
92
|
+
agent:
|
|
93
|
+
build:
|
|
94
|
+
context: .
|
|
95
|
+
dockerfile: Dockerfile.agent
|
|
96
|
+
container_name: neetru-dev-agent
|
|
97
|
+
environment:
|
|
98
|
+
- NEETRU_SERVER_ID=dev-local-${input.productSlug}
|
|
99
|
+
- NEETRU_CORE_URL=${input.coreUrl ?? 'https://core.neetru.com'}
|
|
100
|
+
- NEETRU_FIREBASE_PROJECT=${input.firebaseProject ?? 'neetru'}
|
|
101
|
+
- NEETRU_FIREBASE_API_KEY=${input.firebaseApiKey ?? ''}
|
|
102
|
+
- NEETRU_DEV_MODE=true
|
|
103
|
+
- NEETRU_APP_PORT=${appPort}
|
|
104
|
+
- 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' : ''}
|
|
105
|
+
ports:
|
|
106
|
+
- "${appPort}:${appPort}"
|
|
107
|
+
volumes:
|
|
108
|
+
- /var/run/docker.sock:/var/run/docker.sock
|
|
109
|
+
- neetru-agent-data:/var/cache/neetru
|
|
110
|
+
- .:/app/product:cached
|
|
111
|
+
depends_on:
|
|
112
|
+
database:
|
|
113
|
+
condition: service_healthy
|
|
114
|
+
restart: unless-stopped
|
|
115
|
+
networks:
|
|
116
|
+
- neetru-dev-net
|
|
117
|
+
|
|
118
|
+
volumes:
|
|
119
|
+
neetru-db-data:
|
|
120
|
+
neetru-agent-data:
|
|
121
|
+
|
|
122
|
+
networks:
|
|
123
|
+
neetru-dev-net:
|
|
124
|
+
driver: bridge
|
|
125
|
+
`;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Escreve o compose + Dockerfile.agent no diretório do projeto.
|
|
129
|
+
*/
|
|
130
|
+
export function writeComposeDev(cwd, input) {
|
|
131
|
+
const composePath = path.join(cwd, 'neetru-compose.dev.yml');
|
|
132
|
+
const dockerfilePath = path.join(cwd, 'Dockerfile.agent');
|
|
133
|
+
const entrypointPath = path.join(cwd, 'agent-entrypoint.sh');
|
|
134
|
+
const compose = generateComposeDev(input);
|
|
135
|
+
fs.writeFileSync(composePath, compose, 'utf8');
|
|
136
|
+
// Copia o Dockerfile.agent do template embutido
|
|
137
|
+
const templateDir = path.join(path.dirname(new URL(import.meta.url).pathname), '..', '..', 'templates', 'dev');
|
|
138
|
+
// Em modo pkg/compilado, busca do __dirname ou do diretório do CLI
|
|
139
|
+
const altTemplate = path.join(process.cwd(), 'node_modules', '@neetru', 'cli', 'templates', 'dev');
|
|
140
|
+
const dockerfileSrc = fs.existsSync(path.join(templateDir, 'Dockerfile.agent'))
|
|
141
|
+
? path.join(templateDir, 'Dockerfile.agent')
|
|
142
|
+
: path.join(altTemplate, 'Dockerfile.agent');
|
|
143
|
+
if (fs.existsSync(dockerfileSrc)) {
|
|
144
|
+
fs.copyFileSync(dockerfileSrc, dockerfilePath);
|
|
145
|
+
}
|
|
146
|
+
return composePath;
|
|
147
|
+
}
|
|
148
|
+
//# 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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"}
|
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,22 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Template — `src/lib/neetru/billing/checkout.ts` (gerado por `neetru add billing`).
|
|
3
|
-
*
|
|
4
|
-
* Inicia checkout Stripe via Core. Server route handler.
|
|
5
|
-
*/
|
|
6
|
-
import { NextRequest, NextResponse } from 'next/server';
|
|
7
|
-
|
|
8
|
-
export const runtime = 'nodejs';
|
|
9
|
-
|
|
10
|
-
export async function POST(request: NextRequest) {
|
|
11
|
-
const body = await request.json();
|
|
12
|
-
const slug = body?.slug as string | undefined;
|
|
13
|
-
if (!slug) {
|
|
14
|
-
return NextResponse.json({ error: 'slug required' }, { status: 400 });
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Hit Core REST: POST /api/v1/billing/checkout
|
|
18
|
-
// (Sprint 9 expõe via SDK direto)
|
|
19
|
-
return NextResponse.json({
|
|
20
|
-
redirectUrl: `https://minhaconta.neetru.com/checkout?slug=${slug}`,
|
|
21
|
-
});
|
|
22
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Template — `src/lib/neetru/billing/checkout.ts` (gerado por `neetru add billing`).
|
|
3
|
+
*
|
|
4
|
+
* Inicia checkout Stripe via Core. Server route handler.
|
|
5
|
+
*/
|
|
6
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
7
|
+
|
|
8
|
+
export const runtime = 'nodejs';
|
|
9
|
+
|
|
10
|
+
export async function POST(request: NextRequest) {
|
|
11
|
+
const body = await request.json();
|
|
12
|
+
const slug = body?.slug as string | undefined;
|
|
13
|
+
if (!slug) {
|
|
14
|
+
return NextResponse.json({ error: 'slug required' }, { status: 400 });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Hit Core REST: POST /api/v1/billing/checkout
|
|
18
|
+
// (Sprint 9 expõe via SDK direto)
|
|
19
|
+
return NextResponse.json({
|
|
20
|
+
redirectUrl: `https://minhaconta.neetru.com/checkout?slug=${slug}`,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Template — `src/lib/neetru/billing/page.tsx` (gerado por `neetru add billing`).
|
|
3
|
-
*
|
|
4
|
-
* Página simples: lista planos + botão checkout via SDK.
|
|
5
|
-
*/
|
|
6
|
-
'use client';
|
|
7
|
-
|
|
8
|
-
import { useEffect, useState } from 'react';
|
|
9
|
-
import { createNeetruClient, type Product } from '@neetru/sdk';
|
|
10
|
-
|
|
11
|
-
const client = createNeetruClient({
|
|
12
|
-
apiKey: process.env.NEXT_PUBLIC_NEETRU_API_KEY,
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
export default function BillingPage() {
|
|
16
|
-
const [products, setProducts] = useState<Product[]>([]);
|
|
17
|
-
useEffect(() => {
|
|
18
|
-
client.catalog
|
|
19
|
-
.list()
|
|
20
|
-
.then(({ products }) => setProducts(products))
|
|
21
|
-
.catch((err) => console.error(err));
|
|
22
|
-
}, []);
|
|
23
|
-
|
|
24
|
-
return (
|
|
25
|
-
<main className="p-8">
|
|
26
|
-
<h1 className="text-3xl font-bold mb-6">Planos</h1>
|
|
27
|
-
<div className="grid gap-4 md:grid-cols-3">
|
|
28
|
-
{products.map((p) => (
|
|
29
|
-
<article key={p.slug} className="border p-6">
|
|
30
|
-
<h2 className="text-xl font-semibold">{p.name}</h2>
|
|
31
|
-
<p className="text-sm text-zinc-600 mt-1">{p.tagline}</p>
|
|
32
|
-
<a
|
|
33
|
-
href={`/checkout?slug=${p.slug}`}
|
|
34
|
-
className="inline-block mt-4 px-4 py-2 bg-zinc-900 text-white"
|
|
35
|
-
>
|
|
36
|
-
Assinar
|
|
37
|
-
</a>
|
|
38
|
-
</article>
|
|
39
|
-
))}
|
|
40
|
-
</div>
|
|
41
|
-
</main>
|
|
42
|
-
);
|
|
43
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Template — `src/lib/neetru/billing/page.tsx` (gerado por `neetru add billing`).
|
|
3
|
+
*
|
|
4
|
+
* Página simples: lista planos + botão checkout via SDK.
|
|
5
|
+
*/
|
|
6
|
+
'use client';
|
|
7
|
+
|
|
8
|
+
import { useEffect, useState } from 'react';
|
|
9
|
+
import { createNeetruClient, type Product } from '@neetru/sdk';
|
|
10
|
+
|
|
11
|
+
const client = createNeetruClient({
|
|
12
|
+
apiKey: process.env.NEXT_PUBLIC_NEETRU_API_KEY,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export default function BillingPage() {
|
|
16
|
+
const [products, setProducts] = useState<Product[]>([]);
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
client.catalog
|
|
19
|
+
.list()
|
|
20
|
+
.then(({ products }) => setProducts(products))
|
|
21
|
+
.catch((err) => console.error(err));
|
|
22
|
+
}, []);
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<main className="p-8">
|
|
26
|
+
<h1 className="text-3xl font-bold mb-6">Planos</h1>
|
|
27
|
+
<div className="grid gap-4 md:grid-cols-3">
|
|
28
|
+
{products.map((p) => (
|
|
29
|
+
<article key={p.slug} className="border p-6">
|
|
30
|
+
<h2 className="text-xl font-semibold">{p.name}</h2>
|
|
31
|
+
<p className="text-sm text-zinc-600 mt-1">{p.tagline}</p>
|
|
32
|
+
<a
|
|
33
|
+
href={`/checkout?slug=${p.slug}`}
|
|
34
|
+
className="inline-block mt-4 px-4 py-2 bg-zinc-900 text-white"
|
|
35
|
+
>
|
|
36
|
+
Assinar
|
|
37
|
+
</a>
|
|
38
|
+
</article>
|
|
39
|
+
))}
|
|
40
|
+
</div>
|
|
41
|
+
</main>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Neetru Agent — modo dev (Docker container, sem systemd)
|
|
2
|
+
#
|
|
3
|
+
# Em produção, o agente roda como systemd service na VM.
|
|
4
|
+
# Em dev-local, roda como processo Node direto no container.
|
|
5
|
+
# O deploy do app SaaS é feito como child process (não systemd unit).
|
|
6
|
+
#
|
|
7
|
+
# Build:
|
|
8
|
+
# docker build -f Dockerfile.agent -t neetru-agent-dev .
|
|
9
|
+
|
|
10
|
+
FROM node:22-slim
|
|
11
|
+
|
|
12
|
+
# Dependências do agente em produção (apt, certbot, etc.)
|
|
13
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
14
|
+
curl ca-certificates systemctl \
|
|
15
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
16
|
+
|
|
17
|
+
# Diretório do agente
|
|
18
|
+
WORKDIR /opt/neetru
|
|
19
|
+
|
|
20
|
+
# Baixa o agente mais recente do Core
|
|
21
|
+
ARG CORE_URL=https://core.neetru.com
|
|
22
|
+
ENV NEETRU_CORE_URL=${CORE_URL}
|
|
23
|
+
|
|
24
|
+
# Download do binário (fallback: usa curl se GCS não disponível)
|
|
25
|
+
RUN ARCH=$(uname -m | sed 's/x86_64/x64/;s/aarch64/arm64/') && \
|
|
26
|
+
curl -fsSL -o /usr/local/bin/neetru-agent \
|
|
27
|
+
"${NEETRU_CORE_URL}/releases/latest/neetru-agent-linux-${ARCH}" || \
|
|
28
|
+
echo "Agente não encontrado no Core — será montado via volume" && \
|
|
29
|
+
chmod +x /usr/local/bin/neetru-agent || true
|
|
30
|
+
|
|
31
|
+
# Entrypoint: agente em modo dev
|
|
32
|
+
# - NEETRU_DEV_MODE=true desabilita systemd, usa child_process direto
|
|
33
|
+
# - NEETRU_APP_PORT define a porta onde o app SaaS vai rodar
|
|
34
|
+
COPY templates/dev/agent-entrypoint.sh /usr/local/bin/neetru-agent-entrypoint
|
|
35
|
+
RUN chmod +x /usr/local/bin/neetru-agent-entrypoint
|
|
36
|
+
|
|
37
|
+
EXPOSE 3000
|
|
38
|
+
|
|
39
|
+
ENTRYPOINT ["/usr/local/bin/neetru-agent-entrypoint"]
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Neetru Agent — entrypoint modo dev (Docker container)
|
|
3
|
+
#
|
|
4
|
+
# Em modo dev, o agente NAO usa systemd. Em vez disso:
|
|
5
|
+
# - Deploy = child process (npm install + node server)
|
|
6
|
+
# - Funções = child process (neetru-functions)
|
|
7
|
+
# - Healthcheck = /health endpoint no próprio agente
|
|
8
|
+
#
|
|
9
|
+
# Env vars obrigatórias:
|
|
10
|
+
# NEETRU_SERVER_ID — id do servidor (ex: dev-local-meuproduto)
|
|
11
|
+
# NEETRU_CORE_URL — URL do Core (ex: https://core.neetru.com)
|
|
12
|
+
# NEETRU_FIREBASE_PROJECT — projeto Firebase
|
|
13
|
+
# NEETRU_DEV_MODE — "true" ativa modo dev
|
|
14
|
+
|
|
15
|
+
set -e
|
|
16
|
+
|
|
17
|
+
echo "═══════════════════════════════════════════"
|
|
18
|
+
echo " Neetru Agent — Dev Mode"
|
|
19
|
+
echo " Server: ${NEETRU_SERVER_ID}"
|
|
20
|
+
echo " Core: ${NEETRU_CORE_URL}"
|
|
21
|
+
echo "═══════════════════════════════════════════"
|
|
22
|
+
|
|
23
|
+
# Verifica binário
|
|
24
|
+
if [ ! -f /usr/local/bin/neetru-agent ]; then
|
|
25
|
+
echo "[AGENT] Binário não encontrado. Montando via volume..."
|
|
26
|
+
echo "[AGENT] Certifique-se de que o agente está em /opt/neetru/neetru-agent"
|
|
27
|
+
ls -la /opt/neetru/ || true
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
# Cria diretórios necessários
|
|
31
|
+
mkdir -p /var/cache/neetru /opt/neetru/deploys
|
|
32
|
+
|
|
33
|
+
# Inicia o agente
|
|
34
|
+
echo "[AGENT] Iniciando agente Neetru..."
|
|
35
|
+
exec node /usr/local/bin/neetru-agent 2>&1 || exec node /opt/neetru/neetru-agent 2>&1 || {
|
|
36
|
+
echo "[AGENT] ERRO: Não foi possível iniciar o agente."
|
|
37
|
+
echo "[AGENT] Verifique se o binário existe em /usr/local/bin/neetru-agent"
|
|
38
|
+
echo "[AGENT] ou monte o binário via volume em /opt/neetru/neetru-agent"
|
|
39
|
+
sleep 10
|
|
40
|
+
exit 1
|
|
41
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Neetru Dev Local — emulador de VM ({{ENGINE}})
|
|
2
|
+
# Gerado por `neetru dev up`. Modifique o neetru.config.json e rode novamente.
|
|
3
|
+
#
|
|
4
|
+
# Este compose simula uma VM de produção Neetru:
|
|
5
|
+
# 1. Banco de dados ({{ENGINE}}) = mesmo engine que vai pra produção
|
|
6
|
+
# 2. Agente Neetru = recebe comandos do Core, faz deploy, npm install, healthcheck
|
|
7
|
+
# 3. App SaaS = deployado pelo agente, acessível em http://localhost:{{APP_PORT}}
|
|
8
|
+
#
|
|
9
|
+
# Uso:
|
|
10
|
+
# neetru dev up # gera este compose + sobe tudo
|
|
11
|
+
# docker compose -f neetru-compose.dev.yml up -d # manual
|
|
12
|
+
# docker compose -f neetru-compose.dev.yml down # desliga
|
|
13
|
+
|
|
14
|
+
services:
|
|
15
|
+
# ── Banco de dados ({{ENGINE}}) ────────────────────────────────────────────
|
|
16
|
+
database:
|
|
17
|
+
image: {{DB_IMAGE}}
|
|
18
|
+
container_name: neetru-dev-db
|
|
19
|
+
environment:
|
|
20
|
+
{{DB_ENV}}
|
|
21
|
+
ports:
|
|
22
|
+
- "{{DB_PORT}}:{{DB_INTERNAL_PORT}}"
|
|
23
|
+
volumes:
|
|
24
|
+
- neetru-db-data:{{DB_DATA_DIR}}
|
|
25
|
+
healthcheck:
|
|
26
|
+
{{DB_HEALTHCHECK}}
|
|
27
|
+
restart: unless-stopped
|
|
28
|
+
networks:
|
|
29
|
+
- neetru-dev-net
|
|
30
|
+
|
|
31
|
+
# ── Agente Neetru (modo dev — sem systemd) ────────────────────────────────
|
|
32
|
+
agent:
|
|
33
|
+
build:
|
|
34
|
+
context: .
|
|
35
|
+
dockerfile: Dockerfile.agent
|
|
36
|
+
container_name: neetru-dev-agent
|
|
37
|
+
environment:
|
|
38
|
+
- NEETRU_SERVER_ID=dev-local-{{PRODUCT_SLUG}}
|
|
39
|
+
- NEETRU_CORE_URL={{CORE_URL}}
|
|
40
|
+
- NEETRU_FIREBASE_PROJECT={{FIREBASE_PROJECT}}
|
|
41
|
+
- NEETRU_FIREBASE_API_KEY={{FIREBASE_API_KEY}}
|
|
42
|
+
- NEETRU_DEV_MODE=true
|
|
43
|
+
- NEETRU_APP_PORT={{APP_PORT}}
|
|
44
|
+
ports:
|
|
45
|
+
- "{{APP_PORT}}:{{APP_PORT}}"
|
|
46
|
+
volumes:
|
|
47
|
+
- /var/run/docker.sock:/var/run/docker.sock
|
|
48
|
+
- neetru-agent-data:/var/cache/neetru
|
|
49
|
+
- .:/app/product:cached
|
|
50
|
+
depends_on:
|
|
51
|
+
database:
|
|
52
|
+
condition: service_healthy
|
|
53
|
+
restart: unless-stopped
|
|
54
|
+
networks:
|
|
55
|
+
- neetru-dev-net
|
|
56
|
+
|
|
57
|
+
volumes:
|
|
58
|
+
neetru-db-data:
|
|
59
|
+
neetru-agent-data:
|
|
60
|
+
|
|
61
|
+
networks:
|
|
62
|
+
neetru-dev-net:
|
|
63
|
+
driver: bridge
|