@hs-x/cli 0.3.7 → 0.4.1
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 +120 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +38 -10
- package/dist/cli/index.js.map +1 -1
- package/dist/command-catalog.d.ts +2 -2
- package/dist/command-catalog.d.ts.map +1 -1
- package/dist/command-catalog.js +1 -0
- package/dist/command-catalog.js.map +1 -1
- package/dist/commands/completion.d.ts.map +1 -1
- package/dist/commands/completion.js +268 -16
- package/dist/commands/completion.js.map +1 -1
- package/dist/commands/connect.d.ts.map +1 -1
- package/dist/commands/connect.js +177 -20
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/control-plane-read.d.ts +28 -0
- package/dist/commands/control-plane-read.d.ts.map +1 -1
- package/dist/commands/control-plane-read.js +134 -28
- package/dist/commands/control-plane-read.js.map +1 -1
- package/dist/commands/deploy.d.ts +5 -0
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +605 -102
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/dev.d.ts +19 -1
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +1335 -83
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +27 -10
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/help-command.d.ts.map +1 -1
- package/dist/commands/help-command.js +145 -35
- package/dist/commands/help-command.js.map +1 -1
- package/dist/commands/project.d.ts +107 -0
- package/dist/commands/project.d.ts.map +1 -0
- package/dist/commands/project.js +586 -0
- package/dist/commands/project.js.map +1 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +15 -5
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/validate.d.ts +19 -0
- package/dist/commands/validate.d.ts.map +1 -1
- package/dist/commands/validate.js +26 -7
- package/dist/commands/validate.js.map +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/dev/account-selection.d.ts +16 -0
- package/dist/dev/account-selection.d.ts.map +1 -0
- package/dist/dev/account-selection.js +22 -0
- package/dist/dev/account-selection.js.map +1 -0
- package/dist/dev/browser-log-bridge.d.ts +32 -0
- package/dist/dev/browser-log-bridge.d.ts.map +1 -0
- package/dist/dev/browser-log-bridge.js +156 -0
- package/dist/dev/browser-log-bridge.js.map +1 -0
- package/dist/dev/compat-shim.d.ts +3 -3
- package/dist/dev/compat-shim.d.ts.map +1 -1
- package/dist/dev/compat-shim.js +7 -6
- package/dist/dev/compat-shim.js.map +1 -1
- package/dist/dev/component-selection.d.ts +25 -0
- package/dist/dev/component-selection.d.ts.map +1 -0
- package/dist/dev/component-selection.js +79 -0
- package/dist/dev/component-selection.js.map +1 -0
- package/dist/dev/console-capture.d.ts +18 -0
- package/dist/dev/console-capture.d.ts.map +1 -0
- package/dist/dev/console-capture.js +57 -0
- package/dist/dev/console-capture.js.map +1 -0
- package/dist/dev/event-bus.d.ts +1 -1
- package/dist/dev/event-bus.js +1 -1
- package/dist/dev/frontend-log-relay.d.ts +27 -0
- package/dist/dev/frontend-log-relay.d.ts.map +1 -0
- package/dist/dev/frontend-log-relay.js +102 -0
- package/dist/dev/frontend-log-relay.js.map +1 -0
- package/dist/dev/keyboard.d.ts +1 -0
- package/dist/dev/keyboard.d.ts.map +1 -1
- package/dist/dev/keyboard.js +9 -3
- package/dist/dev/keyboard.js.map +1 -1
- package/dist/dev/log-server.js +3 -0
- package/dist/dev/log-server.js.map +1 -1
- package/dist/dev/managed-session.d.ts +124 -0
- package/dist/dev/managed-session.d.ts.map +1 -0
- package/dist/dev/managed-session.js +597 -0
- package/dist/dev/managed-session.js.map +1 -0
- package/dist/dev/port-process.d.ts +21 -0
- package/dist/dev/port-process.d.ts.map +1 -0
- package/dist/dev/port-process.js +145 -0
- package/dist/dev/port-process.js.map +1 -0
- package/dist/dev/session-manager.d.ts +11 -1
- package/dist/dev/session-manager.d.ts.map +1 -1
- package/dist/dev/session-manager.js +62 -12
- package/dist/dev/session-manager.js.map +1 -1
- package/dist/dev/stream-event-format.d.ts +14 -0
- package/dist/dev/stream-event-format.d.ts.map +1 -0
- package/dist/dev/stream-event-format.js +262 -0
- package/dist/dev/stream-event-format.js.map +1 -0
- package/dist/dev/stream-filter.d.ts.map +1 -1
- package/dist/dev/stream-filter.js +16 -1
- package/dist/dev/stream-filter.js.map +1 -1
- package/dist/dev/stream-renderer.d.ts +4 -2
- package/dist/dev/stream-renderer.d.ts.map +1 -1
- package/dist/dev/stream-renderer.js +224 -84
- package/dist/dev/stream-renderer.js.map +1 -1
- package/dist/errors-registry.d.ts.map +1 -1
- package/dist/errors-registry.js +213 -0
- package/dist/errors-registry.js.map +1 -1
- package/dist/hubspot-app-logs.d.ts +38 -5
- package/dist/hubspot-app-logs.d.ts.map +1 -1
- package/dist/hubspot-app-logs.js +88 -17
- package/dist/hubspot-app-logs.js.map +1 -1
- package/dist/hubspot-auth.d.ts +19 -1
- package/dist/hubspot-auth.d.ts.map +1 -1
- package/dist/hubspot-auth.js +240 -85
- package/dist/hubspot-auth.js.map +1 -1
- package/dist/hubspot-developer-client.d.ts +87 -0
- package/dist/hubspot-developer-client.d.ts.map +1 -1
- package/dist/hubspot-developer-client.js +232 -1
- package/dist/hubspot-developer-client.js.map +1 -1
- package/dist/hubspot-project-archive.d.ts +21 -0
- package/dist/hubspot-project-archive.d.ts.map +1 -0
- package/dist/hubspot-project-archive.js +281 -0
- package/dist/hubspot-project-archive.js.map +1 -0
- package/dist/hubspot-project.d.ts +32 -0
- package/dist/hubspot-project.d.ts.map +1 -0
- package/dist/hubspot-project.js +269 -0
- package/dist/hubspot-project.js.map +1 -0
- package/dist/local-project-picker.js +1 -1
- package/dist/local-project-picker.js.map +1 -1
- package/dist/output-context.js +1 -1
- package/dist/output-context.js.map +1 -1
- package/dist/services/hubspot-dev-client.js +3 -0
- package/dist/services/hubspot-dev-client.js.map +1 -1
- package/package.json +14 -12
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { readlink } from 'node:fs/promises';
|
|
3
|
+
export function isHubSpotDevPortConflict(error) {
|
|
4
|
+
const messages = [];
|
|
5
|
+
let current = error;
|
|
6
|
+
for (let depth = 0; depth < 4 && current; depth += 1) {
|
|
7
|
+
if (current instanceof Error)
|
|
8
|
+
messages.push(current.message);
|
|
9
|
+
else if (typeof current === 'string')
|
|
10
|
+
messages.push(current);
|
|
11
|
+
current =
|
|
12
|
+
typeof current === 'object' && current !== null && 'cause' in current
|
|
13
|
+
? current.cause
|
|
14
|
+
: undefined;
|
|
15
|
+
}
|
|
16
|
+
return messages.some((message) => /another instance is already running|port\s+\d+\s+is already in use|EADDRINUSE/i.test(message));
|
|
17
|
+
}
|
|
18
|
+
export async function findListeningProcess(port) {
|
|
19
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535)
|
|
20
|
+
return undefined;
|
|
21
|
+
const pid = process.platform === 'win32'
|
|
22
|
+
? await findWindowsListeningPid(port)
|
|
23
|
+
: await findUnixListeningPid(port);
|
|
24
|
+
if (!pid)
|
|
25
|
+
return undefined;
|
|
26
|
+
const [command, cwd] = await Promise.all([readProcessCommand(pid), readProcessCwd(pid)]);
|
|
27
|
+
return {
|
|
28
|
+
port,
|
|
29
|
+
pid,
|
|
30
|
+
...(command ? { command } : {}),
|
|
31
|
+
...(cwd ? { cwd } : {}),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export async function terminateProcessGracefully(pid, options = {}) {
|
|
35
|
+
if (!Number.isInteger(pid) || pid <= 1 || pid === process.pid) {
|
|
36
|
+
return { ok: false, message: `Refusing to stop invalid process ${pid}.` };
|
|
37
|
+
}
|
|
38
|
+
const kill = options.kill ?? process.kill.bind(process);
|
|
39
|
+
const delay = options.delay ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
40
|
+
const timeoutMs = options.timeoutMs ?? 3_000;
|
|
41
|
+
const pollMs = options.pollMs ?? 100;
|
|
42
|
+
try {
|
|
43
|
+
kill(pid, 'SIGTERM');
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
if (isMissingProcessError(error))
|
|
47
|
+
return { ok: true };
|
|
48
|
+
return { ok: false, message: error instanceof Error ? error.message : String(error) };
|
|
49
|
+
}
|
|
50
|
+
const deadline = Date.now() + timeoutMs;
|
|
51
|
+
while (Date.now() < deadline) {
|
|
52
|
+
await delay(pollMs);
|
|
53
|
+
try {
|
|
54
|
+
kill(pid, 0);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
if (isMissingProcessError(error))
|
|
58
|
+
return { ok: true };
|
|
59
|
+
return { ok: false, message: error instanceof Error ? error.message : String(error) };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
ok: false,
|
|
64
|
+
message: `Process ${pid} did not exit after SIGTERM. It was left running.`,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export function stopProcessCommand(pid) {
|
|
68
|
+
return process.platform === 'win32' ? `taskkill /PID ${pid}` : `kill -TERM ${pid}`;
|
|
69
|
+
}
|
|
70
|
+
export function redactProcessCommand(command) {
|
|
71
|
+
return command
|
|
72
|
+
.replace(/(--(?:personal-access-key|pak|token|api-token|client-secret|password)(?:=|\s+))\S+/gi, '$1[REDACTED]')
|
|
73
|
+
.replace(/\b((?:HSX|HUBSPOT|CLOUDFLARE)[A-Z0-9_]*(?:TOKEN|SECRET|KEY|PASSWORD)=)\S+/g, '$1[REDACTED]')
|
|
74
|
+
.slice(0, 2_000);
|
|
75
|
+
}
|
|
76
|
+
async function findUnixListeningPid(port) {
|
|
77
|
+
const output = await execFileText('lsof', ['-nP', `-iTCP:${port}`, '-sTCP:LISTEN', '-Fp']);
|
|
78
|
+
const match = output?.match(/^p(\d+)$/m);
|
|
79
|
+
return match?.[1] ? Number(match[1]) : undefined;
|
|
80
|
+
}
|
|
81
|
+
async function findWindowsListeningPid(port) {
|
|
82
|
+
const output = await execFileText('netstat', ['-ano', '-p', 'tcp']);
|
|
83
|
+
if (!output)
|
|
84
|
+
return undefined;
|
|
85
|
+
for (const line of output.split(/\r?\n/)) {
|
|
86
|
+
const fields = line.trim().split(/\s+/);
|
|
87
|
+
if (fields.length < 5 || fields[3]?.toUpperCase() !== 'LISTENING')
|
|
88
|
+
continue;
|
|
89
|
+
const local = fields[1] ?? '';
|
|
90
|
+
if (!local.endsWith(`:${port}`))
|
|
91
|
+
continue;
|
|
92
|
+
const pid = Number(fields[4]);
|
|
93
|
+
if (Number.isInteger(pid) && pid > 0)
|
|
94
|
+
return pid;
|
|
95
|
+
}
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
async function readProcessCommand(pid) {
|
|
99
|
+
if (process.platform === 'win32') {
|
|
100
|
+
const output = await execFileText('wmic', [
|
|
101
|
+
'process',
|
|
102
|
+
'where',
|
|
103
|
+
`ProcessId=${pid}`,
|
|
104
|
+
'get',
|
|
105
|
+
'CommandLine',
|
|
106
|
+
'/value',
|
|
107
|
+
]);
|
|
108
|
+
const command = output?.match(/^CommandLine=(.+)$/m)?.[1]?.trim();
|
|
109
|
+
return command ? redactProcessCommand(command) : undefined;
|
|
110
|
+
}
|
|
111
|
+
const command = (await execFileText('ps', ['-p', String(pid), '-o', 'command=']))?.trim();
|
|
112
|
+
return command ? redactProcessCommand(command) : undefined;
|
|
113
|
+
}
|
|
114
|
+
async function readProcessCwd(pid) {
|
|
115
|
+
if (process.platform === 'linux') {
|
|
116
|
+
try {
|
|
117
|
+
return await readlink(`/proc/${pid}/cwd`);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (process.platform === 'darwin') {
|
|
124
|
+
const output = await execFileText('lsof', ['-a', '-p', String(pid), '-d', 'cwd', '-Fn']);
|
|
125
|
+
return output?.match(/^n(.+)$/m)?.[1];
|
|
126
|
+
}
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
function execFileText(command, args) {
|
|
130
|
+
return new Promise((resolve) => {
|
|
131
|
+
execFile(command, [...args], { encoding: 'utf8', timeout: 2_000 }, (error, stdout) => {
|
|
132
|
+
if (error && !stdout)
|
|
133
|
+
resolve(undefined);
|
|
134
|
+
else
|
|
135
|
+
resolve(stdout || undefined);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
function isMissingProcessError(error) {
|
|
140
|
+
return (typeof error === 'object' &&
|
|
141
|
+
error !== null &&
|
|
142
|
+
'code' in error &&
|
|
143
|
+
error.code === 'ESRCH');
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=port-process.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"port-process.js","sourceRoot":"","sources":["../../src/dev/port-process.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,11 +9,21 @@
|
|
|
9
9
|
*
|
|
10
10
|
* See docs/phase-1.5/spike-ui-extension-dev-session.md.
|
|
11
11
|
*/
|
|
12
|
+
import { type CapturedConsoleEntry } from './console-capture.js';
|
|
13
|
+
import { type FrontendLogEntry } from './frontend-log-relay.js';
|
|
12
14
|
export interface DevSessionStart {
|
|
13
|
-
|
|
15
|
+
/** Backward-compatible shorthand when project and testing accounts are the same. */
|
|
16
|
+
readonly accountId?: number;
|
|
17
|
+
readonly projectAccountId?: number;
|
|
18
|
+
readonly testingAccountId?: number;
|
|
14
19
|
readonly projectDir: string;
|
|
20
|
+
readonly profile?: string;
|
|
15
21
|
/** Optional whitelist — only these node UIDs are registered. */
|
|
16
22
|
readonly selectedNodeUids?: readonly string[];
|
|
23
|
+
/** Receives console/logger calls relayed through HubSpot's worker channel. */
|
|
24
|
+
readonly onFrontendLog?: (entry: FrontendLogEntry) => void;
|
|
25
|
+
/** Receives stdout/stderr-style logs from locally executed HubSpot app functions. */
|
|
26
|
+
readonly onBackendLog?: (entry: CapturedConsoleEntry) => void;
|
|
17
27
|
/** Called every successful heartbeat (used by the request-log renderer). */
|
|
18
28
|
readonly onHeartbeat?: (info: {
|
|
19
29
|
at: Date;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/dev/session-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;
|
|
1
|
+
{"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/dev/session-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAWH,OAAO,EAAE,KAAK,oBAAoB,EAAkB,MAAM,sBAAsB,CAAC;AACjF,OAAO,EACL,KAAK,gBAAgB,EAGtB,MAAM,yBAAyB,CAAC;AAGjC,MAAM,WAAW,eAAe;IAC9B,oFAAoF;IACpF,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,gEAAgE;IAChE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9C,8EAA8E;IAC9E,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC3D,qFAAqF;IACrF,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAC9D,4EAA4E;IAC5E,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,IAAI,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CACxE;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClE,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAID,wBAAsB,eAAe,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAuKvF"}
|
|
@@ -12,52 +12,80 @@
|
|
|
12
12
|
import { readFile } from 'node:fs/promises';
|
|
13
13
|
import { join } from 'node:path';
|
|
14
14
|
import { createDevSessionsClient } from '@hs-x/hubspot-cli';
|
|
15
|
+
import { createHubSpotDevBrowserLogInstrumentor } from './browser-log-bridge.js';
|
|
15
16
|
import { loadDevStack } from './compat-shim.js';
|
|
17
|
+
import { filterHubSpotDevSessionNodes, listHubSpotDevComponentCandidates, } from './component-selection.js';
|
|
18
|
+
import { captureConsole } from './console-capture.js';
|
|
19
|
+
import { createFrontendLogRelay, } from './frontend-log-relay.js';
|
|
16
20
|
import { withLoopbackHttpListener } from './loopback-http-listener.js';
|
|
17
21
|
const HEARTBEAT_INTERVAL_MS = 30_000;
|
|
18
22
|
export async function startDevSession(input) {
|
|
19
23
|
const stack = await loadDevStack();
|
|
20
|
-
|
|
21
|
-
|
|
24
|
+
const projectAccountId = input.projectAccountId ?? input.accountId;
|
|
25
|
+
const testingAccountId = input.testingAccountId ?? projectAccountId;
|
|
26
|
+
if (!projectAccountId || !stack.getAccountConfig(projectAccountId)) {
|
|
27
|
+
throw new DevSessionStartError('HSX_E_DEV_SESSION_NO_HUBSPOT_ACCOUNT', `HubSpot CLI config has no project account ${projectAccountId ?? '(missing)'}. Run \`hs account auth\` or pass --project-account.`);
|
|
28
|
+
}
|
|
29
|
+
if (!testingAccountId || !stack.getAccountConfig(testingAccountId)) {
|
|
30
|
+
throw new DevSessionStartError('HSX_E_DEV_SESSION_NO_HUBSPOT_ACCOUNT', `HubSpot CLI config has no testing account ${testingAccountId ?? '(missing)'}. Run \`hs account auth\` or pass --testing-account.`);
|
|
22
31
|
}
|
|
23
32
|
const projectConfigRaw = await readFile(join(input.projectDir, 'hsproject.json'), 'utf8');
|
|
24
33
|
const projectConfig = JSON.parse(projectConfigRaw);
|
|
25
34
|
const ir = await stack.translateForLocalDev({
|
|
26
35
|
projectSourceDir: join(input.projectDir, projectConfig.srcDir),
|
|
27
36
|
platformVersion: projectConfig.platformVersion,
|
|
28
|
-
accountId:
|
|
29
|
-
}, {});
|
|
37
|
+
accountId: projectAccountId,
|
|
38
|
+
}, input.profile ? { profile: input.profile } : {});
|
|
30
39
|
let nodesByUid = ir.intermediateNodesIndexedByUid;
|
|
40
|
+
let activeNodeUids = listHubSpotDevComponentCandidates(nodesByUid).map((candidate) => candidate.uid);
|
|
31
41
|
if (input.selectedNodeUids && input.selectedNodeUids.length > 0) {
|
|
32
|
-
const
|
|
33
|
-
nodesByUid =
|
|
34
|
-
|
|
42
|
+
const filtered = filterHubSpotDevSessionNodes(nodesByUid, input.selectedNodeUids);
|
|
43
|
+
nodesByUid = filtered.nodesByUid;
|
|
44
|
+
activeNodeUids = [...filtered.activeNodeUids];
|
|
45
|
+
if (activeNodeUids.length === 0) {
|
|
35
46
|
throw new DevSessionStartError('HSX_E_DEV_SESSION_NO_NODES', 'None of the selected nodes were found in the project IR.');
|
|
36
47
|
}
|
|
37
48
|
}
|
|
38
49
|
await stack.startPortManagerServer();
|
|
50
|
+
let frontendLogRelay;
|
|
51
|
+
let stopBackendConsoleCapture;
|
|
52
|
+
let stopBrowserLogWatcher;
|
|
39
53
|
try {
|
|
54
|
+
frontendLogRelay = input.onFrontendLog
|
|
55
|
+
? await createFrontendLogRelay({ nodesByUid, onEntry: input.onFrontendLog })
|
|
56
|
+
: undefined;
|
|
57
|
+
const sessionNodesByUid = frontendLogRelay?.nodesByUid ?? nodesByUid;
|
|
58
|
+
const browserLogs = frontendLogRelay
|
|
59
|
+
? createHubSpotDevBrowserLogInstrumentor({
|
|
60
|
+
nodesByUid: sessionNodesByUid,
|
|
61
|
+
relayFunctionName: frontendLogRelay.functionUid,
|
|
62
|
+
logger: stack.logger,
|
|
63
|
+
})
|
|
64
|
+
: undefined;
|
|
65
|
+
stopBackendConsoleCapture = input.onBackendLog ? captureConsole(input.onBackendLog) : undefined;
|
|
40
66
|
await stack.uie.setup({
|
|
41
|
-
components:
|
|
67
|
+
components: sessionNodesByUid,
|
|
42
68
|
profileData: ir.profileData,
|
|
43
|
-
logger: stack.logger,
|
|
69
|
+
logger: browserLogs?.logger ?? stack.logger,
|
|
44
70
|
urls: {
|
|
45
71
|
api: stack.getHubSpotApiOrigin(),
|
|
46
72
|
web: stack.getHubSpotWebsiteOrigin(),
|
|
47
73
|
},
|
|
48
74
|
});
|
|
49
75
|
await withLoopbackHttpListener(() => stack.uie.start({
|
|
50
|
-
accountId:
|
|
76
|
+
accountId: testingAccountId,
|
|
51
77
|
projectConfig: projectConfig,
|
|
52
78
|
requestPorts: stack.requestPorts,
|
|
53
79
|
}));
|
|
80
|
+
browserLogs?.patchBundles();
|
|
81
|
+
stopBrowserLogWatcher = browserLogs?.watchBundles();
|
|
54
82
|
const activeServers = await stack.getActiveServers();
|
|
55
83
|
const ports = Object.entries(activeServers).map(([serverId, port]) => ({
|
|
56
84
|
serverId,
|
|
57
85
|
port,
|
|
58
86
|
}));
|
|
59
87
|
const client = await createDevSessionsClient({
|
|
60
|
-
accountId:
|
|
88
|
+
accountId: testingAccountId,
|
|
61
89
|
});
|
|
62
90
|
const { sessionId } = await client.register({ ports });
|
|
63
91
|
const heartbeat = setInterval(async () => {
|
|
@@ -76,6 +104,7 @@ export async function startDevSession(input) {
|
|
|
76
104
|
return;
|
|
77
105
|
cleanedUp = true;
|
|
78
106
|
clearInterval(heartbeat);
|
|
107
|
+
stopBrowserLogWatcher?.();
|
|
79
108
|
const errors = [];
|
|
80
109
|
try {
|
|
81
110
|
await client.delete({ sessionId });
|
|
@@ -95,6 +124,13 @@ export async function startDevSession(input) {
|
|
|
95
124
|
catch (e) {
|
|
96
125
|
errors.push(`port manager: ${e.message}`);
|
|
97
126
|
}
|
|
127
|
+
try {
|
|
128
|
+
await frontendLogRelay?.cleanup();
|
|
129
|
+
}
|
|
130
|
+
catch (e) {
|
|
131
|
+
errors.push(`frontend log relay: ${e.message}`);
|
|
132
|
+
}
|
|
133
|
+
stopBackendConsoleCapture?.();
|
|
98
134
|
if (errors.length > 0) {
|
|
99
135
|
throw new DevSessionCleanupError(errors.join('; '));
|
|
100
136
|
}
|
|
@@ -102,17 +138,31 @@ export async function startDevSession(input) {
|
|
|
102
138
|
return {
|
|
103
139
|
sessionId,
|
|
104
140
|
ports,
|
|
105
|
-
nodeUids:
|
|
141
|
+
nodeUids: activeNodeUids,
|
|
106
142
|
cleanup,
|
|
107
143
|
};
|
|
108
144
|
}
|
|
109
145
|
catch (error) {
|
|
146
|
+
stopBrowserLogWatcher?.();
|
|
147
|
+
try {
|
|
148
|
+
await stack.uie.cleanup();
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
// Best-effort rollback for partially-started UI-extension servers.
|
|
152
|
+
}
|
|
110
153
|
try {
|
|
111
154
|
await stack.stopPortManagerServer();
|
|
112
155
|
}
|
|
113
156
|
catch {
|
|
114
157
|
// best-effort
|
|
115
158
|
}
|
|
159
|
+
try {
|
|
160
|
+
await frontendLogRelay?.cleanup();
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
// best-effort
|
|
164
|
+
}
|
|
165
|
+
stopBackendConsoleCapture?.();
|
|
116
166
|
throw error;
|
|
117
167
|
}
|
|
118
168
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../src/dev/session-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAA0B,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AACpF,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../src/dev/session-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type Style } from '../reporter/style.js';
|
|
2
|
+
import type { DevEvent } from './event-bus.js';
|
|
3
|
+
import type { ManagedDevStoredEvent } from './managed-session.js';
|
|
4
|
+
/**
|
|
5
|
+
* Restore the canonical in-process event shape from the durable managed-log
|
|
6
|
+
* envelope. Machine output keeps the stored envelope and cursor unchanged;
|
|
7
|
+
* human output can therefore reuse the exact same formatter and renderer as
|
|
8
|
+
* foreground `hs-x dev`.
|
|
9
|
+
*/
|
|
10
|
+
export declare function managedDevEventToDevEvent(event: ManagedDevStoredEvent): DevEvent;
|
|
11
|
+
export declare function formatDevStreamEvent(event: DevEvent, style: Style, count?: number): string;
|
|
12
|
+
export declare function renderDevEventDetails(event: DevEvent, count: number, style: Style, columns: number): string;
|
|
13
|
+
export declare function devEventFingerprint(event: DevEvent): string;
|
|
14
|
+
//# sourceMappingURL=stream-event-format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-event-format.d.ts","sourceRoot":"","sources":["../../src/dev/stream-event-format.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAe,MAAM,sBAAsB,CAAC;AAC/D,OAAO,KAAK,EAAE,QAAQ,EAAY,MAAM,gBAAgB,CAAC;AACzD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AASlE;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,qBAAqB,GAAG,QAAQ,CAqBhF;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,SAAI,GAAG,MAAM,CAYrF;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,QAAQ,EACf,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,MAAM,GACd,MAAM,CAoCR;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAI3D"}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { wrapVisible } from '../reporter/style.js';
|
|
2
|
+
const LANE_LABEL = {
|
|
3
|
+
frontend: 'frontend',
|
|
4
|
+
backend: 'backend ',
|
|
5
|
+
request: 'request ',
|
|
6
|
+
hubspot: 'hubspot ',
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Restore the canonical in-process event shape from the durable managed-log
|
|
10
|
+
* envelope. Machine output keeps the stored envelope and cursor unchanged;
|
|
11
|
+
* human output can therefore reuse the exact same formatter and renderer as
|
|
12
|
+
* foreground `hs-x dev`.
|
|
13
|
+
*/
|
|
14
|
+
export function managedDevEventToDevEvent(event) {
|
|
15
|
+
const parsedTimestamp = Date.parse(event.ts);
|
|
16
|
+
const ts = Number.isFinite(parsedTimestamp) ? parsedTimestamp : 0;
|
|
17
|
+
if (event.type === 'log') {
|
|
18
|
+
return {
|
|
19
|
+
lane: event.lane,
|
|
20
|
+
level: event.level,
|
|
21
|
+
ts,
|
|
22
|
+
msg: event.message,
|
|
23
|
+
...(event.source ? { source: event.source } : {}),
|
|
24
|
+
...(event.fields ? { fields: event.fields } : {}),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
lane: 'backend',
|
|
29
|
+
level: event.state === 'failed' ? 'error' : 'info',
|
|
30
|
+
ts,
|
|
31
|
+
source: 'session',
|
|
32
|
+
msg: event.message ? `${event.state} · ${event.message}` : event.state,
|
|
33
|
+
fields: { generation: event.generation },
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export function formatDevStreamEvent(event, style, count = 1) {
|
|
37
|
+
const ts = style.dim(formatTimestamp(event.ts));
|
|
38
|
+
const lane = paintLane(event.lane, style);
|
|
39
|
+
const level = paintLevel(event.level, style);
|
|
40
|
+
const source = event.source ? `${style.cyan(event.source)} ` : '';
|
|
41
|
+
const message = formatMessage(event, style);
|
|
42
|
+
const [first = '', ...continuations] = message.split('\n');
|
|
43
|
+
const headline = count > 1 ? `${first} ${style.dim(`×${count}`)}` : first;
|
|
44
|
+
const continuationRail = style.dim(style.unicode ? ' │ ' : ' | ');
|
|
45
|
+
return ` ${ts} ${lane} ${level} ${source}${headline}${continuations
|
|
46
|
+
.map((line) => `\n${continuationRail}${line}`)
|
|
47
|
+
.join('')}`;
|
|
48
|
+
}
|
|
49
|
+
export function renderDevEventDetails(event, count, style, columns) {
|
|
50
|
+
const rail = style.dim(style.unicode ? '│' : '|');
|
|
51
|
+
const lines = [
|
|
52
|
+
` ${style.dim('time')} ${formatTimestamp(event.ts)}`,
|
|
53
|
+
` ${style.dim('lane')} ${paintLane(event.lane, style).trimEnd()}`,
|
|
54
|
+
` ${style.dim('level')} ${paintLevel(event.level, style).trimEnd()}`,
|
|
55
|
+
...(event.source ? [` ${style.dim('source')} ${style.cyan(event.source)}`] : []),
|
|
56
|
+
...(count > 1 ? [` ${style.dim('repeat')} ×${count}`] : []),
|
|
57
|
+
...(typeof event.fields?.api === 'string'
|
|
58
|
+
? [` ${style.dim('api')} ${event.fields.api}`]
|
|
59
|
+
: []),
|
|
60
|
+
'',
|
|
61
|
+
` ${style.dim('message')}`,
|
|
62
|
+
...event.msg.split('\n').map((line) => ` ${rail} ${line}`),
|
|
63
|
+
];
|
|
64
|
+
if (Array.isArray(event.fields?.args)) {
|
|
65
|
+
lines.push('', ` ${style.dim('arguments')}`);
|
|
66
|
+
lines.push(...prettyJson(event.fields.args)
|
|
67
|
+
.split('\n')
|
|
68
|
+
.map((line) => ` ${rail} ${line}`));
|
|
69
|
+
}
|
|
70
|
+
const metadata = Object.fromEntries(Object.entries(event.fields ?? {}).filter(([key]) => key !== 'api' && key !== 'args'));
|
|
71
|
+
if (Object.keys(metadata).length > 0) {
|
|
72
|
+
lines.push('', ` ${style.dim('metadata')}`);
|
|
73
|
+
lines.push(...prettyJson(metadata)
|
|
74
|
+
.split('\n')
|
|
75
|
+
.map((line) => ` ${rail} ${line}`));
|
|
76
|
+
}
|
|
77
|
+
return lines.map((line) => wrapVisible(line, Math.max(20, columns - 1), ' ')).join('\n');
|
|
78
|
+
}
|
|
79
|
+
export function devEventFingerprint(event) {
|
|
80
|
+
return [event.lane, event.level, event.source ?? '', event.msg, safeJson(event.fields)].join('\u0000');
|
|
81
|
+
}
|
|
82
|
+
function prettyJson(value) {
|
|
83
|
+
try {
|
|
84
|
+
return JSON.stringify(value, null, 2) ?? String(value);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return '[unserializable]';
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function formatMessage(event, style) {
|
|
91
|
+
const structuredArgs = formatStructuredArgs(event.fields?.args, style);
|
|
92
|
+
const structured = structuredArgs ? undefined : splitStructuredMessage(event.msg);
|
|
93
|
+
const lines = structuredArgs
|
|
94
|
+
? structuredArgs
|
|
95
|
+
: [structured?.summary || (structured ? 'details' : event.msg)];
|
|
96
|
+
if (structured)
|
|
97
|
+
lines.push(...formatStructuredTree(structured.value, style));
|
|
98
|
+
// The frontend bridge records the originating console/logger API for
|
|
99
|
+
// diagnostics. It is transport metadata, not useful long-form event data,
|
|
100
|
+
// and rendering it as a JSON blob made every browser line noisy.
|
|
101
|
+
const displayFields = Object.fromEntries(Object.entries(event.fields ?? {}).filter(([key]) => key !== 'api' && key !== 'args'));
|
|
102
|
+
const fields = formatFields(displayFields);
|
|
103
|
+
if (fields)
|
|
104
|
+
lines[0] = `${lines[0]} ${style.dim(fields)}`;
|
|
105
|
+
return lines.join('\n');
|
|
106
|
+
}
|
|
107
|
+
function formatStructuredArgs(value, style) {
|
|
108
|
+
if (!Array.isArray(value))
|
|
109
|
+
return undefined;
|
|
110
|
+
const structured = value
|
|
111
|
+
.map((item, index) => ({ index, item }))
|
|
112
|
+
.filter(({ item }) => item !== null && typeof item === 'object');
|
|
113
|
+
if (structured.length === 0)
|
|
114
|
+
return undefined;
|
|
115
|
+
const summary = value
|
|
116
|
+
.filter((item) => item === null || typeof item !== 'object')
|
|
117
|
+
.filter((item) => item !== '[undefined]' && typeof item !== 'undefined')
|
|
118
|
+
.map(formatConsolePrimitive)
|
|
119
|
+
.filter(Boolean)
|
|
120
|
+
.join(' ');
|
|
121
|
+
const lines = [summary || 'details'];
|
|
122
|
+
if (structured.length === 1) {
|
|
123
|
+
const item = structured[0]?.item;
|
|
124
|
+
if (item && typeof item === 'object') {
|
|
125
|
+
lines.push(...formatStructuredTree(item, style));
|
|
126
|
+
}
|
|
127
|
+
return lines;
|
|
128
|
+
}
|
|
129
|
+
for (const { index, item } of structured) {
|
|
130
|
+
lines.push(...formatStructuredTree({ [`arg ${index + 1}`]: item }, style));
|
|
131
|
+
}
|
|
132
|
+
return lines;
|
|
133
|
+
}
|
|
134
|
+
function formatConsolePrimitive(value) {
|
|
135
|
+
if (typeof value === 'string')
|
|
136
|
+
return value;
|
|
137
|
+
if (value === null)
|
|
138
|
+
return 'null';
|
|
139
|
+
return String(value);
|
|
140
|
+
}
|
|
141
|
+
function formatFields(fields) {
|
|
142
|
+
if (Object.keys(fields).length === 0)
|
|
143
|
+
return undefined;
|
|
144
|
+
try {
|
|
145
|
+
return JSON.stringify(fields);
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return '[unserializable fields]';
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
function splitStructuredMessage(message) {
|
|
152
|
+
const text = message.trimEnd();
|
|
153
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
154
|
+
const token = text[index];
|
|
155
|
+
if (token !== '{' && token !== '[')
|
|
156
|
+
continue;
|
|
157
|
+
if (index > 0 && !/\s/.test(text[index - 1] ?? ''))
|
|
158
|
+
continue;
|
|
159
|
+
try {
|
|
160
|
+
const value = JSON.parse(text.slice(index));
|
|
161
|
+
if (!value || typeof value !== 'object')
|
|
162
|
+
continue;
|
|
163
|
+
return {
|
|
164
|
+
summary: text.slice(0, index).trimEnd(),
|
|
165
|
+
value: value,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
// Prefixes such as "[component]" contain JSON-looking tokens. Keep
|
|
170
|
+
// scanning until a suffix parses as a complete structured value.
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
175
|
+
function formatStructuredTree(value, style) {
|
|
176
|
+
const entries = Array.isArray(value)
|
|
177
|
+
? value.map((item, index) => [String(index), item])
|
|
178
|
+
: Object.entries(value);
|
|
179
|
+
const maxEntries = 12;
|
|
180
|
+
const shown = entries.slice(0, maxEntries);
|
|
181
|
+
const lines = shown.map(([key, item], index) => {
|
|
182
|
+
const isLast = index === shown.length - 1 && entries.length <= maxEntries;
|
|
183
|
+
const branch = style.unicode ? (isLast ? '└─' : '├─') : isLast ? '`-' : '|-';
|
|
184
|
+
return ` ${style.dim(branch)} ${style.cyan(key)}${style.dim(':')} ${formatStructuredValue(item)}`;
|
|
185
|
+
});
|
|
186
|
+
if (entries.length > maxEntries) {
|
|
187
|
+
const branch = style.unicode ? '└─' : '`-';
|
|
188
|
+
lines.push(` ${style.dim(branch)} ${style.dim(`… ${entries.length - maxEntries} more fields`)}`);
|
|
189
|
+
}
|
|
190
|
+
return lines;
|
|
191
|
+
}
|
|
192
|
+
function formatStructuredValue(value) {
|
|
193
|
+
if (value === null)
|
|
194
|
+
return 'null';
|
|
195
|
+
if (typeof value === 'string') {
|
|
196
|
+
return /\s/.test(value) ? truncateValue(JSON.stringify(value), 260) : truncateValue(value, 260);
|
|
197
|
+
}
|
|
198
|
+
if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {
|
|
199
|
+
return String(value);
|
|
200
|
+
}
|
|
201
|
+
if (typeof value === 'undefined')
|
|
202
|
+
return 'undefined';
|
|
203
|
+
if (Array.isArray(value))
|
|
204
|
+
return truncateValue(safeJson(value), 260);
|
|
205
|
+
if (typeof value === 'object') {
|
|
206
|
+
const pairs = Object.entries(value).map(([key, nested]) => `${key}=${formatNestedValue(nested)}`);
|
|
207
|
+
return truncateValue(pairs.join(' '), 260);
|
|
208
|
+
}
|
|
209
|
+
return truncateValue(String(value), 260);
|
|
210
|
+
}
|
|
211
|
+
function formatNestedValue(value) {
|
|
212
|
+
if (value === null)
|
|
213
|
+
return 'null';
|
|
214
|
+
if (typeof value === 'string')
|
|
215
|
+
return /\s/.test(value) ? JSON.stringify(value) : value;
|
|
216
|
+
if (typeof value === 'object')
|
|
217
|
+
return safeJson(value);
|
|
218
|
+
return String(value);
|
|
219
|
+
}
|
|
220
|
+
function safeJson(value) {
|
|
221
|
+
try {
|
|
222
|
+
return JSON.stringify(value) ?? String(value);
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
return '[unserializable]';
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
function truncateValue(value, max) {
|
|
229
|
+
return value.length <= max ? value : `${value.slice(0, Math.max(0, max - 1))}…`;
|
|
230
|
+
}
|
|
231
|
+
function formatTimestamp(ts) {
|
|
232
|
+
const d = new Date(ts);
|
|
233
|
+
const hh = String(d.getHours()).padStart(2, '0');
|
|
234
|
+
const mm = String(d.getMinutes()).padStart(2, '0');
|
|
235
|
+
const ss = String(d.getSeconds()).padStart(2, '0');
|
|
236
|
+
const ms = String(d.getMilliseconds()).padStart(3, '0');
|
|
237
|
+
return `${hh}:${mm}:${ss}.${ms}`;
|
|
238
|
+
}
|
|
239
|
+
function paintLane(lane, style) {
|
|
240
|
+
const label = LANE_LABEL[lane];
|
|
241
|
+
if (lane === 'frontend')
|
|
242
|
+
return style.orange(label);
|
|
243
|
+
if (lane === 'backend')
|
|
244
|
+
return style.green(label);
|
|
245
|
+
if (lane === 'hubspot')
|
|
246
|
+
return style.yellow(label);
|
|
247
|
+
return style.dim(label);
|
|
248
|
+
}
|
|
249
|
+
function paintLevel(level, style) {
|
|
250
|
+
const padded = level.padEnd(5, ' ');
|
|
251
|
+
switch (level) {
|
|
252
|
+
case 'error':
|
|
253
|
+
return style.red(padded);
|
|
254
|
+
case 'warn':
|
|
255
|
+
return style.yellow(padded);
|
|
256
|
+
case 'debug':
|
|
257
|
+
return style.dim(padded);
|
|
258
|
+
default:
|
|
259
|
+
return style.dim(padded);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
//# sourceMappingURL=stream-event-format.js.map
|