import * as _sentry_node from '@sentry/node'; import { DeployContextForReport } from './memory-report.js'; import { VersionFreshness } from './version-check.js'; import 'node:v8'; import 'node:stream'; /** * Registry of instrumented code paths for dead-branch coverage monitoring. * * Each ID is emitted as a "code.path." span attribute the first time a deploy * exercises that branch. The nightly check-code-path-coverage.py queries * Sentry for zero-hit paths over a rolling 30-day window and files a GitHub * issue if any are found. * * Rule: never remove an ID without also removing the corresponding branch. * Add a new ID whenever you add a conditional branch worth monitoring. * * When adding a new ID here, ALSO add it to CODE_PATHS in * tools/check-code-path-coverage.py with an `introduced` date of today * (YYYY-MM-DD UTC). The grace window prevents the brand-new path from * triggering a false "0 hits over 30d" alarm before any consumer has * had time to upgrade and exercise the branch. */ declare const CODE_PATHS: { readonly DOTNS_AUTO_MAPPING: "dotns.auto-mapping"; readonly DOTNS_MANUAL_MAPPING: "dotns.manual-mapping"; }; type CodePath = typeof CODE_PATHS[keyof typeof CODE_PATHS]; declare const VERSION: string; type SentryModule = typeof _sentry_node | null; declare function extractRepoSlug(url: string): string; /** * Resolve the `owner/name` slug for the package's own GitHub issue tracker. * Accepts the raw `repository` field from package.json (string or `{url}` object) * and returns a normalized `owner/name` slug. Falls back to the upstream * literal if the field is absent or does not resolve to a valid `owner/name` slug. */ declare function resolveIssueRepoSlug(repository: unknown): string; interface InternalContextSignals { githubRepository?: string; runnerName?: string; gitRemote?: string; hostApp?: string; } declare function isInternalContextFromSignals(signals: InternalContextSignals): boolean; declare function isInternalContext(): boolean; /** * Pure decision function for whether telemetry is disabled. * * Precedence (highest to lowest): * 1. optOut (BULLETIN_DEPLOY_TELEMETRY=0/off) → always disabled * 2. optIn (BULLETIN_DEPLOY_TELEMETRY=1) → enabled, overrides DO_NOT_TRACK * 3. doNotTrack (DO_NOT_TRACK=1) → disabled * 4. internalContext (Parity CI / internal org) → enabled * 5. default → disabled (telemetry is off for external users) */ declare function isTelemetryDisabled(s: { optIn: boolean; optOut: boolean; doNotTrack: boolean; internalContext: boolean; }): boolean; declare function scrubPaths(msg: string): string; declare function truncateAddress(ss58: string | undefined): string | undefined; declare function sanitizeBranch(name: string | undefined): string | undefined; declare function sanitizeRepo(slug: string | undefined): string | undefined; declare function setRunStateActive(v: boolean): void; declare function markRelaunchOomHintShown(): void; declare function setVersionFreshness(status: VersionFreshness): void; declare function closeTelemetry(timeoutMs: number): Promise; declare function initTelemetry(): void; declare function resolveRepo(domain: string): string; declare function resolveRunner(): string; declare function resolveRunnerType(): string; declare function getDeployAttributes(domain: string): Record; type DeployErrorCategory = 'user' | 'environment' | 'internal' | 'unknown'; declare function isExpectedError(msg: string, variant?: string): boolean; declare function classifyDeployError(msg: string, variant?: string): DeployErrorCategory; declare function classifySadReason(message: string): string; declare function computeDeployOutcome(errorCategory: DeployErrorCategory | null, isSad: boolean, sadReason: string): string; type DeployErrorKind = 'contract-revert' | 'chain-timeout' | 'nonce-stale' | 'connection' | 'naming.pop_required' | 'naming.nostatus_required' | 'naming.contract_unavailable' | 'naming.contract_function_removed' | 'dotns.abi_decode_empty' | 'naming.already_owned' | 'naming.governance_reserved' | 'naming.short_names_closed' | 'naming.subdomain_orphan' | 'naming.tld_mismatch' | 'funding.insufficient_balance' | 'verify.contenthash_mismatch' | 'verify.dagpb_not_finalised' | 'network.recovery_exhausted' | 'account.mapping_pending' | 'chain.api_timeout' | 'chain.tx_timeout' | 'chain.tx_silent' | 'chain.extrinsic_expired' | 'chain.quota_exhausted' | 'chain.bad_proof' | 'signer.message_too_large' | 'storage.rejected' | 'user.aborted' | 'signer.phone_confirmation_unavailable' | 'tool.invariant' | 'unknown'; /** * Every kind that some rule below can produce. Exported so the test suite can * assert the fall-through guard actually covers all of them — without that, * a rule added without a fixture makes the guard silently non-exhaustive * instead of failing loudly, which defeats its purpose (#1345). */ declare function classifiableErrorKinds(): Set; declare function classifyErrorKind(msg: string, variant?: string): DeployErrorKind; declare function sanitizeErrorMessage(msg: string): string; /** * Classify an error message's *shape* (length, presence of certain patterns) * without excerpting content. The result is a comma-joined list of tags; * future analysis of scrubbed events will use this to identify which content * shape triggered Sentry's PII scrubber, so we can build a real sanitiser. */ declare function analyseErrorPattern(msg: string): string; declare function withSpan(op: string, description: string, attributes: Record, fn: () => T | Promise): Promise; declare function sampleMemory(stage: string): void; declare function withDeploySpan(domain: string, fn: () => T | Promise): Promise; declare function withManifestSpan(domain: string, fn: () => T | Promise): Promise; declare function setDeployReportContext(patch: Partial & { outputDir?: string; }): void; declare function setDeployAttribute(key: string, value: string | number | boolean): void; declare function setDeployError(msg: string, variant?: string): void; declare function __setDeployRootSpanForTest(span: any | null): void; declare function __setSentryForTest(stub: any): SentryModule; declare function getCurrentSentryTraceId(): string | undefined; declare function setDeploySentryTag(key: string, value: string): void; /** * Mark a code path as exercised in the current deploy span. * Used for dead-branch coverage monitoring — see src/code-paths.ts. * * Design: each path gets its own boolean attribute `code.path.` = "true" * rather than a single `code.path` attribute. This avoids the overwrite problem * — a single deploy span that exercises multiple branches would otherwise only * record the last one. Boolean-per-path lets Sentry query `has:code.path.pool.auth.v2` * independently for each path. * * Note: @sentry/node user-defined attributes come back as string-typed in EAP * regardless of value type. Store as the string "true" so queries using * `count_if(code.path.pool.auth.v2, "true")` or `has:code.path.pool.auth.v2` * both work correctly. * * No-ops gracefully if called outside a deploy span (setDeployAttribute guards * on deployRootSpan — see setDeployAttribute implementation above). */ declare function markCodePath(id: CodePath): void; /** * Emit a span for an interval that has ALREADY elapsed, with explicit start and * end timestamps, parented to the current deploy root span. * * Why retroactive rather than an open span held across the interval: the * emitter is a background block subscription, not the active call stack, so * `Sentry.startSpan` would attach to whatever scope happens to be current — * the same scope-stack unreliability documented on `deployRootSpan` above. * Recording start/end ourselves and passing them to `startInactiveSpan` makes * parentage explicit and means a dropped subscription can never leave a span * open. * * The resulting `span.duration` IS the measurement. That matters: user-defined * attributes from @sentry/node come back string-typed in EAP, so `avg()`/`p95()` * only work on built-in numeric columns. Callers wanting an aggregatable metric * must express it as an elapsed interval, not an attribute. * * No-ops when there is no active deploy root span (telemetry disabled, opted * out, or called outside a deploy) — that single guard is what keeps * background sampling off for users who opted out. */ declare function emitIntervalSpan(op: string, name: string, startMs: number, endMs: number, attributes: Record): void; declare function captureWarning(message: string, context?: Record): void; declare function flush(): Promise; export { type DeployErrorCategory, type DeployErrorKind, type InternalContextSignals, VERSION, __setDeployRootSpanForTest, __setSentryForTest, analyseErrorPattern, captureWarning, classifiableErrorKinds, classifyDeployError, classifyErrorKind, classifySadReason, closeTelemetry, computeDeployOutcome, emitIntervalSpan, extractRepoSlug, flush, getCurrentSentryTraceId, getDeployAttributes, initTelemetry, isExpectedError, isInternalContext, isInternalContextFromSignals, isTelemetryDisabled, markCodePath, markRelaunchOomHintShown, resolveIssueRepoSlug, resolveRepo, resolveRunner, resolveRunnerType, sampleMemory, sanitizeBranch, sanitizeErrorMessage, sanitizeRepo, scrubPaths, setDeployAttribute, setDeployError, setDeployReportContext, setDeploySentryTag, setRunStateActive, setVersionFreshness, truncateAddress, withDeploySpan, withManifestSpan, withSpan };