@dcl/sdk-commands 7.31.1-40606969412.commit-24c05c3 → 7.31.1-41472004640.commit-3147448
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 +15 -0
- package/dist/commands/scene-insights/actions.d.ts +63 -0
- package/dist/commands/scene-insights/actions.js +106 -0
- package/dist/commands/scene-insights/actions.js.map +1 -0
- package/dist/commands/scene-insights/client.d.ts +51 -0
- package/dist/commands/scene-insights/client.js +294 -0
- package/dist/commands/scene-insights/client.js.map +1 -0
- package/dist/commands/scene-insights/format.d.ts +23 -0
- package/dist/commands/scene-insights/format.js +143 -0
- package/dist/commands/scene-insights/format.js.map +1 -0
- package/dist/commands/scene-insights/index.d.ts +51 -0
- package/dist/commands/scene-insights/index.js +312 -0
- package/dist/commands/scene-insights/index.js.map +1 -0
- package/dist/commands/scene-insights/inputs.d.ts +49 -0
- package/dist/commands/scene-insights/inputs.js +166 -0
- package/dist/commands/scene-insights/inputs.js.map +1 -0
- package/dist/commands/scene-insights/session-store.d.ts +42 -0
- package/dist/commands/scene-insights/session-store.js +131 -0
- package/dist/commands/scene-insights/session-store.js.map +1 -0
- package/dist/commands/scene-insights/session.d.ts +42 -0
- package/dist/commands/scene-insights/session.js +97 -0
- package/dist/commands/scene-insights/session.js.map +1 -0
- package/dist/commands/scene-insights/sign-in.d.ts +48 -0
- package/dist/commands/scene-insights/sign-in.js +116 -0
- package/dist/commands/scene-insights/sign-in.js.map +1 -0
- package/dist/commands/scene-insights/types.d.ts +61 -0
- package/dist/commands/scene-insights/types.js +4 -0
- package/dist/commands/scene-insights/types.js.map +1 -0
- package/dist/logic/error.d.ts +1 -1
- package/dist/logic/error.js.map +1 -1
- package/dist/run-command.js +3 -2
- package/dist/run-command.js.map +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -105,3 +105,18 @@ make sync-deps
|
|
|
105
105
|
For detailed documentation on using the CLI tools, visit:
|
|
106
106
|
|
|
107
107
|
- [CLI Documentation](https://docs.decentraland.org/creator/development-guide/sdk7/cli/)
|
|
108
|
+
|
|
109
|
+
### Scene Insights scoped sessions
|
|
110
|
+
|
|
111
|
+
`scene-insights login` requests a 12-hour scoped login with only `insights:logs-read`,
|
|
112
|
+
`insights:metrics-read`, and `insights:executions-read`. Browser and `DCL_PRIVATE_KEY`
|
|
113
|
+
sessions use these same explicit grants. They cover scenes the wallet already has
|
|
114
|
+
permission to read; the credential is not restricted to a single scene. No wildcard
|
|
115
|
+
or write operation is granted. Environments sharing the `insights` service identifier
|
|
116
|
+
(including `.org` and `.zone`) accept the same credential. The signed headers don't
|
|
117
|
+
name the host, so `--target` only accepts https hosts under `decentraland.org` or
|
|
118
|
+
`decentraland.zone` unless `--trust-target` is passed.
|
|
119
|
+
|
|
120
|
+
Previously saved full-login sessions require signing in again. A saved scoped
|
|
121
|
+
session expires no later than its parent delegation. Deploy the scoped-login
|
|
122
|
+
Insights server before using this command version.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { InsightsClient } from './client';
|
|
2
|
+
import { LogLevel } from './inputs';
|
|
3
|
+
import { ExecutionsResult, LogEntry, MetricNamesResult, MetricSeries } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Where results go: text to `write` (stdout), notes about it to `note` (stderr). With `json`, a
|
|
6
|
+
* subcommand prints no text and returns its result instead, which the CLI prints as JSON (the
|
|
7
|
+
* `--json` convention of every sdk-commands command); only the tail, a stream, writes its own
|
|
8
|
+
* JSON, one entry per line.
|
|
9
|
+
*/
|
|
10
|
+
export interface Output {
|
|
11
|
+
write(line: string): void;
|
|
12
|
+
note(message: string): void;
|
|
13
|
+
json: boolean;
|
|
14
|
+
color: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface LogsResult {
|
|
17
|
+
sceneKey: string;
|
|
18
|
+
/** Oldest first */
|
|
19
|
+
logs: LogEntry[];
|
|
20
|
+
/** Whether more lines matched than were returned */
|
|
21
|
+
more: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface LogsParams {
|
|
24
|
+
from?: string;
|
|
25
|
+
to?: string;
|
|
26
|
+
level?: LogLevel;
|
|
27
|
+
source?: string;
|
|
28
|
+
query?: string;
|
|
29
|
+
execution?: string;
|
|
30
|
+
/** Lines to print in total, across pages */
|
|
31
|
+
limit: number;
|
|
32
|
+
/** `desc` prints the newest `limit` lines, `asc` the oldest */
|
|
33
|
+
order: 'asc' | 'desc';
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Searches the persisted logs, paging until `limit` lines, and prints them oldest first.
|
|
37
|
+
*/
|
|
38
|
+
export declare function runLogs(client: InsightsClient, params: LogsParams, output: Output): Promise<LogsResult>;
|
|
39
|
+
export interface TailParams {
|
|
40
|
+
/** Replay the newest N lines before following */
|
|
41
|
+
lines?: number;
|
|
42
|
+
/** Only print lines at this level or above */
|
|
43
|
+
level?: LogLevel;
|
|
44
|
+
/** Only print lines containing this text (case-insensitive) */
|
|
45
|
+
query?: string;
|
|
46
|
+
signal?: AbortSignal;
|
|
47
|
+
}
|
|
48
|
+
/** Whether an entry passes the tail's local filters (the tail endpoint has none of its own). */
|
|
49
|
+
export declare function matchesTailFilters(entry: LogEntry, params: Pick<TailParams, 'level' | 'query'>): boolean;
|
|
50
|
+
/** Follows the live tail until interrupted or `signal` aborts. */
|
|
51
|
+
export declare function runTail(client: InsightsClient, params: TailParams, output: Output): Promise<void>;
|
|
52
|
+
export interface MetricsParams {
|
|
53
|
+
/** A full metric name; without it the metrics with data are listed */
|
|
54
|
+
metric?: string;
|
|
55
|
+
from?: string;
|
|
56
|
+
to?: string;
|
|
57
|
+
step?: number;
|
|
58
|
+
execution?: string;
|
|
59
|
+
}
|
|
60
|
+
/** Lists the scene's metrics, or prints one metric's series. */
|
|
61
|
+
export declare function runMetrics(client: InsightsClient, params: MetricsParams, output: Output): Promise<MetricNamesResult | MetricSeries>;
|
|
62
|
+
/** Lists the scene's executions (deployments × process restarts). */
|
|
63
|
+
export declare function runExecutions(client: InsightsClient, params: Pick<MetricsParams, 'from' | 'to'>, output: Output): Promise<ExecutionsResult>;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runLogs = runLogs;
|
|
4
|
+
exports.matchesTailFilters = matchesTailFilters;
|
|
5
|
+
exports.runTail = runTail;
|
|
6
|
+
exports.runMetrics = runMetrics;
|
|
7
|
+
exports.runExecutions = runExecutions;
|
|
8
|
+
const format_1 = require("./format");
|
|
9
|
+
const inputs_1 = require("./inputs");
|
|
10
|
+
/** The service's page size cap. */
|
|
11
|
+
const MAX_PAGE = 1000;
|
|
12
|
+
/**
|
|
13
|
+
* Searches the persisted logs, paging until `limit` lines, and prints them oldest first.
|
|
14
|
+
*/
|
|
15
|
+
async function runLogs(client, params, output) {
|
|
16
|
+
const entries = [];
|
|
17
|
+
let cursor;
|
|
18
|
+
let more = false;
|
|
19
|
+
let sceneKey = '';
|
|
20
|
+
do {
|
|
21
|
+
const page = await client.searchLogs({
|
|
22
|
+
from: params.from,
|
|
23
|
+
to: params.to,
|
|
24
|
+
level: params.level,
|
|
25
|
+
source: params.source,
|
|
26
|
+
q: params.query,
|
|
27
|
+
execution: params.execution,
|
|
28
|
+
order: params.order,
|
|
29
|
+
limit: Math.min(MAX_PAGE, params.limit - entries.length),
|
|
30
|
+
cursor
|
|
31
|
+
});
|
|
32
|
+
sceneKey = page.sceneKey;
|
|
33
|
+
entries.push(...page.logs);
|
|
34
|
+
// an empty page with a cursor would otherwise be requested forever
|
|
35
|
+
cursor = page.logs.length > 0 ? (page.nextCursor ?? undefined) : undefined;
|
|
36
|
+
more = !!cursor;
|
|
37
|
+
} while (cursor && entries.length < params.limit);
|
|
38
|
+
const result = { sceneKey, logs: params.order === 'desc' ? entries.reverse() : entries, more };
|
|
39
|
+
if (output.json)
|
|
40
|
+
return result;
|
|
41
|
+
for (const entry of result.logs) {
|
|
42
|
+
output.write((0, format_1.formatLogEntry)(entry, output.color));
|
|
43
|
+
}
|
|
44
|
+
if (entries.length === 0) {
|
|
45
|
+
output.note('No log lines match');
|
|
46
|
+
}
|
|
47
|
+
else if (more) {
|
|
48
|
+
output.note(`Printed ${entries.length} lines; more match. Raise --limit or narrow --from/--to, --level or --query to see them.`);
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
/** Whether an entry passes the tail's local filters (the tail endpoint has none of its own). */
|
|
53
|
+
function matchesTailFilters(entry, params) {
|
|
54
|
+
if (params.level && inputs_1.LOG_LEVELS.indexOf(entry.level) < inputs_1.LOG_LEVELS.indexOf(params.level)) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
if (params.query && !entry.message.toLowerCase().includes(params.query.toLowerCase())) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
/** Follows the live tail until interrupted or `signal` aborts. */
|
|
63
|
+
async function runTail(client, params, output) {
|
|
64
|
+
output.note('Following the scene logs');
|
|
65
|
+
await client.tail({
|
|
66
|
+
lines: params.lines,
|
|
67
|
+
signal: params.signal,
|
|
68
|
+
onLog(entry) {
|
|
69
|
+
if (matchesTailFilters(entry, params)) {
|
|
70
|
+
output.write(output.json ? JSON.stringify(entry) : (0, format_1.formatLogEntry)(entry, output.color));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/** Lists the scene's metrics, or prints one metric's series. */
|
|
76
|
+
async function runMetrics(client, params, output) {
|
|
77
|
+
if (!params.metric) {
|
|
78
|
+
const names = await client.listMetrics({ from: params.from, to: params.to });
|
|
79
|
+
if (output.json)
|
|
80
|
+
return names;
|
|
81
|
+
(0, format_1.formatMetricNames)(names).forEach((line) => output.write(line));
|
|
82
|
+
if (names.metrics.length > 0) {
|
|
83
|
+
output.note('Chart one with: scene-insights metrics <name>');
|
|
84
|
+
}
|
|
85
|
+
return names;
|
|
86
|
+
}
|
|
87
|
+
const series = await client.getMetricSeries(params.metric, {
|
|
88
|
+
from: params.from,
|
|
89
|
+
to: params.to,
|
|
90
|
+
step: params.step,
|
|
91
|
+
execution: params.execution
|
|
92
|
+
});
|
|
93
|
+
if (output.json)
|
|
94
|
+
return series;
|
|
95
|
+
(0, format_1.formatMetricSeries)(series).forEach((line) => output.write(line));
|
|
96
|
+
return series;
|
|
97
|
+
}
|
|
98
|
+
/** Lists the scene's executions (deployments × process restarts). */
|
|
99
|
+
async function runExecutions(client, params, output) {
|
|
100
|
+
const result = await client.listExecutions({ from: params.from, to: params.to });
|
|
101
|
+
if (output.json)
|
|
102
|
+
return result;
|
|
103
|
+
(0, format_1.formatExecutions)(result).forEach((line) => output.write(line));
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=actions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actions.js","sourceRoot":"","sources":["../../../src/commands/scene-insights/actions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { CliComponents } from '../../components';
|
|
2
|
+
import { CliError, CliErrorName } from '../../logic/error';
|
|
3
|
+
import { InsightsSession } from './session';
|
|
4
|
+
import { ExecutionsResult, LogEntry, LogSearchResult, MetricNamesResult, MetricSeries } from './types';
|
|
5
|
+
/** Query parameters; undefined values are left out. */
|
|
6
|
+
export type Query = Record<string, string | number | undefined>;
|
|
7
|
+
export interface InsightsClient {
|
|
8
|
+
searchLogs(query: Query): Promise<LogSearchResult>;
|
|
9
|
+
listExecutions(query: Query): Promise<ExecutionsResult>;
|
|
10
|
+
/** The metrics with data for the scene (`GET /v1/metrics`). */
|
|
11
|
+
listMetrics(query: Query): Promise<MetricNamesResult>;
|
|
12
|
+
/** One metric's series (`GET /v1/metrics/<metric>/series`); the metric name is part of the signed path. */
|
|
13
|
+
getMetricSeries(metric: string, query: Query): Promise<MetricSeries>;
|
|
14
|
+
/**
|
|
15
|
+
* Follows the live tail until `signal` aborts or the service ends the stream with an error.
|
|
16
|
+
* Reconnects on its own after a dropped connection or a server restart, resuming from the last
|
|
17
|
+
* event, and never delivers the same line twice.
|
|
18
|
+
*/
|
|
19
|
+
tail(options: {
|
|
20
|
+
lines?: number;
|
|
21
|
+
signal?: AbortSignal;
|
|
22
|
+
onLog: (entry: LogEntry) => void;
|
|
23
|
+
}): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
export interface ServerSentEvent {
|
|
26
|
+
event: string;
|
|
27
|
+
data: string;
|
|
28
|
+
id?: string;
|
|
29
|
+
retry?: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Incremental `text/event-stream` parser: feed it decoded chunks, and it calls `onEvent` for every
|
|
33
|
+
* complete event. Comments (`: ping`) are skipped.
|
|
34
|
+
*/
|
|
35
|
+
export declare function createSseParser(onEvent: (event: ServerSentEvent) => void): {
|
|
36
|
+
push(chunk: string): void;
|
|
37
|
+
};
|
|
38
|
+
/** Remembers the most recent ids, forgetting the oldest past its capacity. */
|
|
39
|
+
export declare function createRecentIds(capacity: number): {
|
|
40
|
+
/** Records the id; false when it was already seen. */
|
|
41
|
+
add(id: string): boolean;
|
|
42
|
+
};
|
|
43
|
+
/** The Retry-After delay of a response, bounded, in milliseconds. */
|
|
44
|
+
export declare function retryAfterMs(response: Response): number;
|
|
45
|
+
/** Turns an error response into a CliError named after what went wrong, saying what to do about it. */
|
|
46
|
+
export declare function errorFromResponse(response: Response): Promise<CliError<CliErrorName>>;
|
|
47
|
+
/**
|
|
48
|
+
* Client of multiplayer-scenes-insights-service. Every request is signed with the session for the
|
|
49
|
+
* target scene (the service reads the scene from the signed metadata, never from the query).
|
|
50
|
+
*/
|
|
51
|
+
export declare function createInsightsClient(components: Pick<CliComponents, 'fetch' | 'logger'>, baseUrl: string, session: InsightsSession, metadata: string): InsightsClient;
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createSseParser = createSseParser;
|
|
4
|
+
exports.createRecentIds = createRecentIds;
|
|
5
|
+
exports.retryAfterMs = retryAfterMs;
|
|
6
|
+
exports.errorFromResponse = errorFromResponse;
|
|
7
|
+
exports.createInsightsClient = createInsightsClient;
|
|
8
|
+
const error_1 = require("../../logic/error");
|
|
9
|
+
const format_1 = require("./format");
|
|
10
|
+
/** Retries of a request the service refused for capacity (429/503 with Retry-After). */
|
|
11
|
+
const MAX_BUSY_RETRIES = 3;
|
|
12
|
+
const MAX_RETRY_AFTER_MS = 10000;
|
|
13
|
+
/** Reconnect delays of a tail whose connection failed, doubled up to the maximum. */
|
|
14
|
+
const TAIL_RECONNECT_MIN_MS = 1000;
|
|
15
|
+
const TAIL_RECONNECT_MAX_MS = 30000;
|
|
16
|
+
/** Event ids remembered to drop the lines the service sends twice around a reconnect. */
|
|
17
|
+
const TAIL_SEEN_IDS = 10000;
|
|
18
|
+
/**
|
|
19
|
+
* Incremental `text/event-stream` parser: feed it decoded chunks, and it calls `onEvent` for every
|
|
20
|
+
* complete event. Comments (`: ping`) are skipped.
|
|
21
|
+
*/
|
|
22
|
+
function createSseParser(onEvent) {
|
|
23
|
+
let buffer = '';
|
|
24
|
+
let event = '';
|
|
25
|
+
let data = [];
|
|
26
|
+
let id;
|
|
27
|
+
let retry;
|
|
28
|
+
function dispatch() {
|
|
29
|
+
if (data.length > 0 || retry !== undefined) {
|
|
30
|
+
onEvent({ event: event || 'message', data: data.join('\n'), id, retry });
|
|
31
|
+
}
|
|
32
|
+
event = '';
|
|
33
|
+
data = [];
|
|
34
|
+
id = undefined;
|
|
35
|
+
retry = undefined;
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
push(chunk) {
|
|
39
|
+
buffer += chunk;
|
|
40
|
+
const lines = buffer.split(/\r\n|\r|\n/);
|
|
41
|
+
buffer = lines.pop() ?? '';
|
|
42
|
+
for (const line of lines) {
|
|
43
|
+
if (line === '') {
|
|
44
|
+
dispatch();
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (line.startsWith(':'))
|
|
48
|
+
continue;
|
|
49
|
+
const separator = line.indexOf(':');
|
|
50
|
+
const field = separator === -1 ? line : line.slice(0, separator);
|
|
51
|
+
let value = separator === -1 ? '' : line.slice(separator + 1);
|
|
52
|
+
if (value.startsWith(' '))
|
|
53
|
+
value = value.slice(1);
|
|
54
|
+
if (field === 'event')
|
|
55
|
+
event = value;
|
|
56
|
+
else if (field === 'data')
|
|
57
|
+
data.push(value);
|
|
58
|
+
else if (field === 'id')
|
|
59
|
+
id = value;
|
|
60
|
+
else if (field === 'retry' && /^\d+$/.test(value))
|
|
61
|
+
retry = parseInt(value, 10);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/** Remembers the most recent ids, forgetting the oldest past its capacity. */
|
|
67
|
+
function createRecentIds(capacity) {
|
|
68
|
+
const ids = new Set();
|
|
69
|
+
return {
|
|
70
|
+
/** Records the id; false when it was already seen. */
|
|
71
|
+
add(id) {
|
|
72
|
+
if (ids.has(id))
|
|
73
|
+
return false;
|
|
74
|
+
ids.add(id);
|
|
75
|
+
if (ids.size > capacity) {
|
|
76
|
+
ids.delete(ids.values().next().value);
|
|
77
|
+
}
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/** The Retry-After delay of a response, bounded, in milliseconds. */
|
|
83
|
+
function retryAfterMs(response) {
|
|
84
|
+
const seconds = Number(response.headers.get('retry-after'));
|
|
85
|
+
return Math.min(Number.isFinite(seconds) && seconds > 0 ? seconds * 1000 : 1000, MAX_RETRY_AFTER_MS);
|
|
86
|
+
}
|
|
87
|
+
/** The error name of each status a caller can act on; anything else is a plain request failure. */
|
|
88
|
+
const ERRORS_BY_STATUS = {
|
|
89
|
+
400: { name: 'SCENE_INSIGHTS_INVALID_ARGUMENT' },
|
|
90
|
+
401: {
|
|
91
|
+
name: 'SCENE_INSIGHTS_UNAUTHORIZED',
|
|
92
|
+
hint: 'the session was refused; run "sdk-commands scene-insights login" to sign a new one'
|
|
93
|
+
},
|
|
94
|
+
403: {
|
|
95
|
+
name: 'SCENE_INSIGHTS_FORBIDDEN',
|
|
96
|
+
hint: "the signed-in address is not in the scene's logsPermissions, and is not the World's owner or a deployer"
|
|
97
|
+
},
|
|
98
|
+
404: { name: 'SCENE_INSIGHTS_NOT_FOUND', hint: 'no deployed scene matches the World or parcel' },
|
|
99
|
+
429: { name: 'SCENE_INSIGHTS_UNAVAILABLE', hint: 'too many requests; try again shortly' },
|
|
100
|
+
503: { name: 'SCENE_INSIGHTS_UNAVAILABLE', hint: 'try again shortly' },
|
|
101
|
+
504: { name: 'SCENE_INSIGHTS_UNAVAILABLE', hint: 'the query timed out; narrow --from/--to or the filters' }
|
|
102
|
+
};
|
|
103
|
+
/** Turns an error response into a CliError named after what went wrong, saying what to do about it. */
|
|
104
|
+
async function errorFromResponse(response) {
|
|
105
|
+
let reason = '';
|
|
106
|
+
try {
|
|
107
|
+
const text = await response.text();
|
|
108
|
+
try {
|
|
109
|
+
reason = String(JSON.parse(text).error ?? text);
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
reason = text;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// keep the status alone
|
|
117
|
+
}
|
|
118
|
+
reason = (0, format_1.stripControlCharacters)(reason);
|
|
119
|
+
const { name, hint } = ERRORS_BY_STATUS[response.status] ?? { name: 'SCENE_INSIGHTS_REQUEST_FAILED' };
|
|
120
|
+
const message = `The insights service answered ${response.status}${reason ? `: ${reason}` : ''}${hint ? ` (${hint})` : ''}`;
|
|
121
|
+
return new error_1.CliError(name, message);
|
|
122
|
+
}
|
|
123
|
+
/** A request that never got an answer (DNS, connection refused, reset). */
|
|
124
|
+
function unreachable(baseUrl, error) {
|
|
125
|
+
const cause = error?.cause?.code ?? error?.message;
|
|
126
|
+
return new error_1.CliError('SCENE_INSIGHTS_UNAVAILABLE', `Could not reach ${baseUrl}${cause ? ` (${cause})` : ''}`);
|
|
127
|
+
}
|
|
128
|
+
/** Whether a parsed `log` event has the fields the tail prints and filters on. */
|
|
129
|
+
function isLogEntry(value) {
|
|
130
|
+
const entry = value;
|
|
131
|
+
return (typeof entry === 'object' &&
|
|
132
|
+
entry !== null &&
|
|
133
|
+
typeof entry.message === 'string' &&
|
|
134
|
+
typeof entry.level === 'string' &&
|
|
135
|
+
typeof entry.source === 'string' &&
|
|
136
|
+
typeof entry.timestamp === 'string');
|
|
137
|
+
}
|
|
138
|
+
const sleep = (ms, signal) => new Promise((resolve) => {
|
|
139
|
+
const timer = setTimeout(done, ms);
|
|
140
|
+
function done() {
|
|
141
|
+
clearTimeout(timer);
|
|
142
|
+
signal?.removeEventListener('abort', done);
|
|
143
|
+
resolve();
|
|
144
|
+
}
|
|
145
|
+
signal?.addEventListener('abort', done, { once: true });
|
|
146
|
+
});
|
|
147
|
+
/**
|
|
148
|
+
* Client of multiplayer-scenes-insights-service. Every request is signed with the session for the
|
|
149
|
+
* target scene (the service reads the scene from the signed metadata, never from the query).
|
|
150
|
+
*/
|
|
151
|
+
function createInsightsClient(components, baseUrl, session, metadata) {
|
|
152
|
+
const { fetch, logger } = components;
|
|
153
|
+
const base = baseUrl.replace(/\/+$/, '');
|
|
154
|
+
function urlFor(pathname, query = {}) {
|
|
155
|
+
const url = new URL(base + pathname);
|
|
156
|
+
for (const [key, value] of Object.entries(query)) {
|
|
157
|
+
if (value !== undefined)
|
|
158
|
+
url.searchParams.set(key, String(value));
|
|
159
|
+
}
|
|
160
|
+
return url.toString();
|
|
161
|
+
}
|
|
162
|
+
async function get(pathname, query) {
|
|
163
|
+
for (let attempt = 0;; attempt++) {
|
|
164
|
+
let response;
|
|
165
|
+
try {
|
|
166
|
+
response = await fetch.fetch(urlFor(pathname, query), {
|
|
167
|
+
headers: { ...session.sign('GET', pathname, metadata), Accept: 'application/json' }
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
throw unreachable(base, error);
|
|
172
|
+
}
|
|
173
|
+
if (response.ok) {
|
|
174
|
+
return readJson(response);
|
|
175
|
+
}
|
|
176
|
+
if ((response.status === 429 || response.status === 503) && attempt < MAX_BUSY_RETRIES) {
|
|
177
|
+
const delay = retryAfterMs(response);
|
|
178
|
+
// an unread body keeps its socket until it is garbage collected
|
|
179
|
+
await response.body?.cancel();
|
|
180
|
+
logger.log(`The insights service is busy (${response.status}); retrying in ${Math.ceil(delay / 1000)}s`);
|
|
181
|
+
await sleep(delay);
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
throw await errorFromResponse(response);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
async function readJson(response) {
|
|
188
|
+
let text;
|
|
189
|
+
try {
|
|
190
|
+
text = await response.text();
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
throw unreachable(base, error);
|
|
194
|
+
}
|
|
195
|
+
try {
|
|
196
|
+
return JSON.parse(text);
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
throw new error_1.CliError('SCENE_INSIGHTS_REQUEST_FAILED', `The insights service answered ${response.status} with a body that is not JSON: ${(0, format_1.stripControlCharacters)(text.slice(0, 200))}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
async function tail({ lines, signal, onLog }) {
|
|
203
|
+
const pathname = '/v1/logs/tail';
|
|
204
|
+
const seen = createRecentIds(TAIL_SEEN_IDS);
|
|
205
|
+
let lastEventId;
|
|
206
|
+
let reconnectMs = TAIL_RECONNECT_MIN_MS;
|
|
207
|
+
while (!signal?.aborted) {
|
|
208
|
+
let serverRetryMs;
|
|
209
|
+
let streamError;
|
|
210
|
+
try {
|
|
211
|
+
// Replayed lines carry no resume id: until a live line gives one, a
|
|
212
|
+
// reconnect asks for the history again and `seen` drops what was shown.
|
|
213
|
+
const response = await fetch.fetch(urlFor(pathname, !lastEventId && lines ? { lines } : {}), {
|
|
214
|
+
headers: {
|
|
215
|
+
...session.sign('GET', pathname, metadata),
|
|
216
|
+
Accept: 'text/event-stream',
|
|
217
|
+
...(lastEventId && { 'Last-Event-ID': lastEventId })
|
|
218
|
+
},
|
|
219
|
+
signal
|
|
220
|
+
});
|
|
221
|
+
if (!response.ok) {
|
|
222
|
+
if (response.status !== 429 && response.status !== 503) {
|
|
223
|
+
throw await errorFromResponse(response);
|
|
224
|
+
}
|
|
225
|
+
serverRetryMs = retryAfterMs(response);
|
|
226
|
+
await response.body?.cancel();
|
|
227
|
+
logger.log(`The insights service is busy (${response.status}); reconnecting`);
|
|
228
|
+
}
|
|
229
|
+
else if (response.body) {
|
|
230
|
+
reconnectMs = TAIL_RECONNECT_MIN_MS;
|
|
231
|
+
const decoder = new TextDecoder();
|
|
232
|
+
const parser = createSseParser((event) => {
|
|
233
|
+
if (event.retry !== undefined)
|
|
234
|
+
serverRetryMs = event.retry;
|
|
235
|
+
if (event.event === 'error') {
|
|
236
|
+
try {
|
|
237
|
+
streamError = String(JSON.parse(event.data).error);
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
streamError = event.data;
|
|
241
|
+
}
|
|
242
|
+
streamError = (0, format_1.stripControlCharacters)(streamError);
|
|
243
|
+
}
|
|
244
|
+
else if (event.event === 'log') {
|
|
245
|
+
if (event.id)
|
|
246
|
+
lastEventId = event.id;
|
|
247
|
+
// skipped rather than thrown: a throw here reads as a dropped connection and resumes at the same line
|
|
248
|
+
let entry;
|
|
249
|
+
try {
|
|
250
|
+
entry = JSON.parse(event.data);
|
|
251
|
+
}
|
|
252
|
+
catch {
|
|
253
|
+
entry = undefined;
|
|
254
|
+
}
|
|
255
|
+
if (!isLogEntry(entry)) {
|
|
256
|
+
logger.log(`Skipped a malformed log line from the insights service${event.id ? ` (event ${event.id})` : ''}`);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
// an empty id means the line has none: never treat it as a repeat
|
|
260
|
+
if (!entry.id || seen.add(entry.id))
|
|
261
|
+
onLog(entry);
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
for await (const chunk of response.body) {
|
|
265
|
+
parser.push(decoder.decode(chunk, { stream: true }));
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
catch (e) {
|
|
270
|
+
if (signal?.aborted)
|
|
271
|
+
return;
|
|
272
|
+
if (e instanceof error_1.CliError)
|
|
273
|
+
throw e;
|
|
274
|
+
logger.log(`The tail connection dropped (${e.message}); reconnecting`);
|
|
275
|
+
}
|
|
276
|
+
if (streamError !== undefined) {
|
|
277
|
+
throw new error_1.CliError('SCENE_INSIGHTS_STREAM_ENDED', `The insights service ended the tail: ${streamError}`);
|
|
278
|
+
}
|
|
279
|
+
if (signal?.aborted)
|
|
280
|
+
return;
|
|
281
|
+
const delay = serverRetryMs ?? reconnectMs;
|
|
282
|
+
reconnectMs = Math.min(reconnectMs * 2, TAIL_RECONNECT_MAX_MS);
|
|
283
|
+
await sleep(delay, signal);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return {
|
|
287
|
+
searchLogs: (query) => get('/v1/logs', query),
|
|
288
|
+
listExecutions: (query) => get('/v1/executions', query),
|
|
289
|
+
listMetrics: (query) => get('/v1/metrics', query),
|
|
290
|
+
getMetricSeries: (metric, query) => get(`/v1/metrics/${encodeURIComponent(metric)}/series`, query),
|
|
291
|
+
tail
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/commands/scene-insights/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ExecutionsResult, LogEntry, MetricNamesResult, MetricSeries } from './types';
|
|
2
|
+
/** Removes what a terminal would interpret (cursor moves, OSC 8 links, OSC 52 clipboard writes) from service text. */
|
|
3
|
+
export declare function stripControlCharacters(text: string): string;
|
|
4
|
+
/** `2026-10-12T14:13:02.166Z` → `2026-10-12 14:13:02.166Z`; anything unparseable is returned as is. */
|
|
5
|
+
export declare function formatTimestamp(iso: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* One log entry as terminal text: time, level, the source when it is not the scene itself, and the
|
|
8
|
+
* message, with the lines of a multi-line message indented under the first.
|
|
9
|
+
*/
|
|
10
|
+
export declare function formatLogEntry(entry: LogEntry, color: boolean): string;
|
|
11
|
+
/** A value in its unit: bytes in binary multiples, milliseconds up to seconds, counts as numbers. */
|
|
12
|
+
export declare function formatValue(value: number | null, unit: string): string;
|
|
13
|
+
/** A one-line chart of the values; gaps are blanks. */
|
|
14
|
+
export declare function sparkline(values: Array<number | null>): string;
|
|
15
|
+
/** Left-aligned columns separated by two spaces. */
|
|
16
|
+
export declare function formatTable(header: string[], rawRows: string[][]): string[];
|
|
17
|
+
export declare function formatMetricNames(result: MetricNamesResult): string[];
|
|
18
|
+
/**
|
|
19
|
+
* A metric series: a header, a sparkline, and one row per bucket. Gauges show the average and the
|
|
20
|
+
* maximum; sums show the bucket total and its rate per second.
|
|
21
|
+
*/
|
|
22
|
+
export declare function formatMetricSeries(series: MetricSeries): string[];
|
|
23
|
+
export declare function formatExecutions(result: ExecutionsResult): string[];
|