@hydranium/protocol 1.0.0-next.10
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/LICENSE +21 -0
- package/README.md +81 -0
- package/lib/abstract-logger.d.ts +66 -0
- package/lib/abstract-logger.d.ts.map +1 -0
- package/lib/abstract-logger.js +110 -0
- package/lib/abstract-logger.js.map +1 -0
- package/lib/browser-runtime.d.ts +124 -0
- package/lib/browser-runtime.d.ts.map +1 -0
- package/lib/browser-runtime.js +11 -0
- package/lib/browser-runtime.js.map +1 -0
- package/lib/client/data-events.d.ts +49 -0
- package/lib/client/data-events.d.ts.map +1 -0
- package/lib/client/data-events.js +60 -0
- package/lib/client/data-events.js.map +1 -0
- package/lib/client/data-port.d.ts +95 -0
- package/lib/client/data-port.d.ts.map +1 -0
- package/lib/client/data-port.js +11 -0
- package/lib/client/data-port.js.map +1 -0
- package/lib/client/data-session.d.ts +129 -0
- package/lib/client/data-session.d.ts.map +1 -0
- package/lib/client/data-session.js +179 -0
- package/lib/client/data-session.js.map +1 -0
- package/lib/client/index.d.ts +39 -0
- package/lib/client/index.d.ts.map +1 -0
- package/lib/client/index.js +55 -0
- package/lib/client/index.js.map +1 -0
- package/lib/client/message-relay.d.ts +111 -0
- package/lib/client/message-relay.d.ts.map +1 -0
- package/lib/client/message-relay.js +139 -0
- package/lib/client/message-relay.js.map +1 -0
- package/lib/client/post-message-transport.d.ts +77 -0
- package/lib/client/post-message-transport.d.ts.map +1 -0
- package/lib/client/post-message-transport.js +95 -0
- package/lib/client/post-message-transport.js.map +1 -0
- package/lib/clock.d.ts +111 -0
- package/lib/clock.d.ts.map +1 -0
- package/lib/clock.js +74 -0
- package/lib/clock.js.map +1 -0
- package/lib/data/data-protocol-methods.d.ts +39 -0
- package/lib/data/data-protocol-methods.d.ts.map +1 -0
- package/lib/data/data-protocol-methods.js +61 -0
- package/lib/data/data-protocol-methods.js.map +1 -0
- package/lib/data/data-server-protocol.d.ts +264 -0
- package/lib/data/data-server-protocol.d.ts.map +1 -0
- package/lib/data/data-server-protocol.js +11 -0
- package/lib/data/data-server-protocol.js.map +1 -0
- package/lib/data/diagnostics.d.ts +97 -0
- package/lib/data/diagnostics.d.ts.map +1 -0
- package/lib/data/diagnostics.js +25 -0
- package/lib/data/diagnostics.js.map +1 -0
- package/lib/data/events.d.ts +107 -0
- package/lib/data/events.d.ts.map +1 -0
- package/lib/data/events.js +11 -0
- package/lib/data/events.js.map +1 -0
- package/lib/data/index.d.ts +15 -0
- package/lib/data/index.d.ts.map +1 -0
- package/lib/data/index.js +38 -0
- package/lib/data/index.js.map +1 -0
- package/lib/data/methods.d.ts +57 -0
- package/lib/data/methods.d.ts.map +1 -0
- package/lib/data/methods.js +60 -0
- package/lib/data/methods.js.map +1 -0
- package/lib/data/requests.d.ts +65 -0
- package/lib/data/requests.d.ts.map +1 -0
- package/lib/data/requests.js +11 -0
- package/lib/data/requests.js.map +1 -0
- package/lib/debouncer.d.ts +75 -0
- package/lib/debouncer.d.ts.map +1 -0
- package/lib/debouncer.js +91 -0
- package/lib/debouncer.js.map +1 -0
- package/lib/errors.d.ts +84 -0
- package/lib/errors.d.ts.map +1 -0
- package/lib/errors.js +113 -0
- package/lib/errors.js.map +1 -0
- package/lib/host-diagnostics.d.ts +58 -0
- package/lib/host-diagnostics.d.ts.map +1 -0
- package/lib/host-diagnostics.js +18 -0
- package/lib/host-diagnostics.js.map +1 -0
- package/lib/index.d.ts +34 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +56 -0
- package/lib/index.js.map +1 -0
- package/lib/latency-collector.d.ts +126 -0
- package/lib/latency-collector.d.ts.map +1 -0
- package/lib/latency-collector.js +137 -0
- package/lib/latency-collector.js.map +1 -0
- package/lib/logger.d.ts +119 -0
- package/lib/logger.d.ts.map +1 -0
- package/lib/logger.js +126 -0
- package/lib/logger.js.map +1 -0
- package/lib/model-server.d.ts +352 -0
- package/lib/model-server.d.ts.map +1 -0
- package/lib/model-server.js +160 -0
- package/lib/model-server.js.map +1 -0
- package/lib/model-service/args.d.ts +64 -0
- package/lib/model-service/args.d.ts.map +1 -0
- package/lib/model-service/args.js +11 -0
- package/lib/model-service/args.js.map +1 -0
- package/lib/model-service/index.d.ts +11 -0
- package/lib/model-service/index.d.ts.map +1 -0
- package/lib/model-service/index.js +31 -0
- package/lib/model-service/index.js.map +1 -0
- package/lib/model-service/reference-candidate.d.ts +56 -0
- package/lib/model-service/reference-candidate.d.ts.map +1 -0
- package/lib/model-service/reference-candidate.js +11 -0
- package/lib/model-service/reference-candidate.js.map +1 -0
- package/lib/noop-logger.d.ts +25 -0
- package/lib/noop-logger.d.ts.map +1 -0
- package/lib/noop-logger.js +36 -0
- package/lib/noop-logger.js.map +1 -0
- package/lib/observable-value.d.ts +72 -0
- package/lib/observable-value.d.ts.map +1 -0
- package/lib/observable-value.js +52 -0
- package/lib/observable-value.js.map +1 -0
- package/lib/patch-merge.d.ts +123 -0
- package/lib/patch-merge.d.ts.map +1 -0
- package/lib/patch-merge.js +104 -0
- package/lib/patch-merge.js.map +1 -0
- package/lib/profile-session.d.ts +87 -0
- package/lib/profile-session.d.ts.map +1 -0
- package/lib/profile-session.js +98 -0
- package/lib/profile-session.js.map +1 -0
- package/lib/profiling.d.ts +83 -0
- package/lib/profiling.d.ts.map +1 -0
- package/lib/profiling.js +20 -0
- package/lib/profiling.js.map +1 -0
- package/lib/project.d.ts +121 -0
- package/lib/project.d.ts.map +1 -0
- package/lib/project.js +34 -0
- package/lib/project.js.map +1 -0
- package/lib/rpc/bind-rpc-methods.d.ts +100 -0
- package/lib/rpc/bind-rpc-methods.d.ts.map +1 -0
- package/lib/rpc/bind-rpc-methods.js +110 -0
- package/lib/rpc/bind-rpc-methods.js.map +1 -0
- package/lib/rpc/create-rpc-proxy.d.ts +188 -0
- package/lib/rpc/create-rpc-proxy.d.ts.map +1 -0
- package/lib/rpc/create-rpc-proxy.js +158 -0
- package/lib/rpc/create-rpc-proxy.js.map +1 -0
- package/lib/rpc/index.d.ts +12 -0
- package/lib/rpc/index.d.ts.map +1 -0
- package/lib/rpc/index.js +31 -0
- package/lib/rpc/index.js.map +1 -0
- package/lib/rpc/wire-prefix.d.ts +37 -0
- package/lib/rpc/wire-prefix.d.ts.map +1 -0
- package/lib/rpc/wire-prefix.js +49 -0
- package/lib/rpc/wire-prefix.js.map +1 -0
- package/lib/testing/data-doubles.d.ts +121 -0
- package/lib/testing/data-doubles.d.ts.map +1 -0
- package/lib/testing/data-doubles.js +102 -0
- package/lib/testing/data-doubles.js.map +1 -0
- package/lib/testing/fake-clock.d.ts +35 -0
- package/lib/testing/fake-clock.d.ts.map +1 -0
- package/lib/testing/fake-clock.js +86 -0
- package/lib/testing/fake-clock.js.map +1 -0
- package/lib/testing/harness.d.ts +24 -0
- package/lib/testing/harness.d.ts.map +1 -0
- package/lib/testing/harness.js +11 -0
- package/lib/testing/harness.js.map +1 -0
- package/lib/testing/index.d.ts +13 -0
- package/lib/testing/index.d.ts.map +1 -0
- package/lib/testing/index.js +41 -0
- package/lib/testing/index.js.map +1 -0
- package/lib/testing/node/duplex-connection.d.ts +25 -0
- package/lib/testing/node/duplex-connection.d.ts.map +1 -0
- package/lib/testing/node/duplex-connection.js +34 -0
- package/lib/testing/node/duplex-connection.js.map +1 -0
- package/lib/testing/node/duplex-stream.d.ts +32 -0
- package/lib/testing/node/duplex-stream.d.ts.map +1 -0
- package/lib/testing/node/duplex-stream.js +35 -0
- package/lib/testing/node/duplex-stream.js.map +1 -0
- package/lib/testing/node/index.d.ts +11 -0
- package/lib/testing/node/index.d.ts.map +1 -0
- package/lib/testing/node/index.js +37 -0
- package/lib/testing/node/index.js.map +1 -0
- package/lib/testing/wait-for.d.ts +69 -0
- package/lib/testing/wait-for.d.ts.map +1 -0
- package/lib/testing/wait-for.js +67 -0
- package/lib/testing/wait-for.js.map +1 -0
- package/lib/tracer.d.ts +115 -0
- package/lib/tracer.d.ts.map +1 -0
- package/lib/tracer.js +205 -0
- package/lib/tracer.js.map +1 -0
- package/lib/transfer-diagnostic.d.ts +73 -0
- package/lib/transfer-diagnostic.d.ts.map +1 -0
- package/lib/transfer-diagnostic.js +45 -0
- package/lib/transfer-diagnostic.js.map +1 -0
- package/lib/transfer-document.d.ts +73 -0
- package/lib/transfer-document.d.ts.map +1 -0
- package/lib/transfer-document.js +46 -0
- package/lib/transfer-document.js.map +1 -0
- package/lib/transfer-element.d.ts +39 -0
- package/lib/transfer-element.d.ts.map +1 -0
- package/lib/transfer-element.js +11 -0
- package/lib/transfer-element.js.map +1 -0
- package/lib/uri.d.ts +62 -0
- package/lib/uri.d.ts.map +1 -0
- package/lib/uri.js +28 -0
- package/lib/uri.js.map +1 -0
- package/lib/util.d.ts +147 -0
- package/lib/util.d.ts.map +1 -0
- package/lib/util.js +211 -0
- package/lib/util.js.map +1 -0
- package/package.json +100 -0
- package/src/abstract-logger.ts +120 -0
- package/src/browser-runtime.ts +135 -0
- package/src/client/data-events.ts +71 -0
- package/src/client/data-port.ts +99 -0
- package/src/client/data-session.ts +209 -0
- package/src/client/index.ts +40 -0
- package/src/client/message-relay.ts +216 -0
- package/src/client/post-message-transport.ts +167 -0
- package/src/clock.ts +173 -0
- package/src/data/data-protocol-methods.ts +79 -0
- package/src/data/data-server-protocol.ts +296 -0
- package/src/data/diagnostics.ts +116 -0
- package/src/data/events.ts +127 -0
- package/src/data/index.ts +23 -0
- package/src/data/methods.ts +59 -0
- package/src/data/requests.ts +70 -0
- package/src/debouncer.ts +118 -0
- package/src/errors.ts +127 -0
- package/src/host-diagnostics.ts +63 -0
- package/src/index.ts +41 -0
- package/src/latency-collector.ts +231 -0
- package/src/logger.ts +172 -0
- package/src/model-server.ts +479 -0
- package/src/model-service/args.ts +67 -0
- package/src/model-service/index.ts +16 -0
- package/src/model-service/reference-candidate.ts +58 -0
- package/src/noop-logger.ts +36 -0
- package/src/observable-value.ts +92 -0
- package/src/patch-merge.ts +165 -0
- package/src/profile-session.ts +164 -0
- package/src/profiling.ts +113 -0
- package/src/project.ts +125 -0
- package/src/rpc/README.md +163 -0
- package/src/rpc/bind-rpc-methods.ts +180 -0
- package/src/rpc/create-rpc-proxy.ts +292 -0
- package/src/rpc/index.ts +16 -0
- package/src/rpc/wire-prefix.ts +48 -0
- package/src/testing/data-doubles.ts +178 -0
- package/src/testing/fake-clock.ts +106 -0
- package/src/testing/harness.ts +24 -0
- package/src/testing/index.ts +26 -0
- package/src/testing/node/duplex-connection.ts +50 -0
- package/src/testing/node/duplex-stream.ts +51 -0
- package/src/testing/node/index.ts +22 -0
- package/src/testing/wait-for.ts +94 -0
- package/src/tracer.ts +277 -0
- package/src/transfer-diagnostic.ts +92 -0
- package/src/transfer-document.ts +99 -0
- package/src/transfer-element.ts +43 -0
- package/src/uri.ts +61 -0
- package/src/util.ts +250 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/********************************************************************************
|
|
3
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
4
|
+
*
|
|
5
|
+
* This program and the accompanying materials are made available under the
|
|
6
|
+
* terms of the MIT License which is available in the project root.
|
|
7
|
+
*
|
|
8
|
+
* SPDX-License-Identifier: MIT
|
|
9
|
+
********************************************************************************/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.HOST_DIAGNOSTICS_PATH = void 0;
|
|
12
|
+
/**
|
|
13
|
+
* Theia service path the host-diagnostics RPC service is registered under. An
|
|
14
|
+
* ordinary in-process backend service (`RpcConnectionHandler`), unlike the
|
|
15
|
+
* socket-forwarded `DATA_SERVER_PATH`.
|
|
16
|
+
*/
|
|
17
|
+
exports.HOST_DIAGNOSTICS_PATH = '/hydranium/host-diagnostics';
|
|
18
|
+
//# sourceMappingURL=host-diagnostics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-diagnostics.js","sourceRoot":"","sources":["../src/host-diagnostics.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;AAkDlF;;;;GAIG;AACU,QAAA,qBAAqB,GAAG,6BAA6B,CAAC"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
export * from './abstract-logger';
|
|
10
|
+
export * from './client';
|
|
11
|
+
export * from './clock';
|
|
12
|
+
export * from './data';
|
|
13
|
+
export * from './browser-runtime';
|
|
14
|
+
export * from './debouncer';
|
|
15
|
+
export * from './errors';
|
|
16
|
+
export * from './host-diagnostics';
|
|
17
|
+
export * from './logger';
|
|
18
|
+
export * from './latency-collector';
|
|
19
|
+
export * from './patch-merge';
|
|
20
|
+
export * from './noop-logger';
|
|
21
|
+
export * from './observable-value';
|
|
22
|
+
export * from './profile-session';
|
|
23
|
+
export * from './profiling';
|
|
24
|
+
export * from './tracer';
|
|
25
|
+
export * from './transfer-diagnostic';
|
|
26
|
+
export * from './transfer-element';
|
|
27
|
+
export * from './model-service';
|
|
28
|
+
export * from './transfer-document';
|
|
29
|
+
export * from './model-server';
|
|
30
|
+
export * from './project';
|
|
31
|
+
export * from './rpc';
|
|
32
|
+
export * from './uri';
|
|
33
|
+
export * from './util';
|
|
34
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AASlF,cAAc,mBAAmB,CAAC;AAClC,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,oBAAoB,CAAC;AACnC,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC;AACpC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,OAAO,CAAC;AACtB,cAAc,OAAO,CAAC;AACtB,cAAc,QAAQ,CAAC"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/********************************************************************************
|
|
3
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
4
|
+
*
|
|
5
|
+
* This program and the accompanying materials are made available under the
|
|
6
|
+
* terms of the MIT License which is available in the project root.
|
|
7
|
+
*
|
|
8
|
+
* SPDX-License-Identifier: MIT
|
|
9
|
+
********************************************************************************/
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
22
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
23
|
+
};
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
// Public API barrel — re-exports every PRODUCTION entry of `@hydranium/protocol`.
|
|
26
|
+
// `./client` and `./data` are re-exported as well as declared standalone, so a
|
|
27
|
+
// consumer wanting the whole production surface needs one specifier while one
|
|
28
|
+
// wanting a narrower graph can still name the subpath. `./testing` is excluded
|
|
29
|
+
// on the opposite constraint: re-exporting it would put the test doubles in
|
|
30
|
+
// every production bundle that imports the root.
|
|
31
|
+
__exportStar(require("./abstract-logger"), exports);
|
|
32
|
+
__exportStar(require("./client"), exports);
|
|
33
|
+
__exportStar(require("./clock"), exports);
|
|
34
|
+
__exportStar(require("./data"), exports);
|
|
35
|
+
__exportStar(require("./browser-runtime"), exports);
|
|
36
|
+
__exportStar(require("./debouncer"), exports);
|
|
37
|
+
__exportStar(require("./errors"), exports);
|
|
38
|
+
__exportStar(require("./host-diagnostics"), exports);
|
|
39
|
+
__exportStar(require("./logger"), exports);
|
|
40
|
+
__exportStar(require("./latency-collector"), exports);
|
|
41
|
+
__exportStar(require("./patch-merge"), exports);
|
|
42
|
+
__exportStar(require("./noop-logger"), exports);
|
|
43
|
+
__exportStar(require("./observable-value"), exports);
|
|
44
|
+
__exportStar(require("./profile-session"), exports);
|
|
45
|
+
__exportStar(require("./profiling"), exports);
|
|
46
|
+
__exportStar(require("./tracer"), exports);
|
|
47
|
+
__exportStar(require("./transfer-diagnostic"), exports);
|
|
48
|
+
__exportStar(require("./transfer-element"), exports);
|
|
49
|
+
__exportStar(require("./model-service"), exports);
|
|
50
|
+
__exportStar(require("./transfer-document"), exports);
|
|
51
|
+
__exportStar(require("./model-server"), exports);
|
|
52
|
+
__exportStar(require("./project"), exports);
|
|
53
|
+
__exportStar(require("./rpc"), exports);
|
|
54
|
+
__exportStar(require("./uri"), exports);
|
|
55
|
+
__exportStar(require("./util"), exports);
|
|
56
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;;;;;;;;;;;;;;AAElF,kFAAkF;AAClF,+EAA+E;AAC/E,8EAA8E;AAC9E,+EAA+E;AAC/E,4EAA4E;AAC5E,iDAAiD;AAEjD,oDAAkC;AAClC,2CAAyB;AACzB,0CAAwB;AACxB,yCAAuB;AACvB,oDAAkC;AAClC,8CAA4B;AAC5B,2CAAyB;AACzB,qDAAmC;AACnC,2CAAyB;AACzB,sDAAoC;AACpC,gDAA8B;AAC9B,gDAA8B;AAC9B,qDAAmC;AACnC,oDAAkC;AAClC,8CAA4B;AAC5B,2CAAyB;AACzB,wDAAsC;AACtC,qDAAmC;AACnC,kDAAgC;AAChC,sDAAoC;AACpC,iDAA+B;AAC/B,4CAA0B;AAC1B,wCAAsB;AACtB,wCAAsB;AACtB,yCAAuB"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
import { type Clock, type Stopwatch } from './clock.js';
|
|
10
|
+
/** Latency/throughput for one method over the collection window. */
|
|
11
|
+
export interface MethodLatency {
|
|
12
|
+
/**
|
|
13
|
+
* Whatever key the caller passed to {@link LatencyCollector.record} or
|
|
14
|
+
* {@link LatencyCollector.time} — the framework feeds it RPC and LSP method
|
|
15
|
+
* names, but nothing enforces that, so two feeds using different spellings
|
|
16
|
+
* for one operation report as two methods.
|
|
17
|
+
*/
|
|
18
|
+
method: string;
|
|
19
|
+
/**
|
|
20
|
+
* Calls since construction or the last {@link LatencyCollector.reset}, which
|
|
21
|
+
* is the only thing that clears it. Unaffected by retention: a ring-buffer
|
|
22
|
+
* collector keeps counting long after it stops keeping samples. Failed calls
|
|
23
|
+
* are counted — a call that threw still consumed time.
|
|
24
|
+
*/
|
|
25
|
+
count: number;
|
|
26
|
+
/**
|
|
27
|
+
* Milliseconds, nearest-rank over the RETAINED samples rather than over
|
|
28
|
+
* {@link count} calls, so under `ring-buffer` retention it describes only the
|
|
29
|
+
* trailing window and can sit well below {@link maxMs}. `0` means no samples
|
|
30
|
+
* were retained, not that calls were instant.
|
|
31
|
+
*/
|
|
32
|
+
p50Ms: number;
|
|
33
|
+
/** Milliseconds, nearest-rank; same retention caveat as {@link p50Ms}. */
|
|
34
|
+
p99Ms: number;
|
|
35
|
+
/**
|
|
36
|
+
* Milliseconds, the slowest single call since the last reset. A lifetime
|
|
37
|
+
* figure, so a spike that has aged out of a ring buffer still shows here
|
|
38
|
+
* after the percentiles have forgotten it.
|
|
39
|
+
*/
|
|
40
|
+
maxMs: number;
|
|
41
|
+
/**
|
|
42
|
+
* Milliseconds summed across every call since the last reset, retention
|
|
43
|
+
* notwithstanding. This is what {@link LatencyCollector.report} ranks on, so
|
|
44
|
+
* it orders by total cost rather than by per-call slowness.
|
|
45
|
+
*/
|
|
46
|
+
totalMs: number;
|
|
47
|
+
}
|
|
48
|
+
/** A collector snapshot: the window length and the per-method latencies, hottest first. */
|
|
49
|
+
export interface LatencyReport {
|
|
50
|
+
/**
|
|
51
|
+
* Milliseconds elapsed since construction or the last
|
|
52
|
+
* {@link LatencyCollector.reset}, off the monotonic stopwatch. It bounds the
|
|
53
|
+
* throughput a caller can derive; it is not the sum of the method totals,
|
|
54
|
+
* which overlap and can exceed it under concurrency.
|
|
55
|
+
*/
|
|
56
|
+
windowMs: number;
|
|
57
|
+
/**
|
|
58
|
+
* Ordered by {@link MethodLatency.totalMs} descending. A method that was
|
|
59
|
+
* never called is absent rather than present with zeroes, so an empty array
|
|
60
|
+
* means nothing ran in the window.
|
|
61
|
+
*/
|
|
62
|
+
methods: MethodLatency[];
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* How many samples a collector retains for percentile estimation. `keep-all`
|
|
66
|
+
* (the default) stores every duration for exact nearest-rank percentiles — sized
|
|
67
|
+
* for a bounded diagnostics window that gets read then {@link LatencyCollector.reset}.
|
|
68
|
+
* `ring-buffer` caps retention at `maxSamplesPerMethod`, keeping only the most
|
|
69
|
+
* recent samples so a collector left running indefinitely cannot grow without
|
|
70
|
+
* bound; percentiles then cover that trailing window while `count`/`totalMs`/
|
|
71
|
+
* `maxMs` remain lifetime totals.
|
|
72
|
+
*/
|
|
73
|
+
export type LatencyRetention = {
|
|
74
|
+
readonly kind: 'keep-all';
|
|
75
|
+
} | {
|
|
76
|
+
readonly kind: 'ring-buffer';
|
|
77
|
+
readonly maxSamplesPerMethod: number;
|
|
78
|
+
};
|
|
79
|
+
/** Per-method state: retained samples (bounded in ring-buffer mode) plus lifetime totals. */
|
|
80
|
+
interface MethodAccumulator {
|
|
81
|
+
/** Retained durations for percentile estimation; capped in ring-buffer mode. Order is irrelevant (report sorts). */
|
|
82
|
+
readonly samples: number[];
|
|
83
|
+
/** Next slot to overwrite once the ring buffer is full (ring-buffer mode only). */
|
|
84
|
+
writeIndex: number;
|
|
85
|
+
/** Lifetime call count, unaffected by retention. */
|
|
86
|
+
count: number;
|
|
87
|
+
/** Lifetime total duration, unaffected by retention. */
|
|
88
|
+
totalMs: number;
|
|
89
|
+
/** Lifetime maximum duration, so a spike that ages out of the window still shows. */
|
|
90
|
+
maxMs: number;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Accumulates per-method call durations and reports count + latency percentiles.
|
|
94
|
+
* Exact (keeps every duration per method) — sized for a diagnostics window, not
|
|
95
|
+
* unbounded production telemetry; {@link reset} drops the samples and restarts
|
|
96
|
+
* the window. Feed it via {@link time} (wraps a call) or {@link record} (a
|
|
97
|
+
* pre-measured duration). Timing rides an injectable {@link Clock} so tests are
|
|
98
|
+
* deterministic on a fake clock.
|
|
99
|
+
*/
|
|
100
|
+
export declare class LatencyCollector {
|
|
101
|
+
protected readonly clock: Clock;
|
|
102
|
+
protected readonly retention: LatencyRetention;
|
|
103
|
+
protected readonly durations: Map<string, MethodAccumulator>;
|
|
104
|
+
protected window: Stopwatch;
|
|
105
|
+
constructor(clock?: Clock, retention?: LatencyRetention);
|
|
106
|
+
/** Record a pre-measured call duration (ms) for `method`. */
|
|
107
|
+
record(method: string, durationMs: number): void;
|
|
108
|
+
/**
|
|
109
|
+
* Run `call`, record how long it took under `method`, and return its result.
|
|
110
|
+
* The duration is recorded even when the call throws/rejects (a failed call
|
|
111
|
+
* still consumed time), then the error propagates.
|
|
112
|
+
*/
|
|
113
|
+
time<T>(method: string, call: () => Promise<T>): Promise<T>;
|
|
114
|
+
time<T>(method: string, call: () => T): T;
|
|
115
|
+
/** Non-destructive snapshot: per-method latencies ordered by total time descending (use {@link reset} to drain). */
|
|
116
|
+
report(): LatencyReport;
|
|
117
|
+
/** Drop all samples and restart the window. */
|
|
118
|
+
reset(): void;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Render a {@link LatencyReport} as a compact ranked table for a log line or a
|
|
122
|
+
* command channel — the latency counterpart to `formatProfileReport`.
|
|
123
|
+
*/
|
|
124
|
+
export declare function formatLatencyReport(report: LatencyReport, label?: string): string;
|
|
125
|
+
export {};
|
|
126
|
+
//# sourceMappingURL=latency-collector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"latency-collector.d.ts","sourceRoot":"","sources":["../src/latency-collector.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAalF,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,SAAS,EAAe,MAAM,YAAY,CAAC;AAErE,oEAAoE;AACpE,MAAM,WAAW,aAAa;IAC3B;;;;;OAKG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC;CAClB;AAED,2FAA2F;AAC3F,MAAM,WAAW,aAAa;IAC3B;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,OAAO,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtI,6FAA6F;AAC7F,UAAU,iBAAiB;IACxB,oHAAoH;IACpH,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAC3B,mFAAmF;IACnF,UAAU,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,qFAAqF;IACrF,KAAK,EAAE,MAAM,CAAC;CAChB;AAWD;;;;;;;GAOG;AACH,qBAAa,gBAAgB;IAKvB,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK;IAC/B,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,gBAAgB;IALjD,SAAS,CAAC,QAAQ,CAAC,SAAS,iCAAwC;IACpE,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC;gBAGN,KAAK,GAAE,KAAyB,EAChC,SAAS,GAAE,gBAAuC;IAQxE,6DAA6D;IAC7D,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAoBhD;;;;OAIG;IACH,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAC3D,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC;IA2BzC,oHAAoH;IACpH,MAAM,IAAI,aAAa;IAiBvB,+CAA+C;IAC/C,KAAK,IAAI,IAAI;CAIf;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,SAAoB,GAAG,MAAM,CAa5F"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/********************************************************************************
|
|
3
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
4
|
+
*
|
|
5
|
+
* This program and the accompanying materials are made available under the
|
|
6
|
+
* terms of the MIT License which is available in the project root.
|
|
7
|
+
*
|
|
8
|
+
* SPDX-License-Identifier: MIT
|
|
9
|
+
********************************************************************************/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.LatencyCollector = void 0;
|
|
12
|
+
exports.formatLatencyReport = formatLatencyReport;
|
|
13
|
+
/*
|
|
14
|
+
* Per-operation latency/throughput accumulator — the time/throughput axis of a
|
|
15
|
+
* profiling run (the CPU profile says "where time went in aggregate"; this says
|
|
16
|
+
* "method X ran N times at p99 Y ms"). It sits on the framework's timing
|
|
17
|
+
* primitives (`Clock`), not on a Node inspector session, so it is neutral and
|
|
18
|
+
* lives here in `protocol`: the RPC binder feeds it at one chokepoint and the
|
|
19
|
+
* LSP connection decorator feeds it at another, both cross-head. A running head
|
|
20
|
+
* holds one collector and reads `report()` out (e.g. over the diagnostics wire
|
|
21
|
+
* or into a bundle's `server-latency.json`).
|
|
22
|
+
*/
|
|
23
|
+
const clock_js_1 = require("./clock.js");
|
|
24
|
+
/** Nearest-rank percentile of an ascending-sorted array (empty → 0). */
|
|
25
|
+
function percentile(sortedAscending, percent) {
|
|
26
|
+
if (sortedAscending.length === 0) {
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
const rank = Math.ceil((percent / 100) * sortedAscending.length);
|
|
30
|
+
return sortedAscending[Math.min(sortedAscending.length - 1, Math.max(0, rank - 1))];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Accumulates per-method call durations and reports count + latency percentiles.
|
|
34
|
+
* Exact (keeps every duration per method) — sized for a diagnostics window, not
|
|
35
|
+
* unbounded production telemetry; {@link reset} drops the samples and restarts
|
|
36
|
+
* the window. Feed it via {@link time} (wraps a call) or {@link record} (a
|
|
37
|
+
* pre-measured duration). Timing rides an injectable {@link Clock} so tests are
|
|
38
|
+
* deterministic on a fake clock.
|
|
39
|
+
*/
|
|
40
|
+
class LatencyCollector {
|
|
41
|
+
clock;
|
|
42
|
+
retention;
|
|
43
|
+
durations = new Map();
|
|
44
|
+
window;
|
|
45
|
+
constructor(clock = new clock_js_1.SystemClock(), retention = { kind: 'keep-all' }) {
|
|
46
|
+
this.clock = clock;
|
|
47
|
+
this.retention = retention;
|
|
48
|
+
if (retention.kind === 'ring-buffer' && retention.maxSamplesPerMethod < 1) {
|
|
49
|
+
throw new RangeError(`ring-buffer maxSamplesPerMethod must be >= 1, got ${retention.maxSamplesPerMethod}`);
|
|
50
|
+
}
|
|
51
|
+
this.window = this.clock.stopwatch();
|
|
52
|
+
}
|
|
53
|
+
/** Record a pre-measured call duration (ms) for `method`. */
|
|
54
|
+
record(method, durationMs) {
|
|
55
|
+
let accumulator = this.durations.get(method);
|
|
56
|
+
if (!accumulator) {
|
|
57
|
+
accumulator = { samples: [], writeIndex: 0, count: 0, totalMs: 0, maxMs: 0 };
|
|
58
|
+
this.durations.set(method, accumulator);
|
|
59
|
+
}
|
|
60
|
+
accumulator.count++;
|
|
61
|
+
accumulator.totalMs += durationMs;
|
|
62
|
+
if (durationMs > accumulator.maxMs) {
|
|
63
|
+
accumulator.maxMs = durationMs;
|
|
64
|
+
}
|
|
65
|
+
if (this.retention.kind === 'ring-buffer' && accumulator.samples.length >= this.retention.maxSamplesPerMethod) {
|
|
66
|
+
// Buffer full: overwrite the oldest slot in O(1) (percentiles sort, so order does not matter).
|
|
67
|
+
accumulator.samples[accumulator.writeIndex] = durationMs;
|
|
68
|
+
accumulator.writeIndex = (accumulator.writeIndex + 1) % this.retention.maxSamplesPerMethod;
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
accumulator.samples.push(durationMs);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
time(method, call) {
|
|
75
|
+
const stopwatch = this.clock.stopwatch();
|
|
76
|
+
const finish = () => this.record(method, stopwatch.elapsedMs);
|
|
77
|
+
let result;
|
|
78
|
+
try {
|
|
79
|
+
result = call();
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
finish();
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
if (result instanceof Promise) {
|
|
86
|
+
return result.then(value => {
|
|
87
|
+
finish();
|
|
88
|
+
return value;
|
|
89
|
+
}, error => {
|
|
90
|
+
finish();
|
|
91
|
+
throw error;
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
finish();
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
/** Non-destructive snapshot: per-method latencies ordered by total time descending (use {@link reset} to drain). */
|
|
98
|
+
report() {
|
|
99
|
+
const methods = [];
|
|
100
|
+
for (const [method, accumulator] of this.durations) {
|
|
101
|
+
const sorted = [...accumulator.samples].sort((left, right) => left - right);
|
|
102
|
+
methods.push({
|
|
103
|
+
method,
|
|
104
|
+
count: accumulator.count,
|
|
105
|
+
totalMs: accumulator.totalMs,
|
|
106
|
+
maxMs: accumulator.maxMs,
|
|
107
|
+
p50Ms: percentile(sorted, 50),
|
|
108
|
+
p99Ms: percentile(sorted, 99)
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
methods.sort((left, right) => right.totalMs - left.totalMs);
|
|
112
|
+
return { windowMs: this.window.elapsedMs, methods };
|
|
113
|
+
}
|
|
114
|
+
/** Drop all samples and restart the window. */
|
|
115
|
+
reset() {
|
|
116
|
+
this.durations.clear();
|
|
117
|
+
this.window = this.clock.stopwatch();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
exports.LatencyCollector = LatencyCollector;
|
|
121
|
+
/**
|
|
122
|
+
* Render a {@link LatencyReport} as a compact ranked table for a log line or a
|
|
123
|
+
* command channel — the latency counterpart to `formatProfileReport`.
|
|
124
|
+
*/
|
|
125
|
+
function formatLatencyReport(report, label = 'RPC/LSP latency') {
|
|
126
|
+
const lines = [`${label} (window ${Math.round(report.windowMs)}ms):`];
|
|
127
|
+
if (report.methods.length === 0) {
|
|
128
|
+
lines.push(' (no calls recorded)');
|
|
129
|
+
return lines.join('\n');
|
|
130
|
+
}
|
|
131
|
+
for (const methodLatency of report.methods) {
|
|
132
|
+
lines.push(` ${methodLatency.method} n=${methodLatency.count} total ${Math.round(methodLatency.totalMs)}ms ` +
|
|
133
|
+
`p50 ${Math.round(methodLatency.p50Ms)}ms p99 ${Math.round(methodLatency.p99Ms)}ms max ${Math.round(methodLatency.maxMs)}ms`);
|
|
134
|
+
}
|
|
135
|
+
return lines.join('\n');
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=latency-collector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"latency-collector.js","sourceRoot":"","sources":["../src/latency-collector.ts"],"names":[],"mappings":"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"}
|
package/lib/logger.d.ts
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
export type LogLevel = 'error' | 'warn' | 'info' | 'debug' | 'trace';
|
|
10
|
+
export type LogThreshold = 'off' | LogLevel;
|
|
11
|
+
export declare const LEVEL_ORDER: Record<LogThreshold, number>;
|
|
12
|
+
/** Default labels rendered in the log line, padded to 5 chars so timestamps line up across sources. */
|
|
13
|
+
export declare const LEVEL_LABELS: Record<LogLevel, string>;
|
|
14
|
+
/**
|
|
15
|
+
* Cross-side public logger contract. Every consumer of the framework — browser
|
|
16
|
+
* client extensions, LSP servers, headless CLIs, tests — programs against this
|
|
17
|
+
* interface; concrete implementations supply platform-specific delivery
|
|
18
|
+
* (`AbstractLogger` is the abstract base class that satisfies this contract).
|
|
19
|
+
*
|
|
20
|
+
* Global threshold configuration lives on the {@link Logger} namespace
|
|
21
|
+
* (`Logger.setLevel(...)`, `Logger.getLevel()`, `Logger.isLevelEnabled(...)`).
|
|
22
|
+
*
|
|
23
|
+
* Every emit returns this logger so calls can chain (`logger.error(a).debug(b)`),
|
|
24
|
+
* and every `for` / `sub` / `with` derivation preserves the implementation type.
|
|
25
|
+
*/
|
|
26
|
+
export interface Logger {
|
|
27
|
+
/** Log a message at error level. */
|
|
28
|
+
error(message?: string, ...args: unknown[]): this;
|
|
29
|
+
/** Log a message at warn level. */
|
|
30
|
+
warn(message?: string, ...args: unknown[]): this;
|
|
31
|
+
/** Log a message at info level. */
|
|
32
|
+
info(message?: string, ...args: unknown[]): this;
|
|
33
|
+
/** Log a message at debug level. */
|
|
34
|
+
debug(message?: string, ...args: unknown[]): this;
|
|
35
|
+
/** High-volume diagnostic lines, only emitted at the `'trace'` threshold. */
|
|
36
|
+
trace(message?: string, ...args: unknown[]): this;
|
|
37
|
+
/** Log a message at info-level threshold with a `Log` label (rather than `Info`). */
|
|
38
|
+
log(message?: string, ...args: unknown[]): this;
|
|
39
|
+
/** Derive a child logger with `component` as a `Foo :: bar`-style suffix. */
|
|
40
|
+
for(component: string): this;
|
|
41
|
+
/** Derive a child logger by deepening the existing `Foo :: bar :: baz` chain. */
|
|
42
|
+
sub(component: string): this;
|
|
43
|
+
/** Derive a child logger appending `component` as a separate bracket: `[a] [b]`. */
|
|
44
|
+
with(component: string): this;
|
|
45
|
+
/**
|
|
46
|
+
* Derive a child logger labelled with the given URI string. Default behaviour
|
|
47
|
+
* appends the URI as a bracket via {@link with}; subclasses with workspace
|
|
48
|
+
* awareness override to display workspace-relative paths. Subclasses MAY
|
|
49
|
+
* widen the parameter type to accept URI objects directly (TypeScript method
|
|
50
|
+
* parameter bivariance permits this) — callers typed against the {@link Logger}
|
|
51
|
+
* interface stringify their URI at the call site.
|
|
52
|
+
*/
|
|
53
|
+
withUri(uri: string): this;
|
|
54
|
+
/**
|
|
55
|
+
* Emit `message` at `threshold`, or do nothing when `threshold === 'off'`.
|
|
56
|
+
* Lets a caller holding a {@link LogThreshold} emit without a hand-written
|
|
57
|
+
* `if (level === 'off') return` guard.
|
|
58
|
+
*/
|
|
59
|
+
logAt(threshold: LogThreshold, message: string): this;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Companion namespace for the {@link Logger} interface holding global
|
|
63
|
+
* threshold configuration.
|
|
64
|
+
*
|
|
65
|
+
* The threshold is process-wide: every {@link Logger} instance shares one
|
|
66
|
+
* value, so adopters don't have to wire it through each logger they
|
|
67
|
+
* construct. The timing facilities that build on a logger — `Tracer.time` /
|
|
68
|
+
* `Tracer.startTimer` — consult {@link Logger.isLevelEnabled} internally to
|
|
69
|
+
* short-circuit when the configured level suppresses output.
|
|
70
|
+
*/
|
|
71
|
+
export declare namespace Logger {
|
|
72
|
+
/** Set the process-wide log threshold. Every {@link Logger} instance picks up the new value live. */
|
|
73
|
+
function setLevel(level: LogThreshold): void;
|
|
74
|
+
/** Read the current process-wide log threshold. */
|
|
75
|
+
function getLevel(): LogThreshold;
|
|
76
|
+
/**
|
|
77
|
+
* Whether a message at `level` would be emitted at the current threshold.
|
|
78
|
+
* Use to guard expensive log-line construction:
|
|
79
|
+
* `if (Logger.isLevelEnabled('trace')) logger.trace(buildPayload())`.
|
|
80
|
+
*/
|
|
81
|
+
function isLevelEnabled(level: LogLevel): boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Whether a message at `threshold` would be emitted: `false` for `'off'`,
|
|
84
|
+
* otherwise tracks {@link isLevelEnabled}. Use to gate work behind a
|
|
85
|
+
* {@link LogThreshold} (which {@link isLevelEnabled} cannot accept).
|
|
86
|
+
*/
|
|
87
|
+
function isThresholdEnabled(threshold: LogThreshold): boolean;
|
|
88
|
+
}
|
|
89
|
+
/** True when `value` is one of `'off' | 'error' | 'warn' | 'info' | 'debug' | 'trace'`. */
|
|
90
|
+
export declare function isLogThreshold(value: unknown): value is LogThreshold;
|
|
91
|
+
/**
|
|
92
|
+
* Parse a string-typed configuration value into a {@link LogThreshold}, returning
|
|
93
|
+
* `undefined` for unset or invalid inputs. Case-insensitive — `'WARN'` / `'warn'`
|
|
94
|
+
* / `'Warn'` all normalise to `'warn'`. Use to consume LSP / env-var / CLI inputs
|
|
95
|
+
* without exposing callers to the case-fold detail.
|
|
96
|
+
*/
|
|
97
|
+
export declare function parseLogLevel(value: unknown): LogThreshold | undefined;
|
|
98
|
+
/**
|
|
99
|
+
* Names of the environment variables the server consults for its launch-time
|
|
100
|
+
* log configuration. They live in the shared protocol layer because they are
|
|
101
|
+
* the *contract* between whoever launches a server (the CLI, a test harness, a
|
|
102
|
+
* container) and the server that reads them — both sides reference one constant
|
|
103
|
+
* instead of duplicating the literal string.
|
|
104
|
+
*/
|
|
105
|
+
export declare const DEFAULT_LOG_LEVEL_ENV = "HYDRANIUM_LOG_LEVEL";
|
|
106
|
+
/** Env var the server reads its log file-tee target from. See {@link DEFAULT_LOG_LEVEL_ENV}. */
|
|
107
|
+
export declare const DEFAULT_LOG_FILE_ENV = "HYDRANIUM_LOG_FILE";
|
|
108
|
+
/**
|
|
109
|
+
* Human-readable formatting helpers used in log lines and diagnostic output.
|
|
110
|
+
*/
|
|
111
|
+
export declare namespace Format {
|
|
112
|
+
/** Format a date as `HH:MM:SS.mmm`. Defaults to `now`. */
|
|
113
|
+
function timestamp(d?: Date): string;
|
|
114
|
+
/** Format a millisecond duration: `<1s` as `Nms`, `>=1s` as `N.NNs`. */
|
|
115
|
+
function elapsed(ms: number): string;
|
|
116
|
+
/** Format a byte count with a human-readable unit suffix (B/KB/MB/GB/TB). */
|
|
117
|
+
function bytes(count: number): string;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AACrE,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,QAAQ,CAAC;AAE5C,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAA8D,CAAC;AAEpH,uGAAuG;AACvG,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAMjD,CAAC;AAMF;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,MAAM;IACpB,oCAAoC;IACpC,KAAK,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAClD,mCAAmC;IACnC,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IACjD,mCAAmC;IACnC,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IACjD,oCAAoC;IACpC,KAAK,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAClD,6EAA6E;IAC7E,KAAK,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAClD,qFAAqF;IACrF,GAAG,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChD,6EAA6E;IAC7E,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,iFAAiF;IACjF,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,oFAAoF;IACpF,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B;;;;;;;OAOG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B;;;;OAIG;IACH,KAAK,CAAC,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxD;AAED;;;;;;;;;GASG;AACH,yBAAiB,MAAM,CAAC;IACrB,qGAAqG;IACrG,SAAgB,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAElD;IACD,mDAAmD;IACnD,SAAgB,QAAQ,IAAI,YAAY,CAEvC;IACD;;;;OAIG;IACH,SAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAEvD;IACD;;;;OAIG;IACH,SAAgB,kBAAkB,CAAC,SAAS,EAAE,YAAY,GAAG,OAAO,CAEnE;CACH;AAED,2FAA2F;AAC3F,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,YAAY,CAEpE;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,GAAG,SAAS,CAGtE;AAED;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,wBAAwB,CAAC;AAC3D,gGAAgG;AAChG,eAAO,MAAM,oBAAoB,uBAAuB,CAAC;AAEzD;;GAEG;AACH,yBAAiB,MAAM,CAAC;IACrB,0DAA0D;IAC1D,SAAgB,SAAS,CAAC,CAAC,GAAE,IAAiB,GAAG,MAAM,CAMtD;IAED,wEAAwE;IACxE,SAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE1C;IAED,6EAA6E;IAC7E,SAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAY3C;CACH"}
|
package/lib/logger.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/********************************************************************************
|
|
3
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
4
|
+
*
|
|
5
|
+
* This program and the accompanying materials are made available under the
|
|
6
|
+
* terms of the MIT License which is available in the project root.
|
|
7
|
+
*
|
|
8
|
+
* SPDX-License-Identifier: MIT
|
|
9
|
+
********************************************************************************/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.Format = exports.DEFAULT_LOG_FILE_ENV = exports.DEFAULT_LOG_LEVEL_ENV = exports.Logger = exports.LEVEL_LABELS = exports.LEVEL_ORDER = void 0;
|
|
12
|
+
exports.isLogThreshold = isLogThreshold;
|
|
13
|
+
exports.parseLogLevel = parseLogLevel;
|
|
14
|
+
exports.LEVEL_ORDER = { off: 0, error: 1, warn: 2, info: 3, debug: 4, trace: 5 };
|
|
15
|
+
/** Default labels rendered in the log line, padded to 5 chars so timestamps line up across sources. */
|
|
16
|
+
exports.LEVEL_LABELS = {
|
|
17
|
+
error: 'Error',
|
|
18
|
+
warn: 'Warn',
|
|
19
|
+
info: 'Info',
|
|
20
|
+
debug: 'Debug',
|
|
21
|
+
trace: 'Trace'
|
|
22
|
+
};
|
|
23
|
+
/** Module-global threshold; shared by every `AbstractLogger` instance so derived child
|
|
24
|
+
* loggers pick up live updates without each having to subscribe to a configuration source. */
|
|
25
|
+
let currentLevel = 'info';
|
|
26
|
+
/**
|
|
27
|
+
* Companion namespace for the {@link Logger} interface holding global
|
|
28
|
+
* threshold configuration.
|
|
29
|
+
*
|
|
30
|
+
* The threshold is process-wide: every {@link Logger} instance shares one
|
|
31
|
+
* value, so adopters don't have to wire it through each logger they
|
|
32
|
+
* construct. The timing facilities that build on a logger — `Tracer.time` /
|
|
33
|
+
* `Tracer.startTimer` — consult {@link Logger.isLevelEnabled} internally to
|
|
34
|
+
* short-circuit when the configured level suppresses output.
|
|
35
|
+
*/
|
|
36
|
+
var Logger;
|
|
37
|
+
(function (Logger) {
|
|
38
|
+
/** Set the process-wide log threshold. Every {@link Logger} instance picks up the new value live. */
|
|
39
|
+
function setLevel(level) {
|
|
40
|
+
currentLevel = level;
|
|
41
|
+
}
|
|
42
|
+
Logger.setLevel = setLevel;
|
|
43
|
+
/** Read the current process-wide log threshold. */
|
|
44
|
+
function getLevel() {
|
|
45
|
+
return currentLevel;
|
|
46
|
+
}
|
|
47
|
+
Logger.getLevel = getLevel;
|
|
48
|
+
/**
|
|
49
|
+
* Whether a message at `level` would be emitted at the current threshold.
|
|
50
|
+
* Use to guard expensive log-line construction:
|
|
51
|
+
* `if (Logger.isLevelEnabled('trace')) logger.trace(buildPayload())`.
|
|
52
|
+
*/
|
|
53
|
+
function isLevelEnabled(level) {
|
|
54
|
+
return exports.LEVEL_ORDER[level] <= exports.LEVEL_ORDER[currentLevel];
|
|
55
|
+
}
|
|
56
|
+
Logger.isLevelEnabled = isLevelEnabled;
|
|
57
|
+
/**
|
|
58
|
+
* Whether a message at `threshold` would be emitted: `false` for `'off'`,
|
|
59
|
+
* otherwise tracks {@link isLevelEnabled}. Use to gate work behind a
|
|
60
|
+
* {@link LogThreshold} (which {@link isLevelEnabled} cannot accept).
|
|
61
|
+
*/
|
|
62
|
+
function isThresholdEnabled(threshold) {
|
|
63
|
+
return threshold !== 'off' && isLevelEnabled(threshold);
|
|
64
|
+
}
|
|
65
|
+
Logger.isThresholdEnabled = isThresholdEnabled;
|
|
66
|
+
})(Logger || (exports.Logger = Logger = {}));
|
|
67
|
+
/** True when `value` is one of `'off' | 'error' | 'warn' | 'info' | 'debug' | 'trace'`. */
|
|
68
|
+
function isLogThreshold(value) {
|
|
69
|
+
return typeof value === 'string' && value in exports.LEVEL_ORDER;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Parse a string-typed configuration value into a {@link LogThreshold}, returning
|
|
73
|
+
* `undefined` for unset or invalid inputs. Case-insensitive — `'WARN'` / `'warn'`
|
|
74
|
+
* / `'Warn'` all normalise to `'warn'`. Use to consume LSP / env-var / CLI inputs
|
|
75
|
+
* without exposing callers to the case-fold detail.
|
|
76
|
+
*/
|
|
77
|
+
function parseLogLevel(value) {
|
|
78
|
+
const normalised = typeof value === 'string' ? value.toLowerCase() : undefined;
|
|
79
|
+
return normalised && isLogThreshold(normalised) ? normalised : undefined;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Names of the environment variables the server consults for its launch-time
|
|
83
|
+
* log configuration. They live in the shared protocol layer because they are
|
|
84
|
+
* the *contract* between whoever launches a server (the CLI, a test harness, a
|
|
85
|
+
* container) and the server that reads them — both sides reference one constant
|
|
86
|
+
* instead of duplicating the literal string.
|
|
87
|
+
*/
|
|
88
|
+
exports.DEFAULT_LOG_LEVEL_ENV = 'HYDRANIUM_LOG_LEVEL';
|
|
89
|
+
/** Env var the server reads its log file-tee target from. See {@link DEFAULT_LOG_LEVEL_ENV}. */
|
|
90
|
+
exports.DEFAULT_LOG_FILE_ENV = 'HYDRANIUM_LOG_FILE';
|
|
91
|
+
/**
|
|
92
|
+
* Human-readable formatting helpers used in log lines and diagnostic output.
|
|
93
|
+
*/
|
|
94
|
+
var Format;
|
|
95
|
+
(function (Format) {
|
|
96
|
+
/** Format a date as `HH:MM:SS.mmm`. Defaults to `now`. */
|
|
97
|
+
function timestamp(d = new Date()) {
|
|
98
|
+
const hh = String(d.getHours()).padStart(2, '0');
|
|
99
|
+
const mm = String(d.getMinutes()).padStart(2, '0');
|
|
100
|
+
const ss = String(d.getSeconds()).padStart(2, '0');
|
|
101
|
+
const ms = String(d.getMilliseconds()).padStart(3, '0');
|
|
102
|
+
return `${hh}:${mm}:${ss}.${ms}`;
|
|
103
|
+
}
|
|
104
|
+
Format.timestamp = timestamp;
|
|
105
|
+
/** Format a millisecond duration: `<1s` as `Nms`, `>=1s` as `N.NNs`. */
|
|
106
|
+
function elapsed(ms) {
|
|
107
|
+
return ms < 1000 ? `${Math.round(ms)}ms` : `${(ms / 1000).toFixed(2)}s`;
|
|
108
|
+
}
|
|
109
|
+
Format.elapsed = elapsed;
|
|
110
|
+
/** Format a byte count with a human-readable unit suffix (B/KB/MB/GB/TB). */
|
|
111
|
+
function bytes(count) {
|
|
112
|
+
if (count < 1024) {
|
|
113
|
+
return `${count}B`;
|
|
114
|
+
}
|
|
115
|
+
const units = ['KB', 'MB', 'GB', 'TB'];
|
|
116
|
+
let value = count / 1024;
|
|
117
|
+
let unit = 0;
|
|
118
|
+
while (value >= 1024 && unit < units.length - 1) {
|
|
119
|
+
value /= 1024;
|
|
120
|
+
unit++;
|
|
121
|
+
}
|
|
122
|
+
return `${value.toFixed(value >= 100 ? 0 : value >= 10 ? 1 : 2)}${units[unit]}`;
|
|
123
|
+
}
|
|
124
|
+
Format.bytes = bytes;
|
|
125
|
+
})(Format || (exports.Format = Format = {}));
|
|
126
|
+
//# sourceMappingURL=logger.js.map
|