@bleedingdev/modern-js-server-runtime-extensions 0.0.0-trusted-publisher-bootstrap

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 (64) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +67 -0
  3. package/dist/cjs/contractGateAutopilot.js +162 -0
  4. package/dist/cjs/contractGateSnapshotStore.js +253 -0
  5. package/dist/cjs/env.js +58 -0
  6. package/dist/cjs/index.js +162 -0
  7. package/dist/cjs/mfCache.js +106 -0
  8. package/dist/cjs/moduleFederationCss.js +285 -0
  9. package/dist/cjs/runtimeFallbackSignal.js +311 -0
  10. package/dist/cjs/telemetry.js +373 -0
  11. package/dist/cjs/telemetryCore.js +819 -0
  12. package/dist/esm/contractGateAutopilot.mjs +124 -0
  13. package/dist/esm/contractGateSnapshotStore.mjs +190 -0
  14. package/dist/esm/env.mjs +17 -0
  15. package/dist/esm/index.mjs +6 -0
  16. package/dist/esm/mfCache.mjs +55 -0
  17. package/dist/esm/moduleFederationCss.mjs +225 -0
  18. package/dist/esm/runtimeFallbackSignal.mjs +222 -0
  19. package/dist/esm/telemetry.mjs +275 -0
  20. package/dist/esm/telemetryCore.mjs +759 -0
  21. package/dist/esm-node/contractGateAutopilot.mjs +125 -0
  22. package/dist/esm-node/contractGateSnapshotStore.mjs +192 -0
  23. package/dist/esm-node/env.mjs +18 -0
  24. package/dist/esm-node/index.mjs +7 -0
  25. package/dist/esm-node/mfCache.mjs +56 -0
  26. package/dist/esm-node/moduleFederationCss.mjs +226 -0
  27. package/dist/esm-node/runtimeFallbackSignal.mjs +223 -0
  28. package/dist/esm-node/telemetry.mjs +276 -0
  29. package/dist/esm-node/telemetryCore.mjs +760 -0
  30. package/dist/types/contractGateAutopilot.d.ts +35 -0
  31. package/dist/types/contractGateSnapshotStore.d.ts +57 -0
  32. package/dist/types/env.d.ts +40 -0
  33. package/dist/types/index.d.ts +6 -0
  34. package/dist/types/mfCache.d.ts +27 -0
  35. package/dist/types/moduleFederationCss.d.ts +87 -0
  36. package/dist/types/runtimeFallbackSignal.d.ts +94 -0
  37. package/dist/types/telemetry.d.ts +12 -0
  38. package/dist/types/telemetryCore.d.ts +257 -0
  39. package/package.json +69 -0
  40. package/rslib.config.mts +4 -0
  41. package/rstest.config.mts +7 -0
  42. package/src/contractGateAutopilot.ts +247 -0
  43. package/src/contractGateSnapshotStore.ts +420 -0
  44. package/src/env.ts +63 -0
  45. package/src/index.ts +84 -0
  46. package/src/mfCache.ts +119 -0
  47. package/src/moduleFederationCss.ts +473 -0
  48. package/src/runtimeFallbackSignal.ts +584 -0
  49. package/src/telemetry.ts +554 -0
  50. package/src/telemetryCore.ts +1332 -0
  51. package/tests/contractGateAutopilot.test.ts +203 -0
  52. package/tests/contractGateSnapshotStore.test.ts +223 -0
  53. package/tests/env.test.ts +73 -0
  54. package/tests/helpers.ts +19 -0
  55. package/tests/mfCache.test.ts +150 -0
  56. package/tests/moduleFederationCss.test.ts +392 -0
  57. package/tests/registration.test.ts +112 -0
  58. package/tests/telemetry.test.ts +360 -0
  59. package/tests/telemetryAutopilot.test.ts +993 -0
  60. package/tests/telemetryCanaryOrchestrator.test.ts +140 -0
  61. package/tests/telemetryLifecycle.test.ts +168 -0
  62. package/tests/telemetryTraceparent.test.ts +167 -0
  63. package/tests/tsconfig.json +11 -0
  64. package/tsconfig.json +10 -0
@@ -0,0 +1,35 @@
1
+ import { type ContractGateSnapshotStore } from './contractGateSnapshotStore';
2
+ import type { TelemetryCanaryOrchestrator } from './telemetryCore';
3
+ type LoggerLike = {
4
+ info?: (message: string) => void;
5
+ warn?: (message: string) => void;
6
+ };
7
+ export type ContractGateAutopilotOptions = {
8
+ orchestrator: TelemetryCanaryOrchestrator;
9
+ gateSnapshotPath?: string;
10
+ gateSnapshotStore?: ContractGateSnapshotStore;
11
+ pollIntervalMs?: number;
12
+ gateStaleAfterMs?: number;
13
+ logger?: LoggerLike;
14
+ };
15
+ export declare class ContractGateAutopilot {
16
+ private readonly orchestrator;
17
+ private readonly gateSnapshotStore;
18
+ private readonly gateSnapshotPath?;
19
+ private readonly pollIntervalMs;
20
+ private readonly gateStaleAfterMs;
21
+ private readonly logger?;
22
+ private poller?;
23
+ private lastSnapshotFingerprint?;
24
+ private readonly appliedGateFingerprints;
25
+ constructor(options: ContractGateAutopilotOptions);
26
+ start(): Promise<void>;
27
+ stop(): void;
28
+ syncOnce(): Promise<number>;
29
+ private loadSnapshot;
30
+ private normalizeSnapshot;
31
+ private normalizeGateValue;
32
+ private normalizeUpdatedAt;
33
+ private normalizeExpiresAt;
34
+ }
35
+ export {};
@@ -0,0 +1,57 @@
1
+ export declare const CONTRACT_GATE_SNAPSHOT_SCHEMA_VERSION = 1;
2
+ export declare const DEFAULT_CONTRACT_GATE_SNAPSHOT_PATH = ".modern/contract-gates.json";
3
+ export type GateSnapshotGateValue = boolean | {
4
+ passed?: boolean;
5
+ reason?: string;
6
+ updatedAt?: number;
7
+ expiresAt?: number;
8
+ [key: string]: unknown;
9
+ };
10
+ export type GateSnapshot = {
11
+ schemaVersion?: number;
12
+ updatedAt?: number;
13
+ gates?: Record<string, GateSnapshotGateValue>;
14
+ };
15
+ type LoggerLike = {
16
+ info?: (message: string) => void;
17
+ warn?: (message: string) => void;
18
+ };
19
+ export type ContractGateSnapshotStore = {
20
+ name: string;
21
+ readSnapshot: () => Promise<GateSnapshot | undefined>;
22
+ writeSnapshot: (snapshot: GateSnapshot) => Promise<void>;
23
+ };
24
+ export type ContractGateSnapshotStoreFactoryContext = {
25
+ appDirectory: string;
26
+ gateSnapshotPath: string;
27
+ options?: Record<string, unknown>;
28
+ logger?: LoggerLike;
29
+ };
30
+ export type ContractGateSnapshotStoreFactory = (context: ContractGateSnapshotStoreFactoryContext) => Promise<ContractGateSnapshotStore> | ContractGateSnapshotStore;
31
+ export type ContractGateSnapshotStoreModule = {
32
+ createContractGateSnapshotStore?: ContractGateSnapshotStoreFactory;
33
+ default?: ContractGateSnapshotStoreFactory | {
34
+ createContractGateSnapshotStore?: ContractGateSnapshotStoreFactory;
35
+ };
36
+ };
37
+ export type ContractGateSnapshotStoreUserConfig = {
38
+ module: string;
39
+ options?: Record<string, unknown>;
40
+ };
41
+ export type ContractGateSnapshotHttpStoreOptions = {
42
+ endpoint: string;
43
+ readMethod?: string;
44
+ writeMethod?: string;
45
+ headers?: Record<string, string>;
46
+ timeoutMs?: number;
47
+ };
48
+ export declare const createHttpContractGateSnapshotStore: (options: ContractGateSnapshotHttpStoreOptions) => ContractGateSnapshotStore;
49
+ export declare const resolveContractGateSnapshotPath: (appDirectory: string, configuredPath: string | undefined) => string;
50
+ export declare const createFileContractGateSnapshotStore: (gateSnapshotPath: string) => ContractGateSnapshotStore;
51
+ export declare const resolveContractGateSnapshotStore: (input: {
52
+ appDirectory: string;
53
+ gateSnapshotPath: string;
54
+ stateStore?: ContractGateSnapshotStoreUserConfig;
55
+ logger?: LoggerLike;
56
+ }) => Promise<ContractGateSnapshotStore>;
57
+ export {};
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Single typed pass over the statically-known environment variables consumed
3
+ * by the ultramodern.js server runtime extensions (telemetry pipeline and
4
+ * contract-gate canary autopilot).
5
+ *
6
+ * Modules in this package read this environment state through
7
+ * `parseServerRuntimeExtensionsEnv()` so the surface is documented and
8
+ * testable in one place, with one documented exception: the telemetry
9
+ * runtime-fallback-signal auth config can name an arbitrary token variable
10
+ * via `auth.expectedValueEnv`, which is necessarily read dynamically from
11
+ * `process.env` when that config is normalized. See the package README for
12
+ * per-variable docs.
13
+ */
14
+ export declare const DEFAULT_ENVIRONMENT_NAME = "development";
15
+ export interface ServerRuntimeExtensionsEnv {
16
+ /**
17
+ * `MODERN_ENV` — deployment environment name loaded by the Modern.js env
18
+ * bootstrap (`.env.{MODERN_ENV}`). Undefined when unset or blank.
19
+ */
20
+ modernEnv?: string;
21
+ /** `NODE_ENV` — standard Node.js environment name. Undefined when unset or blank. */
22
+ nodeEnv?: string;
23
+ /**
24
+ * Effective telemetry environment label:
25
+ * `MODERN_ENV` || `NODE_ENV` || `"development"`.
26
+ */
27
+ environmentName: string;
28
+ /**
29
+ * `MODERN_CONTRACT_GATES_FILE` — path of the contract-gate snapshot file
30
+ * (absolute, or relative to the app directory). Undefined when unset.
31
+ */
32
+ contractGatesFile?: string;
33
+ }
34
+ /**
35
+ * Parse the statically-known environment variables consumed by this package
36
+ * in one typed, documented pass. Defaults are applied here so consumers never
37
+ * touch `process.env` directly (except the documented `expectedValueEnv`
38
+ * indirection above).
39
+ */
40
+ export declare const parseServerRuntimeExtensionsEnv: (env?: Record<string, string | undefined>) => ServerRuntimeExtensionsEnv;
@@ -0,0 +1,6 @@
1
+ export { ContractGateAutopilot, type ContractGateAutopilotOptions, } from './contractGateAutopilot';
2
+ export { CONTRACT_GATE_SNAPSHOT_SCHEMA_VERSION, type ContractGateSnapshotHttpStoreOptions, type ContractGateSnapshotStore, type ContractGateSnapshotStoreFactory, type ContractGateSnapshotStoreFactoryContext, type ContractGateSnapshotStoreModule, type ContractGateSnapshotStoreUserConfig, createFileContractGateSnapshotStore, createHttpContractGateSnapshotStore, DEFAULT_CONTRACT_GATE_SNAPSHOT_PATH, type GateSnapshot, type GateSnapshotGateValue, resolveContractGateSnapshotPath, resolveContractGateSnapshotStore, } from './contractGateSnapshotStore';
3
+ export { DEFAULT_ENVIRONMENT_NAME, parseServerRuntimeExtensionsEnv, type ServerRuntimeExtensionsEnv, } from './env';
4
+ export { getRequestPathname, injectMfAssetCacheHeadersPlugin, isMfManifestAsset, isMfRemoteEntryAsset, resolveMfAssetCacheHeaders, } from './mfCache';
5
+ export { type CollectDirectRemoteModuleFederationCssOptions, collectDirectRemoteModuleFederationCss, collectDirectRemoteModuleFederationCssWithMeta, collectModuleFederationManifestCss, createModuleFederationCssCollector, injectModuleFederationCssPlugin, type ModuleFederationCssCollectorOptions, type ModuleFederationCssPluginOptions, type ModuleFederationManifest, type RemoteModuleFederationCssCollection, } from './moduleFederationCss';
6
+ export { createOtlpTelemetryExporter, createRuntimeFallbackSignalRuntimeState, createRuntimeSignalError, createTelemetryAwareMetrics, createVictoriaMetricsTelemetryExporter, DEFAULT_RUNTIME_FALLBACK_SIGNAL_ENDPOINT, DEFAULT_RUNTIME_STATUS_ENDPOINT, enforceRuntimeFallbackSignalAuthToken, enforceRuntimeFallbackSignalTrustPolicy, getRuntimeSignalErrorStatusCode, hasEnabledTelemetryExporters, injectTelemetryPlugin, normalizeRequiredRuntimeFallbackSignalAuthConfig, normalizeRuntimeFallbackSignalAuthConfig, normalizeRuntimeFallbackTrustPolicy, type OtlpExporterOptions, parseRuntimeFallbackSignalPayloadFromRawBody, type RuntimeFallbackSignalAuthConfig, type RuntimeFallbackSignalRuntimeState, type RuntimeFallbackSignalSource, type RuntimeFallbackSignalTrustContext, type RuntimeFallbackSignalTrustPolicy, type RuntimeSignalError, type RuntimeSignalErrorCode, resolveRuntimeFallbackSignalEndpoint, resolveTelemetrySloOptions, type TelemetryCanaryDecision, TelemetryCanaryOrchestrator, type TelemetryCanaryStatusSnapshot, type TelemetryEnvelope, type TelemetryExporter, type TelemetryQueueStats, TelemetryRegistry, type TelemetryRegistryOptions, type TelemetrySignalType, type TelemetrySloAlert, TelemetryStartupHealthError, type VictoriaMetricsExporterOptions, } from './telemetry';
@@ -0,0 +1,27 @@
1
+ import type { ServerPlugin } from '@modern-js/server-core';
2
+ export declare function getRequestPathname(url: string): string;
3
+ export declare function isMfManifestAsset(pathname: string): boolean;
4
+ export declare function isMfRemoteEntryAsset(pathname: string): boolean;
5
+ export declare function resolveMfAssetCacheHeaders(url: string, query?: Record<string, unknown>): {
6
+ 'cache-control': string;
7
+ pragma: string;
8
+ expires: string;
9
+ } | {
10
+ pragma?: undefined;
11
+ expires?: undefined;
12
+ 'cache-control': string;
13
+ } | undefined;
14
+ /**
15
+ * Applies the documented MF asset cache-header policy (ADR-0002) to responses
16
+ * for module federation manifest/remoteEntry endpoints:
17
+ *
18
+ * - `mf-manifest.json` / `mf-stats.json` are never cached (`no-store`), so
19
+ * hosts always observe remote redeploys;
20
+ * - `remoteEntry*.js` revalidates unless explicitly version-pinned via a
21
+ * `mfv`/`v`/`version` query parameter, in which case it is immutable.
22
+ *
23
+ * Registered by @modern-js/prod-server next to the other fork plugins; the
24
+ * middleware runs in the `pre` phase so it wraps the static-file middleware
25
+ * that actually serves these assets.
26
+ */
27
+ export declare const injectMfAssetCacheHeadersPlugin: () => ServerPlugin;
@@ -0,0 +1,87 @@
1
+ import type { ServerPlugin } from '@modern-js/server-core';
2
+ import type { Monitors } from '@modern-js/types';
3
+ type ModuleFederationAssets = {
4
+ css?: {
5
+ sync?: string[];
6
+ async?: string[];
7
+ };
8
+ };
9
+ export type ModuleFederationManifest = {
10
+ metaData?: {
11
+ publicPath?: string;
12
+ };
13
+ shared?: Array<{
14
+ assets?: ModuleFederationAssets;
15
+ }>;
16
+ remotes?: Array<{
17
+ entry?: string;
18
+ assets?: ModuleFederationAssets;
19
+ }>;
20
+ exposes?: Array<{
21
+ assets?: ModuleFederationAssets;
22
+ }>;
23
+ };
24
+ type FetchLike = (input: string, init?: {
25
+ signal?: AbortSignal;
26
+ }) => Promise<Response>;
27
+ export type CollectDirectRemoteModuleFederationCssOptions = {
28
+ fetcher?: FetchLike;
29
+ monitors?: Monitors;
30
+ timeout?: number;
31
+ };
32
+ export declare const collectModuleFederationManifestCss: (manifest: ModuleFederationManifest, manifestUrl: string) => string[];
33
+ export type RemoteModuleFederationCssCollection = {
34
+ assets: string[];
35
+ /**
36
+ * True when at least one remote manifest fetch failed, i.e. `assets` may be
37
+ * incomplete and should not be cached long-term.
38
+ */
39
+ errored: boolean;
40
+ };
41
+ export declare const collectDirectRemoteModuleFederationCssWithMeta: (pwd: string, options?: CollectDirectRemoteModuleFederationCssOptions) => Promise<RemoteModuleFederationCssCollection>;
42
+ export declare const collectDirectRemoteModuleFederationCss: (pwd: string, options?: CollectDirectRemoteModuleFederationCssOptions) => Promise<string[]>;
43
+ export type ModuleFederationCssCollectorOptions = CollectDirectRemoteModuleFederationCssOptions & {
44
+ /**
45
+ * How long a successful remote CSS collection may be served from cache.
46
+ * `0` disables caching (beyond in-flight request coalescing).
47
+ */
48
+ ttlMs?: number;
49
+ /** Clock override for tests. */
50
+ now?: () => number;
51
+ };
52
+ /**
53
+ * TTL cache around remote MF CSS collection. Remote manifests mutate
54
+ * independently of the host (that is the point of module federation), so the
55
+ * collection must expire: a boot-time-forever cache serves stale or broken
56
+ * CSS links after any remote redeploy.
57
+ *
58
+ * Error handling: a collection where any remote fetch failed is never cached.
59
+ * The last known-good asset list is served instead (stale-on-error) and the
60
+ * next request retries the collection.
61
+ */
62
+ export declare const createModuleFederationCssCollector: (pwd: string, options?: ModuleFederationCssCollectorOptions) => {
63
+ collect(monitors?: Monitors): Promise<string[]>;
64
+ };
65
+ export type ModuleFederationCssPluginOptions = {
66
+ /**
67
+ * TTL for the cached remote CSS collection in production.
68
+ *
69
+ * @default 30000 in production, 0 (no caching) otherwise
70
+ */
71
+ remoteCssCacheTtlMs?: number;
72
+ };
73
+ /**
74
+ * Enriches the request-scoped server manifest with CSS assets collected from
75
+ * direct module federation remotes, so SSR/CSR-RSC rendering can inline
76
+ * `<link>` tags for remote CSS.
77
+ *
78
+ * In production the collection is cached with a TTL (default 30s) instead of
79
+ * being pinned at boot: remote manifests change on every remote redeploy, and
80
+ * fetch failures must not pin an empty/partial list for the process lifetime.
81
+ *
82
+ * This plugin must be registered after `injectResourcePlugin()` (which sets
83
+ * `serverManifest` on the request context). @modern-js/prod-server wires it
84
+ * into its plugin assembly for both production and dev servers.
85
+ */
86
+ export declare const injectModuleFederationCssPlugin: (options?: ModuleFederationCssPluginOptions) => ServerPlugin;
87
+ export {};
@@ -0,0 +1,94 @@
1
+ import type { Context, ServerEnv } from '@modern-js/server-core';
2
+ import { type ContractGateSnapshotStore } from './contractGateSnapshotStore';
3
+ export declare const DEFAULT_RUNTIME_FALLBACK_SIGNAL_ENDPOINT = "/_modern/contract-gates/runtime-fallback";
4
+ export declare const DEFAULT_RUNTIME_STATUS_ENDPOINT = "/_modern/runtime/status";
5
+ export declare const DEFAULT_RUNTIME_FALLBACK_GATE_NAME = "runtime-mf-fallback-health";
6
+ export declare const DEFAULT_RUNTIME_FALLBACK_FAILURE_HOLD_MS: number;
7
+ export declare const DEFAULT_RUNTIME_FALLBACK_MAX_BODY_BYTES: number;
8
+ export type RuntimeSignalErrorCode = 'PAYLOAD_TOO_LARGE' | 'INVALID_PAYLOAD' | 'RATE_LIMITED' | 'UNAUTHORIZED' | 'UNTRUSTED_SOURCE';
9
+ export type RuntimeSignalError = Error & {
10
+ code?: RuntimeSignalErrorCode;
11
+ };
12
+ export type RuntimeFallbackSignalTrustPolicy = {
13
+ allowedApps: string[];
14
+ allowedEntryOrigins: string[];
15
+ expectedRuntimeDigests: Record<string, string>;
16
+ enforceRuntimeDigest: boolean;
17
+ maxSignalsPerWindow: number;
18
+ windowMs: number;
19
+ dedupeWindowMs: number;
20
+ };
21
+ type RuntimeFallbackSignalRateLimitState = {
22
+ count: number;
23
+ windowStartedAt: number;
24
+ };
25
+ export type RuntimeFallbackSignalAuthConfig = {
26
+ enabled: boolean;
27
+ headerName: string;
28
+ expectedValue?: string;
29
+ };
30
+ export type RuntimeFallbackSignalRuntimeState = {
31
+ rateLimitBySource: Map<string, RuntimeFallbackSignalRateLimitState>;
32
+ dedupeByFingerprint: Map<string, number>;
33
+ };
34
+ export type RuntimeFallbackSignalTrustContext = {
35
+ trustPolicy: RuntimeFallbackSignalTrustPolicy;
36
+ runtimeState: RuntimeFallbackSignalRuntimeState;
37
+ };
38
+ export type RuntimeFallbackSignalConfig = {
39
+ endpoint: string;
40
+ gateName: string;
41
+ gateSnapshotStore: Promise<ContractGateSnapshotStore>;
42
+ failureHoldMs: number;
43
+ maxBodyBytes: number;
44
+ auth: RuntimeFallbackSignalAuthConfig;
45
+ trustPolicy: RuntimeFallbackSignalTrustPolicy;
46
+ runtimeState: RuntimeFallbackSignalRuntimeState;
47
+ };
48
+ export declare function resolveRuntimeFallbackSignalEndpoint(configuredEndpoint?: string): string;
49
+ export declare function createRuntimeSignalError(message: string, code: RuntimeSignalError['code']): RuntimeSignalError;
50
+ export declare function normalizeRuntimeFallbackSignalAuthConfig(configured: {
51
+ enabled?: boolean;
52
+ headerName?: string;
53
+ expectedValue?: string;
54
+ expectedValueEnv?: string;
55
+ } | undefined): RuntimeFallbackSignalAuthConfig;
56
+ /**
57
+ * Normalizes the auth config for the runtime fallback signal endpoint when the
58
+ * endpoint itself is enabled. The endpoint can persist failing contract gates
59
+ * (a canary kill switch), so it always requires a token: auth cannot be
60
+ * disabled and a token must be configured via `auth.expectedValue` or
61
+ * `auth.expectedValueEnv`.
62
+ */
63
+ export declare function normalizeRequiredRuntimeFallbackSignalAuthConfig(configured: Parameters<typeof normalizeRuntimeFallbackSignalAuthConfig>[0]): RuntimeFallbackSignalAuthConfig;
64
+ export declare function enforceRuntimeFallbackSignalAuthToken(token: string | undefined, authConfig: RuntimeFallbackSignalAuthConfig): void;
65
+ export declare function enforceRuntimeFallbackSignalAuth(c: Context<ServerEnv>, runtimeSignalConfig: RuntimeFallbackSignalConfig): void;
66
+ export declare function normalizeRuntimeFallbackTrustPolicy(configured: {
67
+ allowedApps?: string[];
68
+ allowedEntryOrigins?: string[];
69
+ expectedRuntimeDigests?: Record<string, string>;
70
+ enforceRuntimeDigest?: boolean;
71
+ maxSignalsPerWindow?: number;
72
+ windowMs?: number;
73
+ dedupeWindowMs?: number;
74
+ } | undefined): RuntimeFallbackSignalTrustPolicy;
75
+ export declare function createRuntimeFallbackSignalRuntimeState(): RuntimeFallbackSignalRuntimeState;
76
+ export type RuntimeFallbackSignalSource = {
77
+ /**
78
+ * Server-trusted connection identity (socket remote address). Never derive
79
+ * this from request headers or the payload: both are attacker-controlled
80
+ * and would let callers reset their own rate-limit budget.
81
+ */
82
+ remoteAddress?: string;
83
+ };
84
+ export declare function enforceRuntimeFallbackSignalTrustPolicy(payload: Record<string, unknown>, runtimeSignalContext: RuntimeFallbackSignalTrustContext, source?: RuntimeFallbackSignalSource): {
85
+ deduped: boolean;
86
+ };
87
+ export declare function parseRuntimeFallbackSignalPayload(c: Context<ServerEnv>, maxBodyBytes: number): Promise<{
88
+ rawBody: string;
89
+ payload: Record<string, unknown>;
90
+ }>;
91
+ export declare function parseRuntimeFallbackSignalPayloadFromRawBody(rawBody: string, maxBodyBytes: number): Record<string, unknown>;
92
+ export declare function getRuntimeSignalErrorStatusCode(signalError: RuntimeSignalError): 400 | 401 | 403 | 413 | 429 | 500;
93
+ export declare function persistRuntimeFallbackContractGate(payload: Record<string, unknown>, runtimeSignalConfig: RuntimeFallbackSignalConfig): Promise<void>;
94
+ export {};
@@ -0,0 +1,12 @@
1
+ import type { ServerPlugin, ServerTelemetryUserConfig } from '@modern-js/server-core';
2
+ import { type TelemetryRegistryOptions } from './telemetryCore';
3
+ export { createRuntimeFallbackSignalRuntimeState, createRuntimeSignalError, DEFAULT_RUNTIME_FALLBACK_SIGNAL_ENDPOINT, DEFAULT_RUNTIME_STATUS_ENDPOINT, enforceRuntimeFallbackSignalAuthToken, enforceRuntimeFallbackSignalTrustPolicy, getRuntimeSignalErrorStatusCode, normalizeRequiredRuntimeFallbackSignalAuthConfig, normalizeRuntimeFallbackSignalAuthConfig, normalizeRuntimeFallbackTrustPolicy, parseRuntimeFallbackSignalPayloadFromRawBody, type RuntimeFallbackSignalAuthConfig, type RuntimeFallbackSignalRuntimeState, type RuntimeFallbackSignalSource, type RuntimeFallbackSignalTrustContext, type RuntimeFallbackSignalTrustPolicy, type RuntimeSignalError, type RuntimeSignalErrorCode, resolveRuntimeFallbackSignalEndpoint, } from './runtimeFallbackSignal';
4
+ export { createOtlpTelemetryExporter, createTelemetryAwareMetrics, createVictoriaMetricsTelemetryExporter, type OtlpExporterOptions, type TelemetryCanaryAction, type TelemetryCanaryContractGateStatus, type TelemetryCanaryDecision, type TelemetryCanaryFailure, type TelemetryCanaryFailureReason, TelemetryCanaryOrchestrator, type TelemetryCanaryOrchestratorOptions, type TelemetryCanaryState, type TelemetryCanaryStatusSnapshot, type TelemetryEnvelope, type TelemetryExporter, type TelemetryExporterHealthStatus, type TelemetryQueueStats, TelemetryRegistry, type TelemetryRegistryOptions, type TelemetrySignalType, type TelemetrySloAlert, type TelemetrySloAlertType, TelemetryStartupHealthError, type VictoriaMetricsExporterOptions, } from './telemetryCore';
5
+ export declare const hasEnabledTelemetryExporters: (config: ServerTelemetryUserConfig | undefined) => boolean;
6
+ /**
7
+ * Builds the registry SLO options from `server.telemetry.slo`, attaching a
8
+ * logger sink so threshold breaches surface as server warnings (parity with
9
+ * the pre-extraction prod-server harness).
10
+ */
11
+ export declare const resolveTelemetrySloOptions: (sloConfig: ServerTelemetryUserConfig['slo'], warnSink?: (message: string) => void) => NonNullable<TelemetryRegistryOptions['slo']>;
12
+ export declare const injectTelemetryPlugin: () => ServerPlugin;
@@ -0,0 +1,257 @@
1
+ import type { Metrics, MonitorEvent } from '@modern-js/types';
2
+ export type TelemetrySignalType = 'log' | 'metric' | 'trace';
3
+ export interface TelemetryEnvelope {
4
+ timestamp: number;
5
+ service: string;
6
+ module: string;
7
+ environment: string;
8
+ signalType: TelemetrySignalType;
9
+ name: string;
10
+ level?: string;
11
+ value?: number;
12
+ unit?: string;
13
+ traceId?: string;
14
+ spanId?: string;
15
+ parentSpanId?: string;
16
+ tags?: Record<string, string>;
17
+ attributes?: Record<string, unknown>;
18
+ error?: {
19
+ name?: string;
20
+ message: string;
21
+ stack?: string;
22
+ };
23
+ }
24
+ export interface TelemetryExporter {
25
+ name: string;
26
+ init?: (context: {
27
+ service: string;
28
+ module: string;
29
+ environment: string;
30
+ }) => void | Promise<void>;
31
+ emit: (batch: TelemetryEnvelope[]) => void | Promise<void>;
32
+ flush?: () => void | Promise<void>;
33
+ shutdown?: () => void | Promise<void>;
34
+ }
35
+ export interface TelemetryRegistryOptions {
36
+ service: string;
37
+ module: string;
38
+ environment: string;
39
+ samplingRate?: number;
40
+ flushIntervalMs?: number;
41
+ maxBatchSize?: number;
42
+ maxQueueSize?: number;
43
+ redactionKeys?: string[];
44
+ slo?: {
45
+ queueUtilizationWarnThreshold?: number;
46
+ queueDroppedWarnThreshold?: number;
47
+ alertCooldownMs?: number;
48
+ onAlert?: (alert: TelemetrySloAlert) => void;
49
+ };
50
+ }
51
+ export type TelemetrySloAlertType = 'queue.utilization' | 'queue.drop';
52
+ export interface TelemetrySloAlert {
53
+ timestamp: number;
54
+ service: string;
55
+ module: string;
56
+ environment: string;
57
+ type: TelemetrySloAlertType;
58
+ value: number;
59
+ threshold: number;
60
+ queueDepth: number;
61
+ queueCapacity: number;
62
+ queueUtilization: number;
63
+ totalDropped: number;
64
+ }
65
+ export interface TelemetryQueueStats {
66
+ depth: number;
67
+ capacity: number;
68
+ utilization: number;
69
+ pendingDropped: number;
70
+ totalDropped: number;
71
+ }
72
+ export type TelemetryCanaryState = 'canary' | 'promoted' | 'rolled_back';
73
+ export type TelemetryCanaryAction = 'hold' | 'promote' | 'rollback';
74
+ export type TelemetryCanaryFailureReason = 'queue_utilization' | 'queue_dropped' | 'unhealthy_exporter' | 'contract_gate_missing' | 'contract_gate_failed';
75
+ export interface TelemetryCanaryFailure {
76
+ reason: TelemetryCanaryFailureReason;
77
+ gate?: string;
78
+ message?: string;
79
+ threshold?: number;
80
+ value?: number;
81
+ }
82
+ export interface TelemetryCanaryContractGateStatus {
83
+ name: string;
84
+ passed: boolean;
85
+ reason?: string;
86
+ updatedAt: number;
87
+ }
88
+ export interface TelemetryCanaryDecision {
89
+ timestamp: number;
90
+ action: TelemetryCanaryAction;
91
+ state: TelemetryCanaryState;
92
+ consecutiveHealthy: number;
93
+ consecutiveFailures: number;
94
+ failures: TelemetryCanaryFailure[];
95
+ queueStats: TelemetryQueueStats;
96
+ unhealthyExporterCount: number;
97
+ contractGates: TelemetryCanaryContractGateStatus[];
98
+ }
99
+ export interface TelemetryCanaryStatusSnapshot {
100
+ timestamp: number;
101
+ state: TelemetryCanaryState;
102
+ consecutiveHealthy: number;
103
+ consecutiveFailures: number;
104
+ queueStats: TelemetryQueueStats;
105
+ unhealthyExporterCount: number;
106
+ requiredContractGates: string[];
107
+ contractGates: TelemetryCanaryContractGateStatus[];
108
+ failurePreview: TelemetryCanaryFailure[];
109
+ }
110
+ export interface TelemetryCanaryOrchestratorOptions {
111
+ registry: TelemetryRegistry;
112
+ evaluationIntervalMs?: number;
113
+ minConsecutiveHealthyEvaluations?: number;
114
+ rollbackConsecutiveFailures?: number;
115
+ maxQueueUtilization?: number;
116
+ maxTotalDropped?: number;
117
+ maxUnhealthyExporters?: number;
118
+ requiredContractGates?: string[];
119
+ onEvaluate?: (decision: TelemetryCanaryDecision) => void;
120
+ onPromote?: (decision: TelemetryCanaryDecision) => void;
121
+ onRollback?: (decision: TelemetryCanaryDecision) => void;
122
+ }
123
+ export interface TelemetryExporterHealthStatus {
124
+ name: string;
125
+ healthy: boolean;
126
+ failures: number;
127
+ lastError?: string;
128
+ lastSuccessAt?: number;
129
+ lastFailureAt?: number;
130
+ }
131
+ export declare class TelemetryStartupHealthError extends Error {
132
+ readonly code = "TELEMETRY_EXPORTER_STARTUP_HEALTH_FAILED";
133
+ readonly failedExporters: TelemetryExporterHealthStatus[];
134
+ constructor(failedExporters: TelemetryExporterHealthStatus[]);
135
+ }
136
+ export interface OtlpExporterOptions {
137
+ endpoint?: string;
138
+ headers?: Record<string, string>;
139
+ timeoutMs?: number;
140
+ }
141
+ export interface VictoriaMetricsExporterOptions extends OtlpExporterOptions {
142
+ metricPrefix?: string;
143
+ }
144
+ export declare function toTelemetryEnvelope(event: MonitorEvent, input: {
145
+ service: string;
146
+ module: string;
147
+ environment: string;
148
+ traceId?: string;
149
+ spanId?: string;
150
+ attributes?: Record<string, unknown>;
151
+ }): TelemetryEnvelope;
152
+ export declare function createOtlpTelemetryExporter(options?: OtlpExporterOptions): TelemetryExporter;
153
+ export declare function createVictoriaMetricsTelemetryExporter(options?: VictoriaMetricsExporterOptions): TelemetryExporter;
154
+ export declare class TelemetryRegistry {
155
+ private readonly exporters;
156
+ private readonly queue;
157
+ private readonly redactionKeys;
158
+ private readonly service;
159
+ private readonly module;
160
+ private readonly environment;
161
+ private readonly samplingRate;
162
+ private readonly maxBatchSize;
163
+ private readonly maxQueueSize;
164
+ private readonly flushIntervalMs;
165
+ private readonly flushTimer?;
166
+ private droppedCount;
167
+ private totalDroppedCount;
168
+ private flushing;
169
+ private readonly exporterHealth;
170
+ private readonly queueUtilizationWarnThreshold;
171
+ private readonly queueDroppedWarnThreshold;
172
+ private readonly alertCooldownMs;
173
+ private readonly onSloAlert?;
174
+ private readonly lastSloAlertAt;
175
+ constructor(options: TelemetryRegistryOptions);
176
+ register(exporter: TelemetryExporter): Promise<void>;
177
+ private getOrCreateExporterHealth;
178
+ private markExporterHealthy;
179
+ private markExporterFailure;
180
+ private maybeEmitSloAlert;
181
+ enqueue(envelope: TelemetryEnvelope): void;
182
+ enqueueMetric(input: {
183
+ name: string;
184
+ value: number;
185
+ unit?: string;
186
+ traceId?: string;
187
+ spanId?: string;
188
+ parentSpanId?: string;
189
+ tags?: Record<string, string>;
190
+ attributes?: Record<string, unknown>;
191
+ }): void;
192
+ enqueueLog(input: {
193
+ name: string;
194
+ level: string;
195
+ traceId?: string;
196
+ spanId?: string;
197
+ parentSpanId?: string;
198
+ tags?: Record<string, string>;
199
+ attributes?: Record<string, unknown>;
200
+ error?: TelemetryEnvelope['error'];
201
+ }): void;
202
+ enqueueTrace(input: {
203
+ name: string;
204
+ traceId?: string;
205
+ spanId?: string;
206
+ parentSpanId?: string;
207
+ tags?: Record<string, string>;
208
+ attributes?: Record<string, unknown>;
209
+ }): void;
210
+ private buildDroppedEnvelope;
211
+ private buildQueueDepthEnvelope;
212
+ private buildQueueUtilizationEnvelope;
213
+ private emitBatch;
214
+ private buildStartupProbeEnvelope;
215
+ startupHealthCheck(options?: {
216
+ failLoud?: boolean;
217
+ }): Promise<void>;
218
+ getExporterHealth(): TelemetryExporterHealthStatus[];
219
+ getQueueStats(): TelemetryQueueStats;
220
+ private flushInternal;
221
+ flush(): Promise<void>;
222
+ shutdown(): Promise<void>;
223
+ }
224
+ export declare class TelemetryCanaryOrchestrator {
225
+ private readonly registry;
226
+ private readonly evaluationIntervalMs;
227
+ private readonly minConsecutiveHealthyEvaluations;
228
+ private readonly rollbackConsecutiveFailures;
229
+ private readonly maxQueueUtilization;
230
+ private readonly maxTotalDropped;
231
+ private readonly maxUnhealthyExporters;
232
+ private requiredContractGates;
233
+ private readonly onEvaluate?;
234
+ private readonly onPromote?;
235
+ private readonly onRollback?;
236
+ private readonly contractGates;
237
+ private state;
238
+ private consecutiveHealthy;
239
+ private consecutiveFailures;
240
+ private evaluationTimer?;
241
+ constructor(options: TelemetryCanaryOrchestratorOptions);
242
+ setRequiredContractGates(gates: string[]): void;
243
+ addRequiredContractGate(name: string): void;
244
+ setContractGate(name: string, passed: boolean, reason?: string): void;
245
+ setContractGates(gates: Record<string, boolean | {
246
+ passed: boolean;
247
+ reason?: string;
248
+ }>): void;
249
+ resetToCanary(): void;
250
+ private collectFailures;
251
+ evaluate(): TelemetryCanaryDecision;
252
+ getStatusSnapshot(): TelemetryCanaryStatusSnapshot;
253
+ start(): void;
254
+ stop(): void;
255
+ }
256
+ export declare const createTelemetryAwareMetrics: <T extends Metrics>(baseMetrics: T, registry: TelemetryRegistry) => T;
257
+ export declare function maybeWarnLegacyOtlpEndpoint(endpoint: string | undefined): void;