@dcl/sdk-commands 7.31.1-40962203448.commit-c68a75f → 7.31.1-41498712919.commit-5e4cada

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.
Files changed (100) hide show
  1. package/README.md +33 -0
  2. package/dist/commands/scene-insights/actions.d.ts +63 -0
  3. package/dist/commands/scene-insights/actions.js +106 -0
  4. package/dist/commands/scene-insights/actions.js.map +1 -0
  5. package/dist/commands/scene-insights/client.d.ts +51 -0
  6. package/dist/commands/scene-insights/client.js +294 -0
  7. package/dist/commands/scene-insights/client.js.map +1 -0
  8. package/dist/commands/scene-insights/format.d.ts +23 -0
  9. package/dist/commands/scene-insights/format.js +143 -0
  10. package/dist/commands/scene-insights/format.js.map +1 -0
  11. package/dist/commands/scene-insights/index.d.ts +51 -0
  12. package/dist/commands/scene-insights/index.js +315 -0
  13. package/dist/commands/scene-insights/index.js.map +1 -0
  14. package/dist/commands/scene-insights/inputs.d.ts +49 -0
  15. package/dist/commands/scene-insights/inputs.js +166 -0
  16. package/dist/commands/scene-insights/inputs.js.map +1 -0
  17. package/dist/commands/scene-insights/session-store.d.ts +43 -0
  18. package/dist/commands/scene-insights/session-store.js +132 -0
  19. package/dist/commands/scene-insights/session-store.js.map +1 -0
  20. package/dist/commands/scene-insights/session.d.ts +46 -0
  21. package/dist/commands/scene-insights/session.js +92 -0
  22. package/dist/commands/scene-insights/session.js.map +1 -0
  23. package/dist/commands/scene-insights/sign-in.d.ts +48 -0
  24. package/dist/commands/scene-insights/sign-in.js +125 -0
  25. package/dist/commands/scene-insights/sign-in.js.map +1 -0
  26. package/dist/commands/scene-insights/signature-validation.d.ts +6 -0
  27. package/dist/commands/scene-insights/signature-validation.js +100 -0
  28. package/dist/commands/scene-insights/signature-validation.js.map +1 -0
  29. package/dist/commands/scene-insights/types.d.ts +61 -0
  30. package/dist/commands/scene-insights/types.js +4 -0
  31. package/dist/commands/scene-insights/types.js.map +1 -0
  32. package/dist/commands/sdk-server-logs/index.d.ts +24 -0
  33. package/dist/commands/sdk-server-logs/index.js +313 -0
  34. package/dist/commands/sdk-server-logs/index.js.map +1 -0
  35. package/dist/commands/start/dcl-env.d.ts +16 -0
  36. package/dist/commands/start/dcl-env.js +51 -0
  37. package/dist/commands/start/dcl-env.js.map +1 -0
  38. package/dist/commands/start/index.d.ts +1 -0
  39. package/dist/commands/start/index.js +24 -6
  40. package/dist/commands/start/index.js.map +1 -1
  41. package/dist/commands/start/multiplayer-server.d.ts +35 -0
  42. package/dist/commands/start/multiplayer-server.js +244 -0
  43. package/dist/commands/start/multiplayer-server.js.map +1 -0
  44. package/dist/commands/start/server/routes.d.ts +1 -1
  45. package/dist/commands/start/server/routes.js +6 -2
  46. package/dist/commands/start/server/routes.js.map +1 -1
  47. package/dist/commands/start/server/runtime-env.d.ts +84 -0
  48. package/dist/commands/start/server/runtime-env.js +415 -0
  49. package/dist/commands/start/server/runtime-env.js.map +1 -0
  50. package/dist/commands/start/server/storage-service.d.ts +8 -0
  51. package/dist/commands/start/server/storage-service.js +243 -0
  52. package/dist/commands/start/server/storage-service.js.map +1 -0
  53. package/dist/commands/start/utils.d.ts +32 -0
  54. package/dist/commands/start/utils.js +72 -0
  55. package/dist/commands/start/utils.js.map +1 -1
  56. package/dist/commands/storage/env.d.ts +5 -0
  57. package/dist/commands/storage/env.js +86 -0
  58. package/dist/commands/storage/env.js.map +1 -0
  59. package/dist/commands/storage/index.d.ts +26 -0
  60. package/dist/commands/storage/index.js +142 -0
  61. package/dist/commands/storage/index.js.map +1 -0
  62. package/dist/commands/storage/player.d.ts +5 -0
  63. package/dist/commands/storage/player.js +143 -0
  64. package/dist/commands/storage/player.js.map +1 -0
  65. package/dist/commands/storage/scene.d.ts +5 -0
  66. package/dist/commands/storage/scene.js +105 -0
  67. package/dist/commands/storage/scene.js.map +1 -0
  68. package/dist/commands/storage/shared.d.ts +62 -0
  69. package/dist/commands/storage/shared.js +260 -0
  70. package/dist/commands/storage/shared.js.map +1 -0
  71. package/dist/commands/storage/types.d.ts +56 -0
  72. package/dist/commands/storage/types.js +23 -0
  73. package/dist/commands/storage/types.js.map +1 -0
  74. package/dist/components/analytics.d.ts +75 -1
  75. package/dist/components/analytics.js +3 -2
  76. package/dist/components/analytics.js.map +1 -1
  77. package/dist/logic/auth-chain-headers.d.ts +11 -0
  78. package/dist/logic/auth-chain-headers.js +25 -0
  79. package/dist/logic/auth-chain-headers.js.map +1 -0
  80. package/dist/logic/bundle.js +31 -0
  81. package/dist/logic/bundle.js.map +1 -1
  82. package/dist/logic/config.d.ts +1 -0
  83. package/dist/logic/config.js +7 -0
  84. package/dist/logic/config.js.map +1 -1
  85. package/dist/logic/error.d.ts +1 -1
  86. package/dist/logic/error.js.map +1 -1
  87. package/dist/logic/exec.d.ts +1 -0
  88. package/dist/logic/exec.js +2 -2
  89. package/dist/logic/exec.js.map +1 -1
  90. package/dist/logic/lang.js +1 -1
  91. package/dist/logic/lsd-realm.d.ts +5 -0
  92. package/dist/logic/lsd-realm.js +28 -0
  93. package/dist/logic/lsd-realm.js.map +1 -0
  94. package/dist/logic/project-files.js +2 -0
  95. package/dist/logic/project-files.js.map +1 -1
  96. package/dist/logic/scene-validations.d.ts +8 -1
  97. package/dist/logic/scene-validations.js.map +1 -1
  98. package/dist/run-command.js +3 -2
  99. package/dist/run-command.js.map +1 -1
  100. package/package.json +6 -5
package/README.md CHANGED
@@ -105,3 +105,36 @@ 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 when the wallet signatures
117
+ verify on the selected network. The signed headers don't
118
+ name the host, so `--target` only accepts https hosts under `decentraland.org` or
119
+ `decentraland.zone` unless `--trust-target` is passed.
120
+
121
+ Previously saved full-login sessions require signing in again. A saved scoped
122
+ session expires no later than its parent delegation. Deploy the scoped-login
123
+ Insights server before using this command version.
124
+
125
+ Smart-contract wallets can sign through the browser linker. Contract signatures are
126
+ validated via Ethereum RPC during login and whenever a saved session is loaded.
127
+ The target selects Mainnet for `.org` and Sepolia for `.zone`; pass the same
128
+ `--target` to `login`, `session`, and read commands. For a custom target, set
129
+ `DCL_SCENE_INSIGHTS_RPC_URL` to its trusted Ethereum RPC endpoint. The endpoint is
130
+ local configuration, never taken from the wallet response, and is ignored for
131
+ `.org`/`.zone` targets so their network mapping stays fixed. Normal EOA sessions
132
+ remain offline during local validation.
133
+
134
+ Deploy the Insights server with `ETH_RPC_URL` before releasing this CLI version.
135
+ The server independently verifies every request against its configured network,
136
+ read-operation grants, and scene permissions. RPC outages return exit 6, including during browser login, without
137
+ removing the saved session or requesting another login. A new browser delegation is
138
+ validated once, then saved with its validated expiration. Invalid or revoked saved
139
+ sessions, including ones that exceed the RPC-call budget, require a new login. Validation is limited to
140
+ 10 chain links, 16 RPC calls and 15 seconds; each RPC request has a 5-second timeout.
@@ -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[];