@entrinsik/vite-plugin-informer 2.3.0 → 2.4.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/bin/deploy.js +3 -2
- package/bin/workspace.js +11 -5
- package/package.json +1 -1
- package/src/agent-dev.js +29 -1
- package/src/env.js +86 -0
- package/src/index.js +8 -5
- package/src/server-routes.js +27 -1
- package/src/workspace.js +2 -2
package/bin/deploy.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import dotenv from 'dotenv';
|
|
4
3
|
import { readFile, writeFile } from 'node:fs/promises';
|
|
5
4
|
import { resolve } from 'node:path';
|
|
6
5
|
import { deploy } from '../src/deploy.js';
|
|
6
|
+
import { loadEnv, parseModeArg } from '../src/env.js';
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
const mode = parseModeArg(process.argv);
|
|
9
|
+
loadEnv({ mode });
|
|
9
10
|
|
|
10
11
|
const baseUrl = process.env.INFORMER_URL;
|
|
11
12
|
const apiKey = process.env.INFORMER_API_KEY;
|
package/bin/workspace.js
CHANGED
|
@@ -1,22 +1,28 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import dotenv from 'dotenv';
|
|
4
3
|
import { readFile } from 'node:fs/promises';
|
|
5
4
|
import { resolve } from 'node:path';
|
|
6
5
|
import { createClient } from '../src/client.js';
|
|
6
|
+
import { loadEnv, envWritePath, parseModeArg } from '../src/env.js';
|
|
7
7
|
import { init, migrate, reset } from '../src/workspace.js';
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
const mode = parseModeArg(process.argv);
|
|
10
|
+
loadEnv({ mode });
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
// Strip --mode <value> from argv before parsing the command
|
|
13
|
+
const args = process.argv.slice(2).filter((arg, i, arr) => arg !== '--mode' && arr[i - 1] !== '--mode');
|
|
14
|
+
const command = args[0];
|
|
12
15
|
|
|
13
16
|
if (!command || !['init', 'migrate', 'reset'].includes(command)) {
|
|
14
|
-
console.error('Usage: informer-workspace <init|migrate|reset>');
|
|
17
|
+
console.error('Usage: informer-workspace <init|migrate|reset> [--mode <name>]');
|
|
15
18
|
console.error('');
|
|
16
19
|
console.error('Commands:');
|
|
17
20
|
console.error(' init Create a dev workspace datasource and run migrations');
|
|
18
21
|
console.error(' migrate Run pending migrations against the dev workspace');
|
|
19
22
|
console.error(' reset Drop all tables and re-run all migrations');
|
|
23
|
+
console.error('');
|
|
24
|
+
console.error('Options:');
|
|
25
|
+
console.error(' --mode <name> Load .env.<name> (e.g. --mode test, --mode production)');
|
|
20
26
|
process.exit(1);
|
|
21
27
|
}
|
|
22
28
|
|
|
@@ -33,7 +39,7 @@ if (!baseUrl || (!apiKey && (!user || !pass))) {
|
|
|
33
39
|
|
|
34
40
|
const api = createClient({ baseUrl, apiKey, user, pass });
|
|
35
41
|
const migrationsDir = resolve('migrations');
|
|
36
|
-
const envPath =
|
|
42
|
+
const envPath = envWritePath({ mode });
|
|
37
43
|
|
|
38
44
|
try {
|
|
39
45
|
if (command === 'init') {
|
package/package.json
CHANGED
package/src/agent-dev.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createHmac } from 'node:crypto';
|
|
1
2
|
import { readFile, readdir, stat, access } from 'node:fs/promises';
|
|
2
3
|
import { join } from 'node:path';
|
|
3
4
|
import { parse as parseUrl } from 'node:url';
|
|
@@ -192,6 +193,33 @@ export function createAgentMiddleware(viteServer, { serverOrigin, authHeader, de
|
|
|
192
193
|
return { ok: true };
|
|
193
194
|
}
|
|
194
195
|
|
|
196
|
+
// crypto helper — mirrors the sandbox's crypto.hmac()
|
|
197
|
+
const cryptoHelper = {
|
|
198
|
+
hmac(algorithm, key, data, encoding) {
|
|
199
|
+
return createHmac(algorithm, key).update(data).digest(encoding || 'hex');
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
// log helper — mirrors sandbox log(message, data) + log.info/warn/error/debug
|
|
204
|
+
const logCall = (level, message, data) => {
|
|
205
|
+
const msg = typeof message === 'string' ? message : JSON.stringify(message);
|
|
206
|
+
const args = [`[app-log] [${level}] ${msg}`];
|
|
207
|
+
if (data) args.push(data);
|
|
208
|
+
console.log(...args);
|
|
209
|
+
};
|
|
210
|
+
const log = Object.assign(
|
|
211
|
+
(message, data) => logCall('info', message, data),
|
|
212
|
+
{
|
|
213
|
+
debug: (message, data) => logCall('debug', message, data),
|
|
214
|
+
info: (message, data) => logCall('info', message, data),
|
|
215
|
+
warn: (message, data) => logCall('warn', message, data),
|
|
216
|
+
error: (message, data) => logCall('error', message, data)
|
|
217
|
+
}
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
// markdown helper — passthrough in dev (production uses `marked`)
|
|
221
|
+
const markdown = (text) => text;
|
|
222
|
+
|
|
195
223
|
return async function agentDevMiddleware(req, res, next) {
|
|
196
224
|
try {
|
|
197
225
|
const parsed = parseUrl(req.url, true);
|
|
@@ -366,7 +394,7 @@ export function createAgentMiddleware(viteServer, { serverOrigin, authHeader, de
|
|
|
366
394
|
|
|
367
395
|
if (tool) {
|
|
368
396
|
try {
|
|
369
|
-
result = await tool.handler(tc.input, { query, fetch: apiFetch, emit, context: triggerEvent });
|
|
397
|
+
result = await tool.handler(tc.input, { query, fetch: apiFetch, emit, crypto: cryptoHelper, markdown, log, context: triggerEvent });
|
|
370
398
|
} catch (err) {
|
|
371
399
|
console.error(`[agent-dev] Tool "${tc.name}" failed:`, err.message);
|
|
372
400
|
result = { error: err.message };
|
package/src/env.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import dotenv from 'dotenv';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { resolve, dirname, parse as parsePath } from 'node:path';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Build an ordered list of .env file paths for dotenv to load.
|
|
7
|
+
*
|
|
8
|
+
* Priority (first match wins in dotenv):
|
|
9
|
+
* 1. <cwd>/.env.<mode> (mode-specific, e.g. .env.test)
|
|
10
|
+
* 2. <cwd>/.env (local defaults)
|
|
11
|
+
* 3. <parent>/.env.<mode> (walk up for monorepo shared config)
|
|
12
|
+
* 4. <parent>/.env
|
|
13
|
+
* ... continues up to first parent that contains a .env file
|
|
14
|
+
*
|
|
15
|
+
* When mode is 'development' (Vite default), mode-specific files are skipped
|
|
16
|
+
* since .env already serves that purpose.
|
|
17
|
+
*
|
|
18
|
+
* @param {{ mode?: string, cwd?: string }} options
|
|
19
|
+
* @returns {string[]} Ordered file paths (may include non-existent files — dotenv ignores those)
|
|
20
|
+
*/
|
|
21
|
+
export function buildEnvPaths({ mode, cwd } = {}) {
|
|
22
|
+
const dir = cwd || process.cwd();
|
|
23
|
+
const useMode = mode && mode !== 'development';
|
|
24
|
+
|
|
25
|
+
// Local project .env files (highest priority)
|
|
26
|
+
const paths = [];
|
|
27
|
+
if (useMode) paths.push(resolve(dir, `.env.${mode}`));
|
|
28
|
+
paths.push(resolve(dir, '.env'));
|
|
29
|
+
|
|
30
|
+
// Walk up to parent directories for monorepo fallback
|
|
31
|
+
let current = dirname(dir);
|
|
32
|
+
const { root } = parsePath(dir);
|
|
33
|
+
|
|
34
|
+
while (current !== root) {
|
|
35
|
+
if (useMode) paths.push(resolve(current, `.env.${mode}`));
|
|
36
|
+
paths.push(resolve(current, '.env'));
|
|
37
|
+
|
|
38
|
+
// Stop at the first ancestor that has any .env file
|
|
39
|
+
const hasEnv = useMode
|
|
40
|
+
? existsSync(resolve(current, `.env.${mode}`)) || existsSync(resolve(current, '.env'))
|
|
41
|
+
: existsSync(resolve(current, '.env'));
|
|
42
|
+
|
|
43
|
+
if (hasEnv) break;
|
|
44
|
+
|
|
45
|
+
current = dirname(current);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return paths;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Load environment variables using mode-aware, parent-walking dotenv paths.
|
|
53
|
+
*
|
|
54
|
+
* @param {{ mode?: string, cwd?: string }} options
|
|
55
|
+
*/
|
|
56
|
+
export function loadEnv({ mode, cwd } = {}) {
|
|
57
|
+
const paths = buildEnvPaths({ mode, cwd });
|
|
58
|
+
dotenv.config({ path: paths });
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Determine the .env file path to write workspace IDs into.
|
|
63
|
+
* Writes to .env.<mode> when a non-default mode is active, otherwise .env.
|
|
64
|
+
*
|
|
65
|
+
* @param {{ mode?: string, cwd?: string }} options
|
|
66
|
+
* @returns {string}
|
|
67
|
+
*/
|
|
68
|
+
export function envWritePath({ mode, cwd } = {}) {
|
|
69
|
+
const dir = cwd || process.cwd();
|
|
70
|
+
const useMode = mode && mode !== 'development';
|
|
71
|
+
return resolve(dir, useMode ? `.env.${mode}` : '.env');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Parse --mode <name> from a process.argv array.
|
|
76
|
+
*
|
|
77
|
+
* @param {string[]} argv
|
|
78
|
+
* @returns {string|null}
|
|
79
|
+
*/
|
|
80
|
+
export function parseModeArg(argv) {
|
|
81
|
+
const idx = argv.indexOf('--mode');
|
|
82
|
+
if (idx !== -1 && idx + 1 < argv.length) {
|
|
83
|
+
return argv[idx + 1];
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
package/src/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import dotenv from 'dotenv';
|
|
2
1
|
import { existsSync } from 'node:fs';
|
|
3
2
|
import { readFile } from 'node:fs/promises';
|
|
4
3
|
import { resolve } from 'node:path';
|
|
5
4
|
import { createClient } from './client.js';
|
|
5
|
+
import { loadEnv, envWritePath } from './env.js';
|
|
6
6
|
import { createMiddleware as createServerRoutes } from './server-routes.js';
|
|
7
7
|
import { createAgentMiddleware } from './agent-dev.js';
|
|
8
8
|
import { init, migrate } from './workspace.js';
|
|
@@ -23,12 +23,14 @@ export default function informer(options = {}) {
|
|
|
23
23
|
let authHeader = null;
|
|
24
24
|
let serverOrigin = null;
|
|
25
25
|
let devWorkspaceId = null;
|
|
26
|
+
let activeMode = null;
|
|
26
27
|
|
|
27
28
|
return {
|
|
28
29
|
name: 'vite-plugin-informer',
|
|
29
30
|
|
|
30
|
-
config(_, { command }) {
|
|
31
|
-
|
|
31
|
+
config(_, { command, mode }) {
|
|
32
|
+
activeMode = mode;
|
|
33
|
+
loadEnv({ mode });
|
|
32
34
|
|
|
33
35
|
isDev = command === 'serve';
|
|
34
36
|
|
|
@@ -57,7 +59,8 @@ export default function informer(options = {}) {
|
|
|
57
59
|
changeOrigin: true,
|
|
58
60
|
headers: {
|
|
59
61
|
Authorization: authHeader
|
|
60
|
-
}
|
|
62
|
+
},
|
|
63
|
+
...options.proxy
|
|
61
64
|
}
|
|
62
65
|
}
|
|
63
66
|
};
|
|
@@ -106,7 +109,7 @@ export default function informer(options = {}) {
|
|
|
106
109
|
api,
|
|
107
110
|
slug,
|
|
108
111
|
migrationsDir,
|
|
109
|
-
envPath:
|
|
112
|
+
envPath: envWritePath({ mode: activeMode })
|
|
110
113
|
});
|
|
111
114
|
devWorkspaceId = result.workspaceId;
|
|
112
115
|
}
|
package/src/server-routes.js
CHANGED
|
@@ -237,6 +237,32 @@ export function createMiddleware(viteServer, { serverOrigin, authHeader, devWork
|
|
|
237
237
|
}
|
|
238
238
|
};
|
|
239
239
|
|
|
240
|
+
// log helper — mirrors sandbox log(message, data) + log.info/warn/error/debug
|
|
241
|
+
const logCall = (level, message, data) => {
|
|
242
|
+
const msg = typeof message === 'string' ? message : JSON.stringify(message);
|
|
243
|
+
const args = [`[app-log] [${level}] ${msg}`];
|
|
244
|
+
if (data) args.push(data);
|
|
245
|
+
console.log(...args);
|
|
246
|
+
};
|
|
247
|
+
const log = Object.assign(
|
|
248
|
+
(message, data) => logCall('info', message, data),
|
|
249
|
+
{
|
|
250
|
+
debug: (message, data) => logCall('debug', message, data),
|
|
251
|
+
info: (message, data) => logCall('info', message, data),
|
|
252
|
+
warn: (message, data) => logCall('warn', message, data),
|
|
253
|
+
error: (message, data) => logCall('error', message, data)
|
|
254
|
+
}
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
// markdown helper — passthrough in dev (production uses `marked`)
|
|
258
|
+
const markdown = (text) => text;
|
|
259
|
+
|
|
260
|
+
// emit helper — no-op in dev (logs to console)
|
|
261
|
+
const emit = (event, payload) => {
|
|
262
|
+
console.log(`[app-event] emit("${event}",`, JSON.stringify(payload), ')');
|
|
263
|
+
return { ok: true };
|
|
264
|
+
};
|
|
265
|
+
|
|
240
266
|
// Build request context
|
|
241
267
|
const request = {
|
|
242
268
|
method: req.method.toUpperCase(),
|
|
@@ -266,7 +292,7 @@ export function createMiddleware(viteServer, { serverOrigin, authHeader, devWork
|
|
|
266
292
|
}
|
|
267
293
|
|
|
268
294
|
// Call handler
|
|
269
|
-
const result = await handler({ query, fetch: apiFetch, respond, crypto: cryptoHelper, env: {}, request });
|
|
295
|
+
const result = await handler({ query, fetch: apiFetch, respond, emit, crypto: cryptoHelper, markdown, log, env: {}, request });
|
|
270
296
|
|
|
271
297
|
// If respond() was already called, the response is already sent
|
|
272
298
|
if (responded) return;
|
package/src/workspace.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readdir, readFile, writeFile, access } from 'node:fs/promises';
|
|
2
|
-
import { join } from 'node:path';
|
|
2
|
+
import { join, basename } from 'node:path';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Execute raw SQL against a workspace datasource via the _sql route.
|
|
@@ -122,7 +122,7 @@ export async function init({ api, slug, migrationsDir, envPath }) {
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
await writeFile(envPath, envContent);
|
|
125
|
-
console.log(`Saved INFORMER_DEV_WORKSPACE=${workspaceId} to
|
|
125
|
+
console.log(`Saved INFORMER_DEV_WORKSPACE=${workspaceId} to ${basename(envPath)}`);
|
|
126
126
|
|
|
127
127
|
return { workspaceId, ...result };
|
|
128
128
|
}
|