@onroad/core 4.0.0-alpha.22 → 4.0.0-alpha.24

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/README.md CHANGED
@@ -97,72 +97,88 @@ await app.buildServer({ port: 3001 })
97
97
 
98
98
  ## Architecture Overview
99
99
 
100
- ```
101
- ┌──────────────────────────────────────────────────┐
102
- │ OnRoadExpress │
103
- │ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
104
- │ │ Container │ │ FilterChain│ │ EventBus │
105
- │ │ (DI + IoC) │ │ (Middleware)│ │ (Sentinel) │ │
106
- └─────┬──────┘ └─────┬──────┘ └─────┬──────┘
107
- │ │ │ │ │
108
- │ ┌─────▼───────────────▼───────────────▼──────┐
109
- │ │ Request Handler (route)
110
- │ │ requestContext.run({ tenant, appToken }) │ │
111
- │ ┌──────────┐ ┌─────────┐ ┌────────────┐ │
112
- │ │ │Controller│→│ Service │→│ Repository │ │
113
- │ │ └──────────┘ └─────────┘ └────────────┘ │
114
- │ └─────────────────────────────────────────────┘
115
- │ │
116
- ┌──────────────────────────────────────────┐ │
117
- │ │ Providers │ │
118
- │ │ Messaging Realtime TaskSched Socket│ │
119
- │ └──────────────────────────────────────────┘ │
120
- │ │
121
- │ ┌──────────────────────────────────────────┐ │
122
- │ │ TransportFactory │ │
123
- │ │ HttpTransport MessagingTransport │ │
124
- │ └──────────────────────────────────────────┘ │
125
- └──────────────────────────────────────────────────┘
100
+ TypeRoad follows a multi-tenant architecture designed for high isolation and developer productivity. The framework orchestrates the request lifecycle using three main internal layers: `RequestContext`, `OnRoadContainer` (DI), and the `Model/Repository` layer.
101
+
102
+ ### The "Matryoshka" Isolation Pattern
103
+
104
+ Isolation in runtime is achieved through a nested hierarchy that ensures one tenant's request never sees another's data or instances.
105
+
106
+ 1. **Nível 1: RequestContext (AsyncLocalStorage)**
107
+ - O `OnRoadExpress` envolve cada execução de rota em um bloco `requestContext.run()`.
108
+ - Atua como um "envelope" de memória global para a thread lógica atual, armazenando metadados como `tenantId`, `logger` e `appToken`.
109
+ - Permite que qualquer parte do sistema acesse o estado da requisição via `getRequestContext()` sem precisar de injeção manual.
110
+
111
+ 2. **Nível 2: OnRoadContainer (RequestScope)**
112
+ - Dentro do contexto da requisição, o Container cria um objeto `RequestScope`.
113
+ - Este escopo é um mapa de instâncias isolado por um `UUID` único para aquela chamada HTTP.
114
+ - Se múltiplos serviços injetarem o mesmo `Repository`, o Container garante que eles recebam a **mesma instância** dentro daquela requisição (reuso de estado), mas instâncias **completamente diferentes** de outras requisições concorrentes.
115
+
116
+ 3. **Nível 3: Repository & Connection Isolation**
117
+ - Repositórios são instanciados pelo Container e recebem automaticamente o `tenantId` do escopo atual.
118
+ - Ao executar uma query (ex: `find()`), o repositório usa seu atributo interno `this.tenant` para solicitar ao `ConnectionManager` o pool de conexões específico daquele banco de dados.
119
+ - Isso garante que o isolamento chegue até o nível físico do banco de dados (schema ou DB separado).
120
+
121
+ ```mermaid
122
+ graph TD
123
+ subgraph "Nível 1: RequestContext (AsyncLocalStorage)"
124
+ direction TB
125
+ Metadata["{ tenant: 'cliente_a', logger, token }"]
126
+
127
+ subgraph "Nível 2: OnRoadContainer (RequestScope)"
128
+ direction TB
129
+ ScopeID["Scope: UUID-123 (Tenant: 'cliente_a')"]
130
+ Instances["Map { Controller, Service, Repository }"]
131
+
132
+ subgraph "Nível 3: Instância do Repository"
133
+ direction TB
134
+ Atributo["this.tenant = 'cliente_a'"]
135
+ Metodo["getConnection() -> Pede ao ConnectionManager o banco 'onroad_cliente_a'"]
136
+ end
137
+ end
138
+ end
126
139
  ```
127
140
 
128
141
  ---
129
142
 
130
143
  ## DI Container & Decorators
131
144
 
132
- TypeRoad uses a decorator-based DI container with automatic class scanning.
145
+ TypeRoad uses a decorator-based DI container with automatic class scanning. It manages the lifecycle of your components through defined scopes.
133
146
 
134
147
  ### Decorators
135
148
 
136
- | Decorator | Scope | Purpose |
137
- |-----------|-------|---------|
138
- | `@Injectable()` | Transient (default) | Generic injectable class |
139
- | `@Controller("/path")` | Request | Express route handler |
140
- | `@Service()` | Request | Business logic layer |
141
- | `@Repository()` | Request | Data access layer |
149
+ | Decorator | Scope | Relationship | Purpose |
150
+ |-----------|-------|:---:|---------|
151
+ | `@Controller("/path")` | `REQUEST` | entry-point | Injetado com Services; lida com req/res Express. |
152
+ | `@Service()` | `REQUEST` | logic | Camada de orquestração e regras de negócio. |
153
+ | `@Repository()` | `REQUEST` | data | Camada de acesso ao banco (Sequelize/Mongoose). |
154
+ | `@Injectable()` | `TRANSIENT` | utility | Classes utilitárias instanciadas a cada uso. |
142
155
 
143
156
  ### Scopes
144
157
 
145
- | Scope | Behavior |
146
- |-------|----------|
147
- | `SINGLETON` | One instance for the entire application |
148
- | `REQUEST` | One instance per request scope |
149
- | `TRANSIENT` | New instance on every resolve |
158
+ - **`SINGLETON`**: Uma única instância para toda a aplicação (ex: `EventBus`, `ConnectionManager`).
159
+ - **`REQUEST`**: Uma instância por requisição HTTP. É o escopo padrão para Controllers e Services, garantindo que o estado do tenant esteja isolado.
160
+ - **`TRANSIENT`**: Uma nova instância é criada toda vez que a classe é injetada ou resolvida.
150
161
 
151
- ### Usage
162
+ ### Controller, Service and Repository linkage
163
+
164
+ The container manages a strict hierarchy: `Controller` -> `Service` -> `Repository`.
165
+
166
+ - **Automatic Wiring**: When you register a module via `app.register([MyController, MyService, MyRepository])`, the container scans the metadata and prepares the injection tree.
167
+ - **Stateful Injection**: A Repository inheriting from `SequelizeRepository` is automatically configured by the container with the current `tenant` and `connectionManager` during its instantiation in the `RequestScope`.
152
168
 
153
169
  ```ts
154
- import { Injectable, Scope } from "@onroad/core"
170
+ import { Service, AbstractService } from "@onroad/core"
155
171
 
156
- @Injectable({ scope: Scope.SINGLETON })
157
- class CacheManager {
158
- private store = new Map<string, unknown>()
159
- get(key: string) { return this.store.get(key) }
160
- set(key: string, value: unknown) { this.store.set(key, value) }
172
+ @Service()
173
+ class OrdemService extends AbstractService<OrdemRepository> {
174
+ constructor() {
175
+ // Shared state: the container ensures OrdemRepository
176
+ // is instantiated within the same RequestScope as this service.
177
+ super({ repository: OrdemRepository })
178
+ }
161
179
  }
162
180
  ```
163
181
 
164
- Register all classes via `app.register([...])` — the container auto-scans metadata.
165
-
166
182
  ---
167
183
 
168
184
  ## Controllers, Services & Repositories
@@ -8,6 +8,10 @@ export interface RouteConfig {
8
8
  }
9
9
  export interface ControllerConfig<TService> {
10
10
  service: Constructor<TService>;
11
+ /** Optional route prefix for auto-CRUD routes (e.g. "turno").
12
+ * Use when the controller is registered at @Controller("/") but needs context-aware paths.
13
+ * Do NOT set when the controller already uses @Controller("/turno"). */
14
+ prefix?: string;
11
15
  routes?: Record<string, RouteConfig>;
12
16
  }
13
17
  export declare abstract class AbstractController<TService = unknown> {
@@ -16,11 +20,6 @@ export declare abstract class AbstractController<TService = unknown> {
16
20
  constructor(config: ControllerConfig<TService>);
17
21
  setService(service: TService): void;
18
22
  getRoutes(): Record<string, RouteConfig>;
19
- /**
20
- * Derives a URL prefix from the service class name.
21
- * e.g. "TurnoService" → "/turno", "BranchLevelService" → "/branchLevel"
22
- */
23
- private inferPrefixFromServiceName;
24
23
  getServiceClass(): Constructor<TService>;
25
24
  create(req: any, res: any): Promise<any>;
26
25
  readAll(req: any, res: any): Promise<any>;
@@ -1 +1 @@
1
- {"version":3,"file":"AbstractController.d.ts","sourceRoot":"","sources":["../../src/core/AbstractController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAE5D,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAA;IACnD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC3B;AAED,MAAM,WAAW,gBAAgB,CAAC,QAAQ;IACxC,OAAO,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAA;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;CACrC;AAED,8BAAsB,kBAAkB,CAAC,QAAQ,GAAG,OAAO;IACzD,SAAS,CAAC,OAAO,EAAG,QAAQ,CAAA;IAC5B,SAAS,CAAC,MAAM,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAA;gBAEhC,MAAM,EAAE,gBAAgB,CAAC,QAAQ,CAAC;IAI9C,UAAU,CAAC,OAAO,EAAE,QAAQ,GAAG,IAAI;IAInC,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC;IA4BxC;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IAOlC,eAAe,IAAI,WAAW,CAAC,QAAQ,CAAC;IAIlC,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG;IAOzB,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG;IAO1B,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG;IAOvB,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG;IAOzB,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG;CAMhC"}
1
+ {"version":3,"file":"AbstractController.d.ts","sourceRoot":"","sources":["../../src/core/AbstractController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAE5D,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAA;IACnD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC3B;AAED,MAAM,WAAW,gBAAgB,CAAC,QAAQ;IACxC,OAAO,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAA;IAC9B;;4EAEwE;IACxE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;CACrC;AAED,8BAAsB,kBAAkB,CAAC,QAAQ,GAAG,OAAO;IACzD,SAAS,CAAC,OAAO,EAAG,QAAQ,CAAA;IAC5B,SAAS,CAAC,MAAM,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAA;gBAEhC,MAAM,EAAE,gBAAgB,CAAC,QAAQ,CAAC;IAI9C,UAAU,CAAC,OAAO,EAAE,QAAQ,GAAG,IAAI;IAInC,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC;IAuBxC,eAAe,IAAI,WAAW,CAAC,QAAQ,CAAC;IAIlC,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG;IAOzB,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG;IAO1B,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG;IAOvB,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG;IAOzB,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG;CAMhC"}
@@ -9,11 +9,7 @@ export class AbstractController {
9
9
  }
10
10
  getRoutes() {
11
11
  const explicitRoutes = this.config.routes ?? {};
12
- // Derive the route context prefix from the service class name.
13
- // e.g. TurnoService → /turno, BranchLevelService → /branchLevel
14
- // When controllers use @Controller("/"), this prevents auto-CRUD routes from
15
- // becoming catch-all /:id that intercept unrelated requests.
16
- const prefix = this.inferPrefixFromServiceName(this.config.service.name);
12
+ const prefix = this.config.prefix ? `/${this.config.prefix.replace(/^\//, "")}` : null;
17
13
  const autoConfig = prefix
18
14
  ? {
19
15
  create: { method: "post", path: prefix },
@@ -31,17 +27,6 @@ export class AbstractController {
31
27
  };
32
28
  return { ...autoConfig, ...explicitRoutes };
33
29
  }
34
- /**
35
- * Derives a URL prefix from the service class name.
36
- * e.g. "TurnoService" → "/turno", "BranchLevelService" → "/branchLevel"
37
- */
38
- inferPrefixFromServiceName(name) {
39
- const match = name.match(/^([A-Z][a-zA-Z0-9]*)Service$/);
40
- if (!match)
41
- return null;
42
- const entity = match[1];
43
- return "/" + entity.charAt(0).toLowerCase() + entity.slice(1);
44
- }
45
30
  getServiceClass() {
46
31
  return this.config.service;
47
32
  }
@@ -1 +1 @@
1
- {"version":3,"file":"AbstractController.js","sourceRoot":"","sources":["../../src/core/AbstractController.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AbstractController.js","sourceRoot":"","sources":["../../src/core/AbstractController.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import type { Request, Response } from "express";
2
+ export interface DevToolsConfig {
3
+ /** GCP project id */
4
+ projectId: string;
5
+ /** Cloud SQL instance name (short, e.g. "teraprox-postgres") */
6
+ instanceId: string;
7
+ /** GCS bucket for intermediate dump storage */
8
+ bucketName: string;
9
+ /** Default Cloud SQL source database name to export */
10
+ sourceDatabase: string;
11
+ /** Local database connection (the Docker dev DB) */
12
+ localDb: {
13
+ host: string;
14
+ port: number;
15
+ user: string;
16
+ password: string;
17
+ database: string;
18
+ };
19
+ /** Optional callback executed after restore finishes (e.g. run migrations) */
20
+ onAfterRestore?: () => Promise<void>;
21
+ }
22
+ /**
23
+ * Standalone route-handler class for the dev console.
24
+ * Routes are mounted directly by DevToolsPlugin (not via the DI container).
25
+ */
26
+ export declare class DevToolsController {
27
+ private config;
28
+ private currentRestore;
29
+ constructor(config: DevToolsConfig);
30
+ checkGcloudAuth: (_req: Request, res: Response) => Promise<void>;
31
+ listDatabases: (_req: Request, res: Response) => Promise<void>;
32
+ exportAndRestore: (req: Request, res: Response) => Promise<void>;
33
+ restoreStatus: (_req: Request, res: Response) => Promise<void>;
34
+ downloadLocalBackup: (_req: Request, res: Response) => Promise<void>;
35
+ renderDashboard: (_req: Request, res: Response) => Promise<void>;
36
+ private runRestore;
37
+ private buildHTML;
38
+ }
39
+ //# sourceMappingURL=DevToolsController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DevToolsController.d.ts","sourceRoot":"","sources":["../../src/dev/DevToolsController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAQhD,MAAM,WAAW,cAAc;IAC7B,qBAAqB;IACrB,SAAS,EAAE,MAAM,CAAA;IACjB,gEAAgE;IAChE,UAAU,EAAE,MAAM,CAAA;IAClB,+CAA+C;IAC/C,UAAU,EAAE,MAAM,CAAA;IAClB,uDAAuD;IACvD,cAAc,EAAE,MAAM,CAAA;IACtB,oDAAoD;IACpD,OAAO,EAAE;QACP,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,EAAE,MAAM,CAAA;QACZ,QAAQ,EAAE,MAAM,CAAA;QAChB,QAAQ,EAAE,MAAM,CAAA;KACjB,CAAA;IACD,8EAA8E;IAC9E,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CACrC;AAED;;;GAGG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,cAAc,CAGrB;gBAEW,MAAM,EAAE,cAAc;IAMlC,eAAe,GAAU,MAAM,OAAO,EAAE,KAAK,QAAQ,KAAG,OAAO,CAAC,IAAI,CAAC,CAUpE;IAED,aAAa,GAAU,MAAM,OAAO,EAAE,KAAK,QAAQ,KAAG,OAAO,CAAC,IAAI,CAAC,CAuBlE;IAED,gBAAgB,GAAU,KAAK,OAAO,EAAE,KAAK,QAAQ,KAAG,OAAO,CAAC,IAAI,CAAC,CAqBpE;IAED,aAAa,GACX,MAAM,OAAO,EACb,KAAK,QAAQ,KACZ,OAAO,CAAC,IAAI,CAAC,CAEf;IAED,mBAAmB,GACjB,MAAM,OAAO,EACb,KAAK,QAAQ,KACZ,OAAO,CAAC,IAAI,CAAC,CA2Bf;IAED,eAAe,GACb,MAAM,OAAO,EACb,KAAK,QAAQ,KACZ,OAAO,CAAC,IAAI,CAAC,CAEf;YAIa,UAAU;IAoGxB,OAAO,CAAC,SAAS;CAmIlB"}
@@ -0,0 +1,299 @@
1
+ import { exec } from "child_process";
2
+ import { promisify } from "util";
3
+ import fs from "fs";
4
+ import path from "path";
5
+ const execAsync = promisify(exec);
6
+ /**
7
+ * Standalone route-handler class for the dev console.
8
+ * Routes are mounted directly by DevToolsPlugin (not via the DI container).
9
+ */
10
+ export class DevToolsController {
11
+ config;
12
+ currentRestore = {
13
+ status: "idle",
14
+ step: "",
15
+ };
16
+ constructor(config) {
17
+ this.config = config;
18
+ }
19
+ // --- Route handlers (arrow fns to preserve `this`) ---
20
+ checkGcloudAuth = async (_req, res) => {
21
+ try {
22
+ await execAsync("gcloud auth print-access-token", { timeout: 10_000 });
23
+ const { stdout } = await execAsync("gcloud config get-value account", {
24
+ timeout: 5_000,
25
+ });
26
+ res.json({ authenticated: true, account: stdout.trim() });
27
+ }
28
+ catch {
29
+ res.json({ authenticated: false, account: null });
30
+ }
31
+ };
32
+ listDatabases = async (_req, res) => {
33
+ const { projectId, instanceId } = this.config;
34
+ try {
35
+ const { stdout } = await execAsync("gcloud sql databases list --instance=" +
36
+ instanceId +
37
+ " --project=" +
38
+ projectId +
39
+ ' --format="json"', { timeout: 30_000 });
40
+ const databases = JSON.parse(stdout)
41
+ .map((d) => d.name)
42
+ .filter((n) => !["postgres", "template0", "template1", "cloudsqladmin"].includes(n));
43
+ res.json({ success: true, databases });
44
+ }
45
+ catch (error) {
46
+ res.status(500).json({ success: false, error: error.message });
47
+ }
48
+ };
49
+ exportAndRestore = async (req, res) => {
50
+ const { database, dropExisting } = req.body;
51
+ const dbName = database || this.config.sourceDatabase;
52
+ if (this.currentRestore.status === "running") {
53
+ res
54
+ .status(409)
55
+ .json({ success: false, error: "Já existe um restore em andamento." });
56
+ return;
57
+ }
58
+ this.currentRestore = { status: "running", step: "Iniciando..." };
59
+ res.json({ success: true, message: "Restore iniciado." });
60
+ this.runRestore(dbName, !!dropExisting).catch((err) => {
61
+ this.currentRestore = {
62
+ status: "error",
63
+ step: "Falhou",
64
+ error: err.message,
65
+ };
66
+ });
67
+ };
68
+ restoreStatus = async (_req, res) => {
69
+ res.json(this.currentRestore);
70
+ };
71
+ downloadLocalBackup = async (_req, res) => {
72
+ const { localDb } = this.config;
73
+ const ts = new Date().toISOString().replace(/[:.]/g, "-");
74
+ const filename = "local_backup_" + localDb.database + "_" + ts + ".sql";
75
+ const filePath = path.join("/tmp", filename);
76
+ try {
77
+ const cmd = 'PGPASSWORD="' +
78
+ localDb.password +
79
+ '" pg_dump -h ' +
80
+ localDb.host +
81
+ " -p " +
82
+ localDb.port +
83
+ " -U " +
84
+ localDb.user +
85
+ " -d " +
86
+ localDb.database +
87
+ " -F p > " +
88
+ filePath;
89
+ await execAsync(cmd, { timeout: 120_000 });
90
+ res.download(filePath, filename, () => {
91
+ if (fs.existsSync(filePath))
92
+ fs.unlinkSync(filePath);
93
+ });
94
+ }
95
+ catch (error) {
96
+ res.status(500).json({ success: false, error: error.message });
97
+ }
98
+ };
99
+ renderDashboard = async (_req, res) => {
100
+ res.send(this.buildHTML());
101
+ };
102
+ // --- Background restore pipeline ---
103
+ async runRestore(sourceDb, dropExisting) {
104
+ const { projectId, instanceId, bucketName, localDb } = this.config;
105
+ const tempFileName = "restore_" + sourceDb + "_" + Date.now() + ".sql";
106
+ const gcsPath = "gs://" + bucketName + "/" + tempFileName;
107
+ const localPath = path.join("/tmp", tempFileName);
108
+ try {
109
+ // 1 — Export from Cloud SQL to GCS
110
+ this.currentRestore.step = "Exportando " + sourceDb + " do Cloud SQL...";
111
+ await execAsync("gcloud sql export sql " +
112
+ instanceId +
113
+ " " +
114
+ gcsPath +
115
+ " --database=" +
116
+ sourceDb +
117
+ " --project=" +
118
+ projectId +
119
+ " --quiet", { timeout: 600_000 });
120
+ // 2 — Download from GCS
121
+ this.currentRestore.step = "Baixando dump do GCS...";
122
+ await execAsync("gcloud storage cp " + gcsPath + " " + localPath, {
123
+ timeout: 300_000,
124
+ });
125
+ // 3 — Cleanup GCS (fire-and-forget)
126
+ execAsync("gcloud storage rm " + gcsPath).catch(() => { });
127
+ // 4 — Drop + recreate local DB
128
+ if (dropExisting) {
129
+ this.currentRestore.step = "Recriando banco local...";
130
+ const pgEnv = 'PGPASSWORD="' + localDb.password + '"';
131
+ const pgConn = "-h " + localDb.host + " -p " + localDb.port + " -U " + localDb.user;
132
+ // Terminate active connections
133
+ await execAsync(pgEnv +
134
+ " psql " +
135
+ pgConn +
136
+ " -d postgres -c \"SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '" +
137
+ localDb.database +
138
+ "' AND pid <> pg_backend_pid();\"", { timeout: 10_000 }).catch(() => { });
139
+ await execAsync(pgEnv + " dropdb " + pgConn + " --if-exists " + localDb.database, { timeout: 10_000 });
140
+ await execAsync(pgEnv + " createdb " + pgConn + " " + localDb.database, { timeout: 10_000 });
141
+ }
142
+ // 5 — Restore SQL dump into local DB
143
+ this.currentRestore.step = "Restaurando dump no banco local...";
144
+ await execAsync('PGPASSWORD="' +
145
+ localDb.password +
146
+ '" psql -h ' +
147
+ localDb.host +
148
+ " -p " +
149
+ localDb.port +
150
+ " -U " +
151
+ localDb.user +
152
+ " -d " +
153
+ localDb.database +
154
+ " -f " +
155
+ localPath, { timeout: 600_000 });
156
+ // 6 — Run migrations
157
+ if (this.config.onAfterRestore) {
158
+ this.currentRestore.step = "Rodando migrations...";
159
+ await this.config.onAfterRestore();
160
+ }
161
+ this.currentRestore = { status: "done", step: "Restore completo!" };
162
+ }
163
+ catch (error) {
164
+ this.currentRestore = {
165
+ status: "error",
166
+ step: "Falhou",
167
+ error: error.message,
168
+ };
169
+ }
170
+ finally {
171
+ if (fs.existsSync(localPath))
172
+ fs.unlinkSync(localPath);
173
+ }
174
+ }
175
+ // --- Dashboard HTML (string concat to avoid template-literal nesting) ---
176
+ buildHTML() {
177
+ var cfg = this.config;
178
+ var css = "* { box-sizing: border-box; margin: 0; padding: 0; }" +
179
+ 'body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; padding: 20px; background: #0f172a; color: #e2e8f0; min-height: 100vh; }' +
180
+ ".container { max-width: 720px; margin: 0 auto; }" +
181
+ "h1 { font-size: 24px; margin-bottom: 4px; color: #38bdf8; }" +
182
+ ".subtitle { color: #94a3b8; margin-bottom: 24px; font-size: 13px; }" +
183
+ ".card { background: #1e293b; border: 1px solid #334155; border-radius: 10px; padding: 20px; margin-bottom: 16px; }" +
184
+ ".card h2 { font-size: 15px; color: #94a3b8; margin-bottom: 12px; text-transform: uppercase; letter-spacing: 0.5px; }" +
185
+ ".badge { display: inline-block; padding: 3px 10px; border-radius: 9999px; font-size: 12px; font-weight: 600; }" +
186
+ ".badge-ok { background: #065f46; color: #34d399; }" +
187
+ ".badge-err { background: #7f1d1d; color: #fca5a5; }" +
188
+ ".badge-warn { background: #78350f; color: #fbbf24; }" +
189
+ ".info-grid { display: grid; grid-template-columns: 120px 1fr; gap: 6px 12px; font-size: 13px; margin: 12px 0; }" +
190
+ ".info-grid dt { color: #64748b; }" +
191
+ '.info-grid dd { color: #cbd5e1; font-family: "SF Mono", Monaco, monospace; }' +
192
+ ".btn { border: none; padding: 10px 20px; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 600; transition: all 0.15s; }" +
193
+ ".btn:disabled { opacity: 0.5; cursor: not-allowed; }" +
194
+ ".btn-primary { background: #2563eb; color: white; }" +
195
+ ".btn-primary:hover:not(:disabled) { background: #1d4ed8; }" +
196
+ ".btn-outline { background: transparent; border: 1px solid #475569; color: #cbd5e1; }" +
197
+ ".btn-outline:hover:not(:disabled) { background: #334155; }" +
198
+ ".btn-sm { padding: 6px 14px; font-size: 12px; }" +
199
+ "select { background: #0f172a; color: #e2e8f0; border: 1px solid #475569; padding: 8px 12px; border-radius: 6px; font-size: 13px; width: 100%; }" +
200
+ ".progress { margin-top: 16px; padding: 14px; background: #0f172a; border-radius: 8px; border: 1px solid #334155; display: none; }" +
201
+ ".progress.active { display: block; }" +
202
+ ".progress .step { color: #38bdf8; font-weight: 600; font-size: 13px; }" +
203
+ ".progress .substep { color: #64748b; font-size: 12px; margin-top: 4px; }" +
204
+ ".progress-bar { height: 4px; background: #334155; border-radius: 2px; margin-top: 10px; overflow: hidden; }" +
205
+ ".progress-bar-fill { height: 100%; background: #2563eb; border-radius: 2px; transition: width 0.5s; }" +
206
+ ".actions { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-top: 12px; }" +
207
+ '.checkbox-label { font-size: 13px; color: #94a3b8; display: flex; align-items: center; gap: 6px; cursor: pointer; }' +
208
+ ".row { display: flex; gap: 8px; align-items: center; }" +
209
+ ".separator { border-top: 1px solid #334155; margin: 16px 0; }";
210
+ var body = '<div class="container">' +
211
+ "<h1>OnRoad Dev Console</h1>" +
212
+ '<p class="subtitle">Gerenciamento de banco para desenvolvimento local</p>' +
213
+ // Auth card
214
+ '<div class="card"><h2>Cloud SDK</h2>' +
215
+ '<div class="row">' +
216
+ '<span id="auth-badge" class="badge badge-warn">verificando...</span>' +
217
+ '<span id="auth-account" style="font-size:13px; color:#94a3b8;"></span>' +
218
+ "</div></div>" +
219
+ // Local DB card
220
+ '<div class="card"><h2>Banco Local</h2>' +
221
+ '<dl class="info-grid">' +
222
+ "<dt>Host</dt><dd>" + cfg.localDb.host + ":" + cfg.localDb.port + "</dd>" +
223
+ "<dt>Database</dt><dd>" + cfg.localDb.database + "</dd>" +
224
+ "<dt>User</dt><dd>" + cfg.localDb.user + "</dd>" +
225
+ "</dl>" +
226
+ '<a href="/dev/db/backup/local" class="btn btn-outline btn-sm">Exportar SQL Local</a>' +
227
+ "</div>" +
228
+ // GCP Restore card
229
+ '<div class="card"><h2>Restaurar do GCP</h2>' +
230
+ '<p style="font-size:13px; color:#64748b; margin-bottom:12px;">' +
231
+ 'Instância <strong style="color:#cbd5e1;">' + cfg.instanceId + "</strong> " +
232
+ 'no projeto <strong style="color:#cbd5e1;">' + cfg.projectId + "</strong>" +
233
+ "</p>" +
234
+ '<label style="display:block; font-size:13px; color:#94a3b8; margin-bottom:6px;">Banco de origem:</label>' +
235
+ '<div class="row">' +
236
+ '<select id="db-select"><option value="' + cfg.sourceDatabase + '">' + cfg.sourceDatabase + " (padrão)</option></select>" +
237
+ '<button onclick="loadDatabases()" class="btn btn-outline btn-sm" id="btn-load-dbs">Atualizar</button>' +
238
+ "</div>" +
239
+ '<div class="separator"></div>' +
240
+ '<div class="actions">' +
241
+ '<label class="checkbox-label"><input type="checkbox" id="drop-check" checked> Limpar banco local antes de restaurar</label>' +
242
+ "</div>" +
243
+ '<div class="actions">' +
244
+ '<button onclick="startRestore()" class="btn btn-primary" id="btn-restore">Restaurar Agora</button>' +
245
+ "</div>" +
246
+ '<div class="progress" id="progress">' +
247
+ '<div class="step" id="progress-step">Preparando...</div>' +
248
+ '<div class="substep" id="progress-substep"></div>' +
249
+ '<div class="progress-bar"><div class="progress-bar-fill" id="progress-fill" style="width:0%"></div></div>' +
250
+ "</div></div>" +
251
+ "</div>";
252
+ var js = "async function checkAuth(){" +
253
+ 'var b=document.getElementById("auth-badge"),a=document.getElementById("auth-account");' +
254
+ 'try{var r=await fetch("/dev/db/auth/status");var d=await r.json();' +
255
+ 'if(d.authenticated){b.className="badge badge-ok";b.textContent="autenticado";a.textContent=d.account;}' +
256
+ 'else{b.className="badge badge-err";b.textContent="não autenticado";a.textContent="Execute: gcloud auth login";}' +
257
+ '}catch(e){b.className="badge badge-err";b.textContent="erro";}}' +
258
+ "checkAuth();" +
259
+ "async function loadDatabases(){" +
260
+ 'var btn=document.getElementById("btn-load-dbs");var sel=document.getElementById("db-select");btn.disabled=true;' +
261
+ 'try{var r=await fetch("/dev/db/databases");var d=await r.json();' +
262
+ "if(d.success){var cur=sel.value;sel.innerHTML=d.databases.map(function(db){" +
263
+ "return \"<option value='\" + db + \"'\" + (db===cur?\" selected\":\"\") + \">\" + db + \"</option>\";}).join(\"\");}" +
264
+ '}catch(e){alert("Erro: "+e.message);}btn.disabled=false;}' +
265
+ "var pollId=null;" +
266
+ "async function startRestore(){" +
267
+ 'var db=document.getElementById("db-select").value;' +
268
+ 'var drop=document.getElementById("drop-check").checked;' +
269
+ 'var btn=document.getElementById("btn-restore");' +
270
+ "if(!confirm(\"Restaurar '\" + db + \"' do GCP para o banco local?\" + (drop?\" O banco local será APAGADO primeiro.\":\"\")))return;" +
271
+ 'btn.disabled=true;document.getElementById("progress").classList.add("active");' +
272
+ 'document.getElementById("progress-fill").style.width="5%";' +
273
+ 'document.getElementById("progress-fill").style.background="#2563eb";' +
274
+ 'document.getElementById("progress-step").style.color="#38bdf8";' +
275
+ 'try{var r=await fetch("/dev/db/restore",{method:"POST",headers:{"Content-Type":"application/json"},' +
276
+ "body:JSON.stringify({database:db,dropExisting:drop})});var d=await r.json();" +
277
+ 'if(!d.success){alert("Erro: "+d.error);btn.disabled=false;return;}' +
278
+ "pollId=setInterval(pollStatus,2000);" +
279
+ '}catch(e){alert("Falha: "+e.message);btn.disabled=false;}}' +
280
+ "async function pollStatus(){" +
281
+ 'try{var r=await fetch("/dev/db/restore/status");var d=await r.json();' +
282
+ 'var s=document.getElementById("progress-step");var sub=document.getElementById("progress-substep");' +
283
+ 'var fill=document.getElementById("progress-fill");var btn=document.getElementById("btn-restore");' +
284
+ "s.textContent=d.step;" +
285
+ 'if(d.status==="running"){var m={"Exportando":20,"Baixando":40,"Recriando":55,"Restaurando":70,"Rodando":90};' +
286
+ "var pct=10;for(var k in m){if(d.step.indexOf(k)>=0)pct=m[k];}fill.style.width=pct+\"%\";}" +
287
+ 'else if(d.status==="done"){fill.style.width="100%";fill.style.background="#22c55e";' +
288
+ 's.style.color="#22c55e";sub.textContent="Banco local atualizado com sucesso!";clearInterval(pollId);btn.disabled=false;}' +
289
+ 'else if(d.status==="error"){fill.style.width="100%";fill.style.background="#ef4444";' +
290
+ 's.style.color="#ef4444";sub.textContent=d.error||"Erro desconhecido";clearInterval(pollId);btn.disabled=false;}' +
291
+ "}catch(e){}}";
292
+ return ('<!DOCTYPE html><html lang="pt-br"><head><meta charset="UTF-8">' +
293
+ "<title>OnRoad Dev Console</title>" +
294
+ "<style>" + css + "</style></head>" +
295
+ "<body>" + body +
296
+ "<script>" + js + "</script></body></html>");
297
+ }
298
+ }
299
+ //# sourceMappingURL=DevToolsController.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DevToolsController.js","sourceRoot":"","sources":["../../src/dev/DevToolsController.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAA;AAChC,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,IAAI,MAAM,MAAM,CAAA;AAEvB,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;AAuBjC;;;GAGG;AACH,MAAM,OAAO,kBAAkB;IACrB,MAAM,CAAgB;IACtB,cAAc,GAAqD;QACzE,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,EAAE;KACT,CAAA;IAED,YAAY,MAAsB;QAChC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;IACtB,CAAC;IAED,wDAAwD;IAExD,eAAe,GAAG,KAAK,EAAE,IAAa,EAAE,GAAa,EAAiB,EAAE;QACtE,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,gCAAgC,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAA;YACtE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,iCAAiC,EAAE;gBACpE,OAAO,EAAE,KAAK;aACf,CAAC,CAAA;YACF,GAAG,CAAC,IAAI,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;QAC3D,CAAC;QAAC,MAAM,CAAC;YACP,GAAG,CAAC,IAAI,CAAC,EAAE,aAAa,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;QACnD,CAAC;IACH,CAAC,CAAA;IAED,aAAa,GAAG,KAAK,EAAE,IAAa,EAAE,GAAa,EAAiB,EAAE;QACpE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,MAAM,CAAA;QAC7C,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAChC,uCAAuC;gBACrC,UAAU;gBACV,aAAa;gBACb,SAAS;gBACT,kBAAkB,EACpB,EAAE,OAAO,EAAE,MAAM,EAAE,CACpB,CAAA;YACD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;iBACjC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;iBACvB,MAAM,CACL,CAAC,CAAS,EAAE,EAAE,CACZ,CAAC,CAAC,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,eAAe,CAAC,CAAC,QAAQ,CAC/D,CAAC,CACF,CACJ,CAAA;YACH,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAA;QACxC,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;QAChE,CAAC;IACH,CAAC,CAAA;IAED,gBAAgB,GAAG,KAAK,EAAE,GAAY,EAAE,GAAa,EAAiB,EAAE;QACtE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,GAAG,CAAC,IAAI,CAAA;QAC3C,MAAM,MAAM,GAAG,QAAQ,IAAI,IAAI,CAAC,MAAM,CAAC,cAAc,CAAA;QAErD,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC7C,GAAG;iBACA,MAAM,CAAC,GAAG,CAAC;iBACX,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,oCAAoC,EAAE,CAAC,CAAA;YACxE,OAAM;QACR,CAAC;QAED,IAAI,CAAC,cAAc,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,cAAc,EAAE,CAAA;QACjE,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC,CAAA;QAEzD,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACpD,IAAI,CAAC,cAAc,GAAG;gBACpB,MAAM,EAAE,OAAO;gBACf,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,GAAG,CAAC,OAAO;aACnB,CAAA;QACH,CAAC,CAAC,CAAA;IACJ,CAAC,CAAA;IAED,aAAa,GAAG,KAAK,EACnB,IAAa,EACb,GAAa,EACE,EAAE;QACjB,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;IAC/B,CAAC,CAAA;IAED,mBAAmB,GAAG,KAAK,EACzB,IAAa,EACb,GAAa,EACE,EAAE;QACjB,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,MAAM,CAAA;QAC/B,MAAM,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;QACzD,MAAM,QAAQ,GAAG,eAAe,GAAG,OAAO,CAAC,QAAQ,GAAG,GAAG,GAAG,EAAE,GAAG,MAAM,CAAA;QACvE,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;QAE5C,IAAI,CAAC;YACH,MAAM,GAAG,GACP,cAAc;gBACd,OAAO,CAAC,QAAQ;gBAChB,eAAe;gBACf,OAAO,CAAC,IAAI;gBACZ,MAAM;gBACN,OAAO,CAAC,IAAI;gBACZ,MAAM;gBACN,OAAO,CAAC,IAAI;gBACZ,MAAM;gBACN,OAAO,CAAC,QAAQ;gBAChB,UAAU;gBACV,QAAQ,CAAA;YACV,MAAM,SAAS,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAA;YAC1C,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE;gBACpC,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;oBAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAA;YACtD,CAAC,CAAC,CAAA;QACJ,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;QAChE,CAAC;IACH,CAAC,CAAA;IAED,eAAe,GAAG,KAAK,EACrB,IAAa,EACb,GAAa,EACE,EAAE;QACjB,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAA;IAC5B,CAAC,CAAA;IAED,sCAAsC;IAE9B,KAAK,CAAC,UAAU,CACtB,QAAgB,EAChB,YAAqB;QAErB,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,MAAM,CAAA;QAClE,MAAM,YAAY,GAAG,UAAU,GAAG,QAAQ,GAAG,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAA;QACtE,MAAM,OAAO,GAAG,OAAO,GAAG,UAAU,GAAG,GAAG,GAAG,YAAY,CAAA;QACzD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;QAEjD,IAAI,CAAC;YACH,mCAAmC;YACnC,IAAI,CAAC,cAAc,CAAC,IAAI,GAAG,aAAa,GAAG,QAAQ,GAAG,kBAAkB,CAAA;YACxE,MAAM,SAAS,CACb,wBAAwB;gBACtB,UAAU;gBACV,GAAG;gBACH,OAAO;gBACP,cAAc;gBACd,QAAQ;gBACR,aAAa;gBACb,SAAS;gBACT,UAAU,EACZ,EAAE,OAAO,EAAE,OAAO,EAAE,CACrB,CAAA;YAED,wBAAwB;YACxB,IAAI,CAAC,cAAc,CAAC,IAAI,GAAG,yBAAyB,CAAA;YACpD,MAAM,SAAS,CAAC,oBAAoB,GAAG,OAAO,GAAG,GAAG,GAAG,SAAS,EAAE;gBAChE,OAAO,EAAE,OAAO;aACjB,CAAC,CAAA;YAEF,oCAAoC;YACpC,SAAS,CAAC,oBAAoB,GAAG,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;YAEzD,+BAA+B;YAC/B,IAAI,YAAY,EAAE,CAAC;gBACjB,IAAI,CAAC,cAAc,CAAC,IAAI,GAAG,0BAA0B,CAAA;gBACrD,MAAM,KAAK,GAAG,cAAc,GAAG,OAAO,CAAC,QAAQ,GAAG,GAAG,CAAA;gBACrD,MAAM,MAAM,GACV,KAAK,GAAG,OAAO,CAAC,IAAI,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAA;gBAEtE,+BAA+B;gBAC/B,MAAM,SAAS,CACb,KAAK;oBACH,QAAQ;oBACR,MAAM;oBACN,4FAA4F;oBAC5F,OAAO,CAAC,QAAQ;oBAChB,kCAAkC,EACpC,EAAE,OAAO,EAAE,MAAM,EAAE,CACpB,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;gBAEjB,MAAM,SAAS,CACb,KAAK,GAAG,UAAU,GAAG,MAAM,GAAG,eAAe,GAAG,OAAO,CAAC,QAAQ,EAChE,EAAE,OAAO,EAAE,MAAM,EAAE,CACpB,CAAA;gBACD,MAAM,SAAS,CACb,KAAK,GAAG,YAAY,GAAG,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,QAAQ,EACtD,EAAE,OAAO,EAAE,MAAM,EAAE,CACpB,CAAA;YACH,CAAC;YAED,qCAAqC;YACrC,IAAI,CAAC,cAAc,CAAC,IAAI,GAAG,oCAAoC,CAAA;YAC/D,MAAM,SAAS,CACb,cAAc;gBACZ,OAAO,CAAC,QAAQ;gBAChB,YAAY;gBACZ,OAAO,CAAC,IAAI;gBACZ,MAAM;gBACN,OAAO,CAAC,IAAI;gBACZ,MAAM;gBACN,OAAO,CAAC,IAAI;gBACZ,MAAM;gBACN,OAAO,CAAC,QAAQ;gBAChB,MAAM;gBACN,SAAS,EACX,EAAE,OAAO,EAAE,OAAO,EAAE,CACrB,CAAA;YAED,qBAAqB;YACrB,IAAI,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;gBAC/B,IAAI,CAAC,cAAc,CAAC,IAAI,GAAG,uBAAuB,CAAA;gBAClD,MAAM,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAA;YACpC,CAAC;YAED,IAAI,CAAC,cAAc,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,EAAE,CAAA;QACrE,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,IAAI,CAAC,cAAc,GAAG;gBACpB,MAAM,EAAE,OAAO;gBACf,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,KAAK,CAAC,OAAO;aACrB,CAAA;QACH,CAAC;gBAAS,CAAC;YACT,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC;gBAAE,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAA;QACxD,CAAC;IACH,CAAC;IAED,2EAA2E;IAEnE,SAAS;QACf,IAAI,GAAG,GAAG,IAAI,CAAC,MAAM,CAAA;QAErB,IAAI,GAAG,GACL,sDAAsD;YACtD,iKAAiK;YACjK,kDAAkD;YAClD,6DAA6D;YAC7D,qEAAqE;YACrE,oHAAoH;YACpH,sHAAsH;YACtH,gHAAgH;YAChH,oDAAoD;YACpD,qDAAqD;YACrD,sDAAsD;YACtD,iHAAiH;YACjH,mCAAmC;YACnC,8EAA8E;YAC9E,2IAA2I;YAC3I,sDAAsD;YACtD,qDAAqD;YACrD,4DAA4D;YAC5D,sFAAsF;YACtF,4DAA4D;YAC5D,iDAAiD;YACjD,iJAAiJ;YACjJ,mIAAmI;YACnI,sCAAsC;YACtC,wEAAwE;YACxE,0EAA0E;YAC1E,6GAA6G;YAC7G,uGAAuG;YACvG,gGAAgG;YAChG,qHAAqH;YACrH,wDAAwD;YACxD,+DAA+D,CAAA;QAEjE,IAAI,IAAI,GACN,yBAAyB;YACzB,6BAA6B;YAC7B,2EAA2E;YAC3E,YAAY;YACZ,sCAAsC;YACtC,mBAAmB;YACnB,sEAAsE;YACtE,wEAAwE;YACxE,cAAc;YACd,gBAAgB;YAChB,wCAAwC;YACxC,wBAAwB;YACxB,mBAAmB,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,GAAG,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,GAAG,OAAO;YACzE,uBAAuB,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,GAAG,OAAO;YACxD,mBAAmB,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,GAAG,OAAO;YAChD,OAAO;YACP,sFAAsF;YACtF,QAAQ;YACR,mBAAmB;YACnB,6CAA6C;YAC7C,gEAAgE;YAChE,2CAA2C,GAAG,GAAG,CAAC,UAAU,GAAG,YAAY;YAC3E,4CAA4C,GAAG,GAAG,CAAC,SAAS,GAAG,WAAW;YAC1E,MAAM;YACN,0GAA0G;YAC1G,mBAAmB;YACnB,wCAAwC,GAAG,GAAG,CAAC,cAAc,GAAG,IAAI,GAAG,GAAG,CAAC,cAAc,GAAG,6BAA6B;YACzH,uGAAuG;YACvG,QAAQ;YACR,+BAA+B;YAC/B,uBAAuB;YACvB,6HAA6H;YAC7H,QAAQ;YACR,uBAAuB;YACvB,oGAAoG;YACpG,QAAQ;YACR,sCAAsC;YACtC,0DAA0D;YAC1D,mDAAmD;YACnD,2GAA2G;YAC3G,cAAc;YACd,QAAQ,CAAA;QAEV,IAAI,EAAE,GACJ,6BAA6B;YAC7B,wFAAwF;YACxF,oEAAoE;YACpE,wGAAwG;YACxG,iHAAiH;YACjH,iEAAiE;YACjE,cAAc;YACd,iCAAiC;YACjC,iHAAiH;YACjH,kEAAkE;YAClE,6EAA6E;YAC7E,sHAAsH;YACtH,2DAA2D;YAC3D,kBAAkB;YAClB,gCAAgC;YAChC,oDAAoD;YACpD,yDAAyD;YACzD,iDAAiD;YACjD,sIAAsI;YACtI,gFAAgF;YAChF,4DAA4D;YAC5D,sEAAsE;YACtE,iEAAiE;YACjE,qGAAqG;YACrG,8EAA8E;YAC9E,oEAAoE;YACpE,sCAAsC;YACtC,4DAA4D;YAC5D,8BAA8B;YAC9B,uEAAuE;YACvE,qGAAqG;YACrG,mGAAmG;YACnG,uBAAuB;YACvB,8GAA8G;YAC9G,2FAA2F;YAC3F,qFAAqF;YACrF,0HAA0H;YAC1H,sFAAsF;YACtF,iHAAiH;YACjH,cAAc,CAAA;QAEhB,OAAO,CACL,gEAAgE;YAChE,mCAAmC;YACnC,SAAS,GAAG,GAAG,GAAG,iBAAiB;YACnC,QAAQ,GAAG,IAAI;YACf,UAAU,GAAG,EAAE,GAAG,yBAAyB,CAC5C,CAAA;IACH,CAAC;CACF"}
@@ -0,0 +1,10 @@
1
+ import type { OnRoadExpress } from "../OnRoadExpress.js";
2
+ import type { OnRoadPlugin } from "../plugins/OnRoadPlugin.js";
3
+ import type { DevToolsConfig } from "./DevToolsController.js";
4
+ export declare class DevToolsPlugin implements OnRoadPlugin {
5
+ name: string;
6
+ private config;
7
+ constructor(config: DevToolsConfig);
8
+ install(app: OnRoadExpress): Promise<void>;
9
+ }
10
+ //# sourceMappingURL=DevToolsPlugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DevToolsPlugin.d.ts","sourceRoot":"","sources":["../../src/dev/DevToolsPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAE9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAE7D,qBAAa,cAAe,YAAW,YAAY;IACjD,IAAI,SAAmB;IAEvB,OAAO,CAAC,MAAM,CAAgB;gBAElB,MAAM,EAAE,cAAc;IAI5B,OAAO,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;CAiBjD"}
@@ -0,0 +1,23 @@
1
+ import { DevToolsController } from "./DevToolsController.js";
2
+ export class DevToolsPlugin {
3
+ name = "DevToolsPlugin";
4
+ config;
5
+ constructor(config) {
6
+ this.config = config;
7
+ }
8
+ async install(app) {
9
+ if (process.env.NODE_ENV === "production" && !process.env.FORCE_DEV_TOOLS) {
10
+ return;
11
+ }
12
+ const ctrl = new DevToolsController(this.config);
13
+ const express = app.app;
14
+ express.get("/dev/db/dashboard", ctrl.renderDashboard);
15
+ express.get("/dev/db/auth/status", ctrl.checkGcloudAuth);
16
+ express.get("/dev/db/databases", ctrl.listDatabases);
17
+ express.get("/dev/db/backup/local", ctrl.downloadLocalBackup);
18
+ express.post("/dev/db/restore", ctrl.exportAndRestore);
19
+ express.get("/dev/db/restore/status", ctrl.restoreStatus);
20
+ app.logger.info("[DevToolsPlugin] Dev console available at /dev/db/dashboard");
21
+ }
22
+ }
23
+ //# sourceMappingURL=DevToolsPlugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DevToolsPlugin.js","sourceRoot":"","sources":["../../src/dev/DevToolsPlugin.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAG5D,MAAM,OAAO,cAAc;IACzB,IAAI,GAAG,gBAAgB,CAAA;IAEf,MAAM,CAAgB;IAE9B,YAAY,MAAsB;QAChC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;IACtB,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,GAAkB;QAC9B,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,CAAC;YAC1E,OAAM;QACR,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAChD,MAAM,OAAO,GAAG,GAAG,CAAC,GAAG,CAAA;QAEvB,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,IAAI,CAAC,eAAe,CAAC,CAAA;QACtD,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,IAAI,CAAC,eAAe,CAAC,CAAA;QACxD,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,IAAI,CAAC,aAAa,CAAC,CAAA;QACpD,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,IAAI,CAAC,mBAAmB,CAAC,CAAA;QAC7D,OAAO,CAAC,IAAI,CAAC,iBAAiB,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAA;QACtD,OAAO,CAAC,GAAG,CAAC,wBAAwB,EAAE,IAAI,CAAC,aAAa,CAAC,CAAA;QAEzD,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,6DAA6D,CAAC,CAAA;IAChF,CAAC;CACF"}
@@ -2,4 +2,7 @@ export { DevServer } from "./DevServer.js";
2
2
  export type { DevServerConfig, DevDatabaseConfig, GcpRestoreConfig } from "./DevServer.js";
3
3
  export { MigrationCLI } from "./MigrationCLI.js";
4
4
  export type { MigrationCLIConfig } from "./MigrationCLI.js";
5
+ export { DevToolsController } from "./DevToolsController.js";
6
+ export type { DevToolsConfig } from "./DevToolsController.js";
7
+ export { DevToolsPlugin } from "./DevToolsPlugin.js";
5
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/dev/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAE1F,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/dev/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAE1F,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAE3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAC5D,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA"}
package/dist/dev/index.js CHANGED
@@ -1,3 +1,5 @@
1
1
  export { DevServer } from "./DevServer.js";
2
2
  export { MigrationCLI } from "./MigrationCLI.js";
3
+ export { DevToolsController } from "./DevToolsController.js";
4
+ export { DevToolsPlugin } from "./DevToolsPlugin.js";
3
5
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/dev/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAG1C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/dev/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAG1C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGhD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAE5D,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA"}
package/dist/index.d.ts CHANGED
@@ -24,6 +24,6 @@ export { PinoLogger } from "./logging/index.js";
24
24
  export type { OnRoadLogger, PinoLoggerConfig } from "./logging/index.js";
25
25
  export type { OnRoadPlugin } from "./plugins/index.js";
26
26
  export { StorageProvider } from "./storage/index.js";
27
- export { DevServer, MigrationCLI } from "./dev/index.js";
28
- export type { DevServerConfig, DevDatabaseConfig, MigrationCLIConfig } from "./dev/index.js";
27
+ export { DevServer, MigrationCLI, DevToolsController, DevToolsPlugin } from "./dev/index.js";
28
+ export type { DevServerConfig, DevDatabaseConfig, MigrationCLIConfig, DevToolsConfig } from "./dev/index.js";
29
29
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,kBAAkB,CAAA;AACzB,OAAO,4BAA4B,CAAA;AAGnC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAGzE,OAAO,EACL,eAAe,EACf,UAAU,EACV,UAAU,EACV,OAAO,EACP,UAAU,EACV,KAAK,EACL,YAAY,GACb,MAAM,sBAAsB,CAAA;AAC7B,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAGpF,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,QAAQ,EACR,eAAe,GAChB,MAAM,iBAAiB,CAAA;AACxB,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,aAAa,EAAE,eAAe,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAG5I,OAAO,EACL,MAAM,EACN,MAAM,EACN,KAAK,EACL,OAAO,EACP,SAAS,EACT,MAAM,EACN,aAAa,EACb,QAAQ,EACR,cAAc,GACf,MAAM,mBAAmB,CAAA;AAC1B,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAGxG,OAAO,EACL,YAAY,EACZ,WAAW,EACX,MAAM,EACN,gBAAgB,EAChB,oBAAoB,EACpB,UAAU,EACV,SAAS,EACT,YAAY,EACZ,UAAU,EACV,oBAAoB,GACrB,MAAM,oBAAoB,CAAA;AAC3B,YAAY,EACV,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,EACjB,2BAA2B,GAC5B,MAAM,oBAAoB,CAAA;AAG3B,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAG7D,OAAO,EAAE,iBAAiB,EAAE,0BAA0B,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAC3G,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAG1E,OAAO,EACL,qBAAqB,EACrB,aAAa,EACb,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,sBAAsB,CAAA;AAC7B,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAGvD,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AAC/E,YAAY,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AAGtE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAGrD,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,EACrB,cAAc,GACf,MAAM,sBAAsB,CAAA;AAC7B,YAAY,EACV,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,sBAAsB,CAAA;AAG7B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAC/C,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAGxE,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAGtD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAGpD,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AACxD,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,kBAAkB,CAAA;AACzB,OAAO,4BAA4B,CAAA;AAGnC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAGzE,OAAO,EACL,eAAe,EACf,UAAU,EACV,UAAU,EACV,OAAO,EACP,UAAU,EACV,KAAK,EACL,YAAY,GACb,MAAM,sBAAsB,CAAA;AAC7B,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAGpF,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,QAAQ,EACR,eAAe,GAChB,MAAM,iBAAiB,CAAA;AACxB,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,aAAa,EAAE,eAAe,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAG5I,OAAO,EACL,MAAM,EACN,MAAM,EACN,KAAK,EACL,OAAO,EACP,SAAS,EACT,MAAM,EACN,aAAa,EACb,QAAQ,EACR,cAAc,GACf,MAAM,mBAAmB,CAAA;AAC1B,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAGxG,OAAO,EACL,YAAY,EACZ,WAAW,EACX,MAAM,EACN,gBAAgB,EAChB,oBAAoB,EACpB,UAAU,EACV,SAAS,EACT,YAAY,EACZ,UAAU,EACV,oBAAoB,GACrB,MAAM,oBAAoB,CAAA;AAC3B,YAAY,EACV,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,EACjB,2BAA2B,GAC5B,MAAM,oBAAoB,CAAA;AAG3B,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAG7D,OAAO,EAAE,iBAAiB,EAAE,0BAA0B,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAC3G,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAG1E,OAAO,EACL,qBAAqB,EACrB,aAAa,EACb,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,sBAAsB,CAAA;AAC7B,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAGvD,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AAC/E,YAAY,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AAGtE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAGrD,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,EACrB,cAAc,GACf,MAAM,sBAAsB,CAAA;AAC7B,YAAY,EACV,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,sBAAsB,CAAA;AAG7B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAC/C,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAGxE,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAGtD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAGpD,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC5F,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA"}
package/dist/index.js CHANGED
@@ -29,5 +29,5 @@ export { PinoLogger } from "./logging/index.js";
29
29
  // --- Storage ---
30
30
  export { StorageProvider } from "./storage/index.js";
31
31
  // --- Dev Tools ---
32
- export { DevServer, MigrationCLI } from "./dev/index.js";
32
+ export { DevServer, MigrationCLI, DevToolsController, DevToolsPlugin } from "./dev/index.js";
33
33
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,kBAAkB;AAElB,OAAO,kBAAkB,CAAA;AACzB,OAAO,4BAA4B,CAAA;AAEnC,eAAe;AACf,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAGlD,iCAAiC;AACjC,OAAO,EACL,eAAe,EACf,UAAU,EACV,UAAU,EACV,OAAO,EACP,UAAU,EACV,KAAK,EACL,YAAY,GACb,MAAM,sBAAsB,CAAA;AAG7B,eAAe;AACf,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,QAAQ,EACR,eAAe,GAChB,MAAM,iBAAiB,CAAA;AAGxB,iBAAiB;AACjB,OAAO,EACL,MAAM,EACN,MAAM,EACN,KAAK,EACL,OAAO,EACP,SAAS,EACT,MAAM,EACN,aAAa,EACb,QAAQ,EACR,cAAc,GACf,MAAM,mBAAmB,CAAA;AAG1B,kBAAkB;AAClB,OAAO,EACL,YAAY,EACZ,WAAW,EACX,MAAM,EACN,gBAAgB,EAChB,oBAAoB,EACpB,UAAU,EACV,SAAS,EACT,YAAY,EACZ,UAAU,EACV,oBAAoB,GACrB,MAAM,oBAAoB,CAAA;AAW3B,mBAAmB;AACnB,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAE7D,mBAAmB;AACnB,OAAO,EAAE,iBAAiB,EAAE,0BAA0B,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAG3G,oBAAoB;AACpB,OAAO,EACL,qBAAqB,EACrB,aAAa,EACb,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,sBAAsB,CAAA;AAG7B,0BAA0B;AAC1B,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AAG/E,oBAAoB;AACpB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAErD,oBAAoB;AACpB,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,EACrB,cAAc,GACf,MAAM,sBAAsB,CAAA;AAQ7B,kBAAkB;AAClB,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAM/C,kBAAkB;AAClB,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAEpD,oBAAoB;AACpB,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,kBAAkB;AAElB,OAAO,kBAAkB,CAAA;AACzB,OAAO,4BAA4B,CAAA;AAEnC,eAAe;AACf,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAGlD,iCAAiC;AACjC,OAAO,EACL,eAAe,EACf,UAAU,EACV,UAAU,EACV,OAAO,EACP,UAAU,EACV,KAAK,EACL,YAAY,GACb,MAAM,sBAAsB,CAAA;AAG7B,eAAe;AACf,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,QAAQ,EACR,eAAe,GAChB,MAAM,iBAAiB,CAAA;AAGxB,iBAAiB;AACjB,OAAO,EACL,MAAM,EACN,MAAM,EACN,KAAK,EACL,OAAO,EACP,SAAS,EACT,MAAM,EACN,aAAa,EACb,QAAQ,EACR,cAAc,GACf,MAAM,mBAAmB,CAAA;AAG1B,kBAAkB;AAClB,OAAO,EACL,YAAY,EACZ,WAAW,EACX,MAAM,EACN,gBAAgB,EAChB,oBAAoB,EACpB,UAAU,EACV,SAAS,EACT,YAAY,EACZ,UAAU,EACV,oBAAoB,GACrB,MAAM,oBAAoB,CAAA;AAW3B,mBAAmB;AACnB,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAE7D,mBAAmB;AACnB,OAAO,EAAE,iBAAiB,EAAE,0BAA0B,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAG3G,oBAAoB;AACpB,OAAO,EACL,qBAAqB,EACrB,aAAa,EACb,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,sBAAsB,CAAA;AAG7B,0BAA0B;AAC1B,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AAG/E,oBAAoB;AACpB,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAErD,oBAAoB;AACpB,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,EACrB,cAAc,GACf,MAAM,sBAAsB,CAAA;AAQ7B,kBAAkB;AAClB,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAM/C,kBAAkB;AAClB,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAEpD,oBAAoB;AACpB,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onroad/core",
3
- "version": "4.0.0-alpha.22",
3
+ "version": "4.0.0-alpha.24",
4
4
  "description": "TypeScript backend framework — DI Container, Filter Chain, EventBus, Provider Pattern",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",