@senpi/runtime 1.1.0-dev.runtime-phase-2.20260610125851 → 1.1.0-dev.runtime-phase-2.20260610130051
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/dist/dsl/events/handlers.d.ts.map +1 -1
- package/dist/dsl/events/handlers.js +4 -0
- package/dist/dsl/events/handlers.js.map +1 -1
- package/dist/recording/emitter.d.ts +21 -0
- package/dist/recording/emitter.d.ts.map +1 -0
- package/dist/recording/emitter.js +2 -0
- package/dist/recording/emitter.js.map +1 -0
- package/dist/recording/identity.d.ts +34 -0
- package/dist/recording/identity.d.ts.map +1 -0
- package/dist/recording/identity.js +2 -0
- package/dist/recording/identity.js.map +1 -0
- package/dist/recording/index.d.ts +11 -0
- package/dist/recording/index.d.ts.map +1 -0
- package/dist/recording/index.js +2 -0
- package/dist/recording/index.js.map +1 -0
- package/dist/recording/noop-emitter.d.ts +17 -0
- package/dist/recording/noop-emitter.d.ts.map +1 -0
- package/dist/recording/noop-emitter.js +16 -0
- package/dist/recording/noop-emitter.js.map +1 -0
- package/dist/recording/otel/attributes.d.ts +35 -0
- package/dist/recording/otel/attributes.d.ts.map +1 -0
- package/dist/recording/otel/attributes.js +131 -0
- package/dist/recording/otel/attributes.js.map +1 -0
- package/dist/recording/otel/constants.d.ts +81 -0
- package/dist/recording/otel/constants.d.ts.map +1 -0
- package/dist/recording/otel/constants.js +96 -0
- package/dist/recording/otel/constants.js.map +1 -0
- package/dist/recording/otel/ids.d.ts +14 -0
- package/dist/recording/otel/ids.d.ts.map +1 -0
- package/dist/recording/otel/ids.js +12 -0
- package/dist/recording/otel/ids.js.map +1 -0
- package/dist/recording/otel/index.d.ts +13 -0
- package/dist/recording/otel/index.d.ts.map +1 -0
- package/dist/recording/otel/index.js +9 -0
- package/dist/recording/otel/index.js.map +1 -0
- package/dist/recording/otel/mappers.d.ts +42 -0
- package/dist/recording/otel/mappers.d.ts.map +1 -0
- package/dist/recording/otel/mappers.js +337 -0
- package/dist/recording/otel/mappers.js.map +1 -0
- package/dist/recording/otel/otel-emitter.d.ts +37 -0
- package/dist/recording/otel/otel-emitter.d.ts.map +1 -0
- package/dist/recording/otel/otel-emitter.js +75 -0
- package/dist/recording/otel/otel-emitter.js.map +1 -0
- package/dist/recording/otel/redaction.d.ts +31 -0
- package/dist/recording/otel/redaction.d.ts.map +1 -0
- package/dist/recording/otel/redaction.js +40 -0
- package/dist/recording/otel/redaction.js.map +1 -0
- package/dist/recording/records.d.ts +327 -0
- package/dist/recording/records.d.ts.map +1 -0
- package/dist/recording/records.js +14 -0
- package/dist/recording/records.js.map +1 -0
- package/dist/recording/transport/batcher.d.ts +59 -0
- package/dist/recording/transport/batcher.d.ts.map +1 -0
- package/dist/recording/transport/batcher.js +234 -0
- package/dist/recording/transport/batcher.js.map +1 -0
- package/dist/recording/transport/client.d.ts +41 -0
- package/dist/recording/transport/client.d.ts.map +1 -0
- package/dist/recording/transport/client.js +69 -0
- package/dist/recording/transport/client.js.map +1 -0
- package/dist/recording/transport/config.d.ts +53 -0
- package/dist/recording/transport/config.d.ts.map +1 -0
- package/dist/recording/transport/config.js +41 -0
- package/dist/recording/transport/config.js.map +1 -0
- package/dist/recording/transport/index.d.ts +16 -0
- package/dist/recording/transport/index.d.ts.map +1 -0
- package/dist/recording/transport/index.js +12 -0
- package/dist/recording/transport/index.js.map +1 -0
- package/dist/recording/transport/rows.d.ts +88 -0
- package/dist/recording/transport/rows.d.ts.map +1 -0
- package/dist/recording/transport/rows.js +15 -0
- package/dist/recording/transport/rows.js.map +1 -0
- package/dist/recording/wiring/emitter-factory.d.ts +39 -0
- package/dist/recording/wiring/emitter-factory.d.ts.map +1 -0
- package/dist/recording/wiring/emitter-factory.js +62 -0
- package/dist/recording/wiring/emitter-factory.js.map +1 -0
- package/dist/recording/wiring/identity.d.ts +27 -0
- package/dist/recording/wiring/identity.d.ts.map +1 -0
- package/dist/recording/wiring/identity.js +51 -0
- package/dist/recording/wiring/identity.js.map +1 -0
- package/dist/recording/wiring/index.d.ts +12 -0
- package/dist/recording/wiring/index.d.ts.map +1 -0
- package/dist/recording/wiring/index.js +9 -0
- package/dist/recording/wiring/index.js.map +1 -0
- package/dist/recording/wiring/record-builders.d.ts +68 -0
- package/dist/recording/wiring/record-builders.d.ts.map +1 -0
- package/dist/recording/wiring/record-builders.js +441 -0
- package/dist/recording/wiring/record-builders.js.map +1 -0
- package/dist/recording/wiring/subscriber.d.ts +21 -0
- package/dist/recording/wiring/subscriber.d.ts.map +1 -0
- package/dist/recording/wiring/subscriber.js +171 -0
- package/dist/recording/wiring/subscriber.js.map +1 -0
- package/dist/recording/wiring/values.d.ts +19 -0
- package/dist/recording/wiring/values.d.ts.map +1 -0
- package/dist/recording/wiring/values.js +49 -0
- package/dist/recording/wiring/values.js.map +1 -0
- package/dist/runtime/load-runtime-config.d.ts +9 -0
- package/dist/runtime/load-runtime-config.d.ts.map +1 -1
- package/dist/runtime/load-runtime-config.js +41 -1
- package/dist/runtime/load-runtime-config.js.map +1 -1
- package/dist/runtime/run.d.ts.map +1 -1
- package/dist/runtime/run.js +3 -2
- package/dist/runtime/run.js.map +1 -1
- package/dist/runtime/runtime-schema.d.ts +182 -0
- package/dist/runtime/runtime-schema.d.ts.map +1 -1
- package/dist/runtime/runtime-schema.js +17 -0
- package/dist/runtime/runtime-schema.js.map +1 -1
- package/dist/runtime/runtime.d.ts +15 -0
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +246 -148
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/scanners/events.d.ts +6 -0
- package/dist/scanners/events.d.ts.map +1 -1
- package/dist/scanners/events.js.map +1 -1
- package/dist/scanners/runtime-module.d.ts.map +1 -1
- package/dist/scanners/runtime-module.js +9 -1
- package/dist/scanners/runtime-module.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Construct the recording emitter at boot. Telemetry is ON by default; it degrades to the inert
|
|
3
|
+
* {@link NoopEmitter} when explicitly disabled or when no API token is available — a missing token
|
|
4
|
+
* is never a boot failure. When live, an {@link OtelEmitter} feeds a {@link TelemetryBatcher} that
|
|
5
|
+
* must be shut down on stop.
|
|
6
|
+
*/
|
|
7
|
+
import type { IdentityEnvelope } from "../identity.js";
|
|
8
|
+
import type { RecordingEmitter } from "../emitter.js";
|
|
9
|
+
import { type TelemetryBatcher } from "../transport/index.js";
|
|
10
|
+
export interface RecordingEmitterOptions {
|
|
11
|
+
/** Resolved enable flag (config + env already applied by the caller). */
|
|
12
|
+
readonly enabled: boolean;
|
|
13
|
+
/** Bearer token (the `SENPI_API_KEY` JWT); absent → degrade to Noop. */
|
|
14
|
+
readonly token?: string;
|
|
15
|
+
/** Built lazily — only invoked on the live path, so the config canonicalize + hash is never
|
|
16
|
+
* computed for a noop emitter. */
|
|
17
|
+
readonly identity: () => IdentityEnvelope;
|
|
18
|
+
/** Emitter scope version — the real package version, wired at boot. */
|
|
19
|
+
readonly scopeVersion: string;
|
|
20
|
+
/** Ingestion base URL override (else env / default, resolved by the transport). */
|
|
21
|
+
readonly baseUrl?: string;
|
|
22
|
+
readonly flushIntervalMs?: number;
|
|
23
|
+
}
|
|
24
|
+
export interface RecordingComponents {
|
|
25
|
+
readonly emitter: RecordingEmitter;
|
|
26
|
+
/** The batcher to flush/stop on shutdown; `null` when the emitter is a Noop. */
|
|
27
|
+
readonly batcher: TelemetryBatcher | null;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build the emitter + (optional) batcher. Never throws: any construction error degrades to Noop so
|
|
31
|
+
* telemetry can never block boot.
|
|
32
|
+
*/
|
|
33
|
+
export declare function createRecordingComponents(options: RecordingEmitterOptions): RecordingComponents;
|
|
34
|
+
/**
|
|
35
|
+
* Resolve the enable flag: explicit env override wins, else the recipe's `telemetry.enabled`, else
|
|
36
|
+
* the default (`true`). Recognized env truthy/falsy spellings keep an ops override unambiguous.
|
|
37
|
+
*/
|
|
38
|
+
export declare function resolveTelemetryEnabled(configEnabled: boolean | undefined, envValue: string | undefined): boolean;
|
|
39
|
+
//# sourceMappingURL=emitter-factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emitter-factory.d.ts","sourceRoot":"","sources":["../../../src/recording/wiring/emitter-factory.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGtD,OAAO,EAAyC,KAAK,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAKrG,MAAM,WAAW,uBAAuB;IACtC,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,wEAAwE;IACxE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;sCACkC;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,gBAAgB,CAAC;IAC1C,uEAAuE;IACvE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,mFAAmF;IACnF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;CACnC;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;IACnC,gFAAgF;IAChF,QAAQ,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;CAC3C;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,uBAAuB,GAAG,mBAAmB,CA+B/F;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,OAAO,GAAG,SAAS,EAClC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC3B,OAAO,CAWT"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Construct the recording emitter at boot. Telemetry is ON by default; it degrades to the inert
|
|
3
|
+
* {@link NoopEmitter} when explicitly disabled or when no API token is available — a missing token
|
|
4
|
+
* is never a boot failure. When live, an {@link OtelEmitter} feeds a {@link TelemetryBatcher} that
|
|
5
|
+
* must be shut down on stop.
|
|
6
|
+
*/
|
|
7
|
+
import { noopEmitter } from "../noop-emitter.js";
|
|
8
|
+
import { OtelEmitter } from "../otel/index.js";
|
|
9
|
+
import { createBatcher, resolveTransportConfig } from "../transport/index.js";
|
|
10
|
+
import { createLogger } from "../../utils/logger.js";
|
|
11
|
+
const logger = createLogger("[recording][wiring]");
|
|
12
|
+
/**
|
|
13
|
+
* Build the emitter + (optional) batcher. Never throws: any construction error degrades to Noop so
|
|
14
|
+
* telemetry can never block boot.
|
|
15
|
+
*/
|
|
16
|
+
export function createRecordingComponents(options) {
|
|
17
|
+
if (!options.enabled) {
|
|
18
|
+
logger.info("telemetry recording disabled by config/env; using noop emitter");
|
|
19
|
+
return { emitter: noopEmitter, batcher: null };
|
|
20
|
+
}
|
|
21
|
+
const token = options.token;
|
|
22
|
+
if (!token) {
|
|
23
|
+
logger.warn("telemetry recording enabled but no SENPI_API_KEY available; degrading to noop emitter (no telemetry will be shipped)");
|
|
24
|
+
return { emitter: noopEmitter, batcher: null };
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const identity = options.identity();
|
|
28
|
+
const batcher = createBatcher(resolveTransportConfig({
|
|
29
|
+
getToken: () => token,
|
|
30
|
+
baseUrl: options.baseUrl,
|
|
31
|
+
flushIntervalMs: options.flushIntervalMs,
|
|
32
|
+
}));
|
|
33
|
+
const emitter = new OtelEmitter(identity, batcher, { scopeVersion: options.scopeVersion });
|
|
34
|
+
logger.info("telemetry recording enabled", { service: identity.service });
|
|
35
|
+
return { emitter, batcher };
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
logger.warn("failed to construct telemetry emitter; degrading to noop", {
|
|
39
|
+
err: err instanceof Error ? err.message : String(err),
|
|
40
|
+
});
|
|
41
|
+
return { emitter: noopEmitter, batcher: null };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Resolve the enable flag: explicit env override wins, else the recipe's `telemetry.enabled`, else
|
|
46
|
+
* the default (`true`). Recognized env truthy/falsy spellings keep an ops override unambiguous.
|
|
47
|
+
*/
|
|
48
|
+
export function resolveTelemetryEnabled(configEnabled, envValue) {
|
|
49
|
+
const env = envValue?.trim().toLowerCase();
|
|
50
|
+
if (env === "false" || env === "0" || env === "no" || env === "off")
|
|
51
|
+
return false;
|
|
52
|
+
if (env === "true" || env === "1" || env === "yes" || env === "on")
|
|
53
|
+
return true;
|
|
54
|
+
if (env !== undefined && env !== "") {
|
|
55
|
+
// Telemetry is on by default, so a typo'd opt-out must not be silent.
|
|
56
|
+
logger.warn("unrecognized SENPI_TELEMETRY_ENABLED value; ignoring (use true/false/1/0/yes/no/on/off)", {
|
|
57
|
+
value: envValue,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return configEnabled ?? true;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=emitter-factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emitter-factory.js","sourceRoot":"","sources":["../../../src/recording/wiring/emitter-factory.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAyB,MAAM,uBAAuB,CAAC;AACrG,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErD,MAAM,MAAM,GAAG,YAAY,CAAC,qBAAqB,CAAC,CAAC;AAuBnD;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CAAC,OAAgC;IACxE,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACrB,MAAM,CAAC,IAAI,CAAC,gEAAgE,CAAC,CAAC;QAC9E,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACjD,CAAC;IACD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC5B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,CAAC,IAAI,CACT,sHAAsH,CACvH,CAAC;QACF,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACjD,CAAC;IAED,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,aAAa,CAC3B,sBAAsB,CAAC;YACrB,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK;YACrB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,eAAe,EAAE,OAAO,CAAC,eAAe;SACzC,CAAC,CACH,CAAC;QACF,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;QAC3F,MAAM,CAAC,IAAI,CAAC,6BAA6B,EAAE,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;QAC1E,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;IAC9B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,IAAI,CAAC,0DAA0D,EAAE;YACtE,GAAG,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;SACtD,CAAC,CAAC;QACH,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACjD,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CACrC,aAAkC,EAClC,QAA4B;IAE5B,MAAM,GAAG,GAAG,QAAQ,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,IAAI,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,KAAK;QAAE,OAAO,KAAK,CAAC;IAClF,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,KAAK,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAChF,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,EAAE,EAAE,CAAC;QACpC,sEAAsE;QACtE,MAAM,CAAC,IAAI,CAAC,yFAAyF,EAAE;YACrG,KAAK,EAAE,QAAQ;SAChB,CAAC,CAAC;IACL,CAAC;IACD,OAAO,aAAa,IAAI,IAAI,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build the {@link IdentityEnvelope} and the config fingerprint stamped on every recorded row.
|
|
3
|
+
*
|
|
4
|
+
* The hash is computed over the **unresolved** config (raw, pre-`${VAR}`) with canonically sorted
|
|
5
|
+
* keys: this keeps it stable across secret rotation and deterministic for a byte-identical recipe,
|
|
6
|
+
* and means it never carries resolved secrets.
|
|
7
|
+
*/
|
|
8
|
+
import type { IdentityEnvelope } from "../identity.js";
|
|
9
|
+
/** Logical producer name stamped as `service.name` on every row. Must stay `senpi-trading-runtime`:
|
|
10
|
+
* it matches the sibling ingestion service's documented convention and the rows already in its
|
|
11
|
+
* ClickHouse tables, where `ServiceName` is part of the sort key. */
|
|
12
|
+
export declare const SERVICE_NAME = "senpi-trading-runtime";
|
|
13
|
+
/** SHA-256 hex of the canonicalized unresolved config; `undefined` when no config is available. */
|
|
14
|
+
export declare function computeConfigHash(unresolvedConfig: Record<string, unknown> | undefined): string | undefined;
|
|
15
|
+
export interface BuildIdentityParams {
|
|
16
|
+
/** Recipe / runtime name (the config's top-level `name`). */
|
|
17
|
+
readonly name: string;
|
|
18
|
+
readonly recipeVersion?: string | number;
|
|
19
|
+
/** Strategy identifier = wallet address. */
|
|
20
|
+
readonly strategyAddress: string;
|
|
21
|
+
/** Per-process boot id. */
|
|
22
|
+
readonly bootId: string;
|
|
23
|
+
/** Unresolved config, used to fingerprint the recipe (`configHash`). */
|
|
24
|
+
readonly unresolvedConfig?: Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
export declare function buildIdentity(params: BuildIdentityParams): IdentityEnvelope;
|
|
27
|
+
//# sourceMappingURL=identity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../../src/recording/wiring/identity.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD;;qEAEqE;AACrE,eAAO,MAAM,YAAY,0BAA0B,CAAC;AAiBpD,mGAAmG;AACnG,wBAAgB,iBAAiB,CAAC,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAO3G;AAED,MAAM,WAAW,mBAAmB;IAClC,6DAA6D;IAC7D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzC,4CAA4C;IAC5C,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,2BAA2B;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,wEAAwE;IACxE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrD;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,gBAAgB,CAU3E"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build the {@link IdentityEnvelope} and the config fingerprint stamped on every recorded row.
|
|
3
|
+
*
|
|
4
|
+
* The hash is computed over the **unresolved** config (raw, pre-`${VAR}`) with canonically sorted
|
|
5
|
+
* keys: this keeps it stable across secret rotation and deterministic for a byte-identical recipe,
|
|
6
|
+
* and means it never carries resolved secrets.
|
|
7
|
+
*/
|
|
8
|
+
import { createHash } from "node:crypto";
|
|
9
|
+
/** Logical producer name stamped as `service.name` on every row. Must stay `senpi-trading-runtime`:
|
|
10
|
+
* it matches the sibling ingestion service's documented convention and the rows already in its
|
|
11
|
+
* ClickHouse tables, where `ServiceName` is part of the sort key. */
|
|
12
|
+
export const SERVICE_NAME = "senpi-trading-runtime";
|
|
13
|
+
/**
|
|
14
|
+
* Canonical JSON with recursively sorted object keys, so two structurally-equal configs serialize
|
|
15
|
+
* identically regardless of key order. Arrays keep their order (order is meaningful there).
|
|
16
|
+
*/
|
|
17
|
+
function canonicalize(value) {
|
|
18
|
+
if (Array.isArray(value))
|
|
19
|
+
return value.map(canonicalize);
|
|
20
|
+
if (value !== null && typeof value === "object") {
|
|
21
|
+
const obj = value;
|
|
22
|
+
const out = {};
|
|
23
|
+
for (const key of Object.keys(obj).sort())
|
|
24
|
+
out[key] = canonicalize(obj[key]);
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
/** SHA-256 hex of the canonicalized unresolved config; `undefined` when no config is available. */
|
|
30
|
+
export function computeConfigHash(unresolvedConfig) {
|
|
31
|
+
if (!unresolvedConfig)
|
|
32
|
+
return undefined;
|
|
33
|
+
try {
|
|
34
|
+
return createHash("sha256").update(JSON.stringify(canonicalize(unresolvedConfig))).digest("hex");
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export function buildIdentity(params) {
|
|
41
|
+
return {
|
|
42
|
+
service: SERVICE_NAME,
|
|
43
|
+
recipe: params.name,
|
|
44
|
+
recipeVersion: params.recipeVersion,
|
|
45
|
+
runtime: params.name,
|
|
46
|
+
strategyAddress: params.strategyAddress,
|
|
47
|
+
bootId: params.bootId,
|
|
48
|
+
configHash: computeConfigHash(params.unresolvedConfig),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../../../src/recording/wiring/identity.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC;;qEAEqE;AACrE,MAAM,CAAC,MAAM,YAAY,GAAG,uBAAuB,CAAC;AAEpD;;;GAGG;AACH,SAAS,YAAY,CAAC,KAAc;IAClC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACzD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,MAAM,GAAG,GAAG,KAAgC,CAAC;QAC7C,MAAM,GAAG,GAA4B,EAAE,CAAC;QACxC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE;YAAE,GAAG,CAAC,GAAG,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QAC7E,OAAO,GAAG,CAAC;IACb,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,mGAAmG;AACnG,MAAM,UAAU,iBAAiB,CAAC,gBAAqD;IACrF,IAAI,CAAC,gBAAgB;QAAE,OAAO,SAAS,CAAC;IACxC,IAAI,CAAC;QACH,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACnG,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAcD,MAAM,UAAU,aAAa,CAAC,MAA2B;IACvD,OAAO;QACL,OAAO,EAAE,YAAY;QACrB,MAAM,EAAE,MAAM,CAAC,IAAI;QACnB,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,OAAO,EAAE,MAAM,CAAC,IAAI;QACpB,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,UAAU,EAAE,iBAAiB,CAAC,MAAM,CAAC,gBAAgB,CAAC;KACvD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `src/recording/wiring/` — the integration seam between the trading runtime and the recording
|
|
3
|
+
* emitter: build the identity/emitter at boot, subscribe to the `SenpiEventBus`, and turn events
|
|
4
|
+
* into records. Pure consumer; no producer change.
|
|
5
|
+
*/
|
|
6
|
+
export { buildIdentity, computeConfigHash, SERVICE_NAME } from "./identity.js";
|
|
7
|
+
export type { BuildIdentityParams } from "./identity.js";
|
|
8
|
+
export { createRecordingComponents, resolveTelemetryEnabled } from "./emitter-factory.js";
|
|
9
|
+
export type { RecordingComponents, RecordingEmitterOptions } from "./emitter-factory.js";
|
|
10
|
+
export { createRecordingSubscriber } from "./subscriber.js";
|
|
11
|
+
export type { RecordingSubscriber, RecordingSubscriberDeps } from "./subscriber.js";
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/recording/wiring/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC/E,YAAY,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,yBAAyB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC1F,YAAY,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACzF,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,YAAY,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `src/recording/wiring/` — the integration seam between the trading runtime and the recording
|
|
3
|
+
* emitter: build the identity/emitter at boot, subscribe to the `SenpiEventBus`, and turn events
|
|
4
|
+
* into records. Pure consumer; no producer change.
|
|
5
|
+
*/
|
|
6
|
+
export { buildIdentity, computeConfigHash, SERVICE_NAME } from "./identity.js";
|
|
7
|
+
export { createRecordingComponents, resolveTelemetryEnabled } from "./emitter-factory.js";
|
|
8
|
+
export { createRecordingSubscriber } from "./subscriber.js";
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/recording/wiring/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE/E,OAAO,EAAE,yBAAyB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAE1F,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure builders: bus-event payloads → recording records. No I/O, no emitter — each function reads a
|
|
3
|
+
* loosely-typed payload defensively and returns a fully-populated record (or `null` when the event
|
|
4
|
+
* cannot yield one). Redaction is NOT done here — records are populated faithfully; the mapper is the
|
|
5
|
+
* single redaction seam.
|
|
6
|
+
*
|
|
7
|
+
* Timestamps: the bus carries ISO strings (and, for a scan result, an epoch-ms number); every record
|
|
8
|
+
* stores epoch ms, converted once here.
|
|
9
|
+
*/
|
|
10
|
+
import type { DslTransitionKind, DslTransitionRecord, PositionLifecycleEvent, PositionLifecycleRecord, RuntimeErrorRecord, RuntimeLifecycleRecord, RuntimeStateRecord, ScannerRunRecord, SignalDecision, SignalEvaluatedRecord, SignalSummary } from "../records.js";
|
|
11
|
+
/** From a `tracking.scanner_run` / `tracking.scanner_run_skipped` / `tracking.scanner_run_error`
|
|
12
|
+
* event (complete runs carry the whole `ScanResult`; skip/error carry status + reason). */
|
|
13
|
+
export declare function buildScannerRun(payload: unknown, nowMs: number): ScannerRunRecord | null;
|
|
14
|
+
/** Pass-level decision state held between `tracking.decision` and its `tracking.action_result`. */
|
|
15
|
+
export interface PendingDecision {
|
|
16
|
+
readonly scannerId?: string;
|
|
17
|
+
readonly startedAtMs: number;
|
|
18
|
+
readonly decision: SignalDecision;
|
|
19
|
+
readonly signals: readonly SignalSummary[];
|
|
20
|
+
}
|
|
21
|
+
/** Build the pending decision from a `tracking.decision` payload. */
|
|
22
|
+
export declare function buildPendingDecision(payload: unknown, nowMs: number): PendingDecision | null;
|
|
23
|
+
/**
|
|
24
|
+
* Pair a held {@link PendingDecision} with its `tracking.action_result` payload into one record.
|
|
25
|
+
* `evaluations` is one entry per per-signal result, each enriched with the matching input signal.
|
|
26
|
+
* The pass span runs decision-ts → action_result-ts; on clock skew (`endedAt < startedAt`) the start
|
|
27
|
+
* is pulled up to `endedAt`, yielding a zero (never negative) duration.
|
|
28
|
+
*/
|
|
29
|
+
export declare function buildSignalEvaluated(pending: PendingDecision, actionResultPayload: unknown, nowMs: number): SignalEvaluatedRecord;
|
|
30
|
+
/**
|
|
31
|
+
* A `tracking.action_result` with no held decision — a producer that never emits `tracking.decision`
|
|
32
|
+
* for the pass (e.g. close-position's static-params path, `decision_mode: 'none'` + `params.asset`).
|
|
33
|
+
* The record carries the per-signal outcomes with signals synthesized from the result entries and no
|
|
34
|
+
* `decision` (the contract allows a decision-less pass); zero duration (`startedAt = endedAt` = the
|
|
35
|
+
* action_result timestamp).
|
|
36
|
+
*/
|
|
37
|
+
export declare function buildResultOnlyEvaluated(actionResultPayload: unknown, nowMs: number): SignalEvaluatedRecord | null;
|
|
38
|
+
/**
|
|
39
|
+
* A decision that never received its action_result (the action threw or returned before emitting
|
|
40
|
+
* one). Flushed when the same action's next decision arrives, so a decided-but-unresulted pass is
|
|
41
|
+
* visible on the signal axis rather than silently dropped: no evaluations, zero duration
|
|
42
|
+
* (`startedAt = endedAt =` the decision timestamp).
|
|
43
|
+
*/
|
|
44
|
+
export declare function buildDecisionOnlyEvaluated(pending: PendingDecision): SignalEvaluatedRecord;
|
|
45
|
+
/**
|
|
46
|
+
* From an `on_position_*` event. Action-driven events arrive as HookEvents (fields under a `data`
|
|
47
|
+
* envelope); the DSL monitor / reconcile paths emit `on_position_closed` flat (fields at the root,
|
|
48
|
+
* always with an `asset`), so a flat payload carrying an `asset` is read as-is. The DSL archive
|
|
49
|
+
* handler's re-broadcast of a close is marked `source: "dsl_archive"` and skipped — the close it
|
|
50
|
+
* mirrors was already recorded from the original emit. (`on_open_order_submitted` is deliberately
|
|
51
|
+
* not recorded — its submit fact is already on the signal-evaluation view, avoiding a double count.)
|
|
52
|
+
*/
|
|
53
|
+
export declare function buildPositionLifecycle(event: PositionLifecycleEvent, payload: unknown, nowMs: number): PositionLifecycleRecord | null;
|
|
54
|
+
/** From a `dsl.*` event (fields live at the payload root, with an ISO `timestamp`). */
|
|
55
|
+
export declare function buildDslTransition(transition: DslTransitionKind, payload: unknown, nowMs: number): DslTransitionRecord | null;
|
|
56
|
+
/** From `signal_processing_error` — a bucket-2 error with no specific domain record home. */
|
|
57
|
+
export declare function buildRuntimeError(payload: unknown, nowMs: number): RuntimeErrorRecord | null;
|
|
58
|
+
/**
|
|
59
|
+
* From `tracking.runtime_started`. The `config` blob is the injected **unresolved** config (not the
|
|
60
|
+
* resolved `data.config` on the bus): resolving inlines secrets, and the unresolved form is what the
|
|
61
|
+
* `configHash` is computed over, so blob and hash agree.
|
|
62
|
+
*/
|
|
63
|
+
export declare function buildRuntimeStarted(payload: unknown, unresolvedConfig: Record<string, unknown> | undefined, nowMs: number): RuntimeLifecycleRecord | null;
|
|
64
|
+
/** From `tracking.runtime_stopped`. */
|
|
65
|
+
export declare function buildRuntimeStopped(payload: unknown, nowMs: number): RuntimeLifecycleRecord | null;
|
|
66
|
+
/** From the self-pause HookEvents (`on_strategy_self_paused`/`on_daily_limit_hit`/`on_drawdown_cap_hit`). */
|
|
67
|
+
export declare function buildRuntimePaused(payload: unknown, fallbackGateId: string, nowMs: number): RuntimeStateRecord | null;
|
|
68
|
+
//# sourceMappingURL=record-builders.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record-builders.d.ts","sourceRoot":"","sources":["../../../src/recording/wiring/record-builders.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,EACtB,uBAAuB,EACvB,kBAAkB,EAClB,sBAAsB,EACtB,kBAAkB,EAElB,gBAAgB,EAChB,cAAc,EACd,qBAAqB,EAIrB,aAAa,EAEd,MAAM,eAAe,CAAC;AAoDvB;2FAC2F;AAC3F,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CA4BxF;AAID,mGAAmG;AACnG,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,CAAC;CAC5C;AAED,qEAAqE;AACrE,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAwB5F;AAsFD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,qBAAqB,CAqBjI;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,mBAAmB,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,qBAAqB,GAAG,IAAI,CAWlH;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,eAAe,GAAG,qBAAqB,CAS1F;AAUD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,sBAAsB,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,uBAAuB,GAAG,IAAI,CAoCrI;AAID,uFAAuF;AACvF,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,iBAAiB,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,mBAAmB,GAAG,IAAI,CA+C7H;AAID,6FAA6F;AAC7F,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CA0B5F;AAID;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,sBAAsB,GAAG,IAAI,CAczJ;AAED,uCAAuC;AACvC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,sBAAsB,GAAG,IAAI,CAWlG;AAID,6GAA6G;AAC7G,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAcrH"}
|