@rawsql-ts/ztd-cli 0.19.0 → 0.20.2
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 +4 -4
- package/dist/commands/agents.d.ts +2 -0
- package/dist/commands/agents.js +68 -0
- package/dist/commands/agents.js.map +1 -0
- package/dist/commands/checkContract.d.ts +46 -0
- package/dist/commands/checkContract.js +359 -0
- package/dist/commands/checkContract.js.map +1 -0
- package/dist/commands/connectionOptions.d.ts +12 -0
- package/dist/commands/connectionOptions.js +22 -0
- package/dist/commands/connectionOptions.js.map +1 -0
- package/dist/commands/ddl.d.ts +7 -0
- package/dist/commands/ddl.js +145 -0
- package/dist/commands/ddl.js.map +1 -0
- package/dist/commands/describe.d.ts +23 -0
- package/dist/commands/describe.js +399 -0
- package/dist/commands/describe.js.map +1 -0
- package/dist/commands/diff.d.ts +24 -0
- package/dist/commands/diff.js +73 -0
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/genEntities.d.ts +14 -0
- package/dist/commands/genEntities.js +58 -0
- package/dist/commands/genEntities.js.map +1 -0
- package/dist/commands/init.d.ts +104 -0
- package/dist/commands/init.js +1480 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/lint.d.ts +89 -0
- package/dist/commands/lint.js +501 -0
- package/dist/commands/lint.js.map +1 -0
- package/dist/commands/modelGen.d.ts +60 -0
- package/dist/commands/modelGen.js +572 -0
- package/dist/commands/modelGen.js.map +1 -0
- package/dist/commands/options.d.ts +9 -0
- package/dist/commands/options.js +48 -0
- package/dist/commands/options.js.map +1 -0
- package/dist/commands/perf.d.ts +9 -0
- package/dist/commands/perf.js +374 -0
- package/dist/commands/perf.js.map +1 -0
- package/dist/commands/pull.d.ts +21 -0
- package/dist/commands/pull.js +115 -0
- package/dist/commands/pull.js.map +1 -0
- package/dist/commands/query.d.ts +9 -0
- package/dist/commands/query.js +377 -0
- package/dist/commands/query.js.map +1 -0
- package/dist/commands/testEvidence.d.ts +237 -0
- package/dist/commands/testEvidence.js +1220 -0
- package/dist/commands/testEvidence.js.map +1 -0
- package/dist/commands/ztdConfig.d.ts +30 -0
- package/dist/commands/ztdConfig.js +224 -0
- package/dist/commands/ztdConfig.js.map +1 -0
- package/dist/commands/ztdConfigCommand.d.ts +18 -0
- package/dist/commands/ztdConfigCommand.js +268 -0
- package/dist/commands/ztdConfigCommand.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +127 -0
- package/dist/index.js.map +1 -0
- package/dist/perf/benchmark.d.ts +277 -0
- package/dist/perf/benchmark.js +2186 -0
- package/dist/perf/benchmark.js.map +1 -0
- package/dist/perf/sandbox.d.ts +73 -0
- package/dist/perf/sandbox.js +492 -0
- package/dist/perf/sandbox.js.map +1 -0
- package/dist/query/analysis.d.ts +20 -0
- package/dist/query/analysis.js +192 -0
- package/dist/query/analysis.js.map +1 -0
- package/dist/query/analyzeColumnUsage.d.ts +10 -0
- package/dist/query/analyzeColumnUsage.js +451 -0
- package/dist/query/analyzeColumnUsage.js.map +1 -0
- package/dist/query/analyzeTableUsage.d.ts +10 -0
- package/dist/query/analyzeTableUsage.js +318 -0
- package/dist/query/analyzeTableUsage.js.map +1 -0
- package/dist/query/execute.d.ts +40 -0
- package/dist/query/execute.js +784 -0
- package/dist/query/execute.js.map +1 -0
- package/dist/query/format.d.ts +1 -0
- package/dist/query/format.js +9 -0
- package/dist/query/format.js.map +1 -0
- package/dist/query/lint.d.ts +29 -0
- package/dist/query/lint.js +340 -0
- package/dist/query/lint.js.map +1 -0
- package/dist/query/location.d.ts +18 -0
- package/dist/query/location.js +204 -0
- package/dist/query/location.js.map +1 -0
- package/dist/query/patch.d.ts +21 -0
- package/dist/query/patch.js +151 -0
- package/dist/query/patch.js.map +1 -0
- package/dist/query/planner.d.ts +31 -0
- package/dist/query/planner.js +134 -0
- package/dist/query/planner.js.map +1 -0
- package/dist/query/report.d.ts +7 -0
- package/dist/query/report.js +19 -0
- package/dist/query/report.js.map +1 -0
- package/dist/query/scalarFilterAnalysis.d.ts +6 -0
- package/dist/query/scalarFilterAnalysis.js +212 -0
- package/dist/query/scalarFilterAnalysis.js.map +1 -0
- package/dist/query/slice.d.ts +17 -0
- package/dist/query/slice.js +204 -0
- package/dist/query/slice.js.map +1 -0
- package/dist/query/structure.d.ts +24 -0
- package/dist/query/structure.js +135 -0
- package/dist/query/structure.js.map +1 -0
- package/dist/query/targets.d.ts +2 -0
- package/dist/query/targets.js +6 -0
- package/dist/query/targets.js.map +1 -0
- package/dist/query/types.d.ts +97 -0
- package/dist/query/types.js +3 -0
- package/dist/query/types.js.map +1 -0
- package/dist/specs/sql/activeOrders.catalog.d.ts +12 -0
- package/dist/specs/sql/activeOrders.catalog.js +36 -0
- package/dist/specs/sql/activeOrders.catalog.js.map +1 -0
- package/dist/specs/sql/usersList.catalog.d.ts +8 -0
- package/dist/specs/sql/usersList.catalog.js +14 -0
- package/dist/specs/sql/usersList.catalog.js.map +1 -0
- package/dist/specs/sqlCatalogDefinition.d.ts +20 -0
- package/dist/specs/sqlCatalogDefinition.js +10 -0
- package/dist/specs/sqlCatalogDefinition.js.map +1 -0
- package/dist/utils/agentCli.d.ts +23 -0
- package/dist/utils/agentCli.js +84 -0
- package/dist/utils/agentCli.js.map +1 -0
- package/dist/utils/agentSafety.d.ts +4 -0
- package/dist/utils/agentSafety.js +50 -0
- package/dist/utils/agentSafety.js.map +1 -0
- package/dist/utils/agents.d.ts +31 -0
- package/dist/utils/agents.js +362 -0
- package/dist/utils/agents.js.map +1 -0
- package/dist/utils/collectSqlFiles.d.ts +9 -0
- package/dist/utils/collectSqlFiles.js +58 -0
- package/dist/utils/collectSqlFiles.js.map +1 -0
- package/dist/utils/connectionSummary.d.ts +3 -0
- package/dist/utils/connectionSummary.js +29 -0
- package/dist/utils/connectionSummary.js.map +1 -0
- package/dist/utils/dbConnection.d.ts +31 -0
- package/dist/utils/dbConnection.js +151 -0
- package/dist/utils/dbConnection.js.map +1 -0
- package/dist/utils/fs.d.ts +1 -0
- package/dist/utils/fs.js +12 -0
- package/dist/utils/fs.js.map +1 -0
- package/dist/utils/modelGenBinder.d.ts +8 -0
- package/dist/utils/modelGenBinder.js +31 -0
- package/dist/utils/modelGenBinder.js.map +1 -0
- package/dist/utils/modelGenRender.d.ts +29 -0
- package/dist/utils/modelGenRender.js +158 -0
- package/dist/utils/modelGenRender.js.map +1 -0
- package/dist/utils/modelGenScanner.d.ts +24 -0
- package/dist/utils/modelGenScanner.js +196 -0
- package/dist/utils/modelGenScanner.js.map +1 -0
- package/dist/utils/modelProbe.d.ts +14 -0
- package/dist/utils/modelProbe.js +121 -0
- package/dist/utils/modelProbe.js.map +1 -0
- package/dist/utils/normalizePulledSchema.d.ts +12 -0
- package/dist/utils/normalizePulledSchema.js +213 -0
- package/dist/utils/normalizePulledSchema.js.map +1 -0
- package/dist/utils/optionalDependencies.d.ts +43 -0
- package/dist/utils/optionalDependencies.js +134 -0
- package/dist/utils/optionalDependencies.js.map +1 -0
- package/dist/utils/pgDump.d.ts +12 -0
- package/dist/utils/pgDump.js +58 -0
- package/dist/utils/pgDump.js.map +1 -0
- package/dist/utils/queryFingerprint.d.ts +14 -0
- package/dist/utils/queryFingerprint.js +34 -0
- package/dist/utils/queryFingerprint.js.map +1 -0
- package/dist/utils/sqlCatalogDiscovery.d.ts +44 -0
- package/dist/utils/sqlCatalogDiscovery.js +166 -0
- package/dist/utils/sqlCatalogDiscovery.js.map +1 -0
- package/dist/utils/sqlCatalogStatements.d.ts +20 -0
- package/dist/utils/sqlCatalogStatements.js +23 -0
- package/dist/utils/sqlCatalogStatements.js.map +1 -0
- package/dist/utils/sqlLintHelpers.d.ts +18 -0
- package/dist/utils/sqlLintHelpers.js +270 -0
- package/dist/utils/sqlLintHelpers.js.map +1 -0
- package/dist/utils/telemetry.d.ts +71 -0
- package/dist/utils/telemetry.js +597 -0
- package/dist/utils/telemetry.js.map +1 -0
- package/dist/utils/typeMapper.d.ts +4 -0
- package/dist/utils/typeMapper.js +79 -0
- package/dist/utils/typeMapper.js.map +1 -0
- package/dist/utils/ztdProjectConfig.d.ts +41 -0
- package/dist/utils/ztdProjectConfig.js +182 -0
- package/dist/utils/ztdProjectConfig.js.map +1 -0
- package/package.json +19 -20
- package/templates/README.md +1 -1
- package/templates/README.webapi.md +1 -1
- package/templates/src/catalog/runtime/_coercions.local-source.ts +0 -30
- package/templates/src/local/sql-contract.ts +0 -1
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export type TelemetryAttributeValue = string | number | boolean | null;
|
|
2
|
+
export type TelemetryAttributes = Record<string, TelemetryAttributeValue | undefined>;
|
|
3
|
+
export type TelemetryStatus = 'ok' | 'error';
|
|
4
|
+
export type TelemetryExportMode = 'console' | 'debug' | 'file' | 'otlp';
|
|
5
|
+
export declare const TELEMETRY_DECISION_EVENT_SCHEMA: {
|
|
6
|
+
readonly 'command.selected': {
|
|
7
|
+
readonly summary: "A command path was selected and root command telemetry started.";
|
|
8
|
+
readonly allowedAttributes: readonly ["command"];
|
|
9
|
+
};
|
|
10
|
+
readonly 'command.completed': {
|
|
11
|
+
readonly summary: "A command path completed successfully.";
|
|
12
|
+
readonly allowedAttributes: readonly ["command"];
|
|
13
|
+
};
|
|
14
|
+
readonly 'model-gen.probe-mode': {
|
|
15
|
+
readonly summary: "model-gen resolved whether probing should use live PostgreSQL or ZTD fixtures.";
|
|
16
|
+
readonly allowedAttributes: readonly ["probeMode"];
|
|
17
|
+
};
|
|
18
|
+
readonly 'watch.invalid-with-dry-run': {
|
|
19
|
+
readonly summary: "ztd-config rejected an invalid watch plus dry-run option combination.";
|
|
20
|
+
readonly allowedAttributes: readonly [];
|
|
21
|
+
};
|
|
22
|
+
readonly 'command.options.resolved': {
|
|
23
|
+
readonly summary: "ztd-config resolved high-level option state that influences generation flow.";
|
|
24
|
+
readonly allowedAttributes: readonly ["dryRun", "watch", "quiet", "shouldUpdateConfig", "jsonPayload"];
|
|
25
|
+
};
|
|
26
|
+
readonly 'config.updated': {
|
|
27
|
+
readonly summary: "ztd-config persisted ddl-related project configuration changes.";
|
|
28
|
+
readonly allowedAttributes: readonly [];
|
|
29
|
+
};
|
|
30
|
+
readonly 'output.json-envelope': {
|
|
31
|
+
readonly summary: "The command emitted a machine-readable JSON envelope.";
|
|
32
|
+
readonly allowedAttributes: readonly [];
|
|
33
|
+
};
|
|
34
|
+
readonly 'watch.enabled': {
|
|
35
|
+
readonly summary: "ztd-config switched into watch mode after the initial generation.";
|
|
36
|
+
readonly allowedAttributes: readonly [];
|
|
37
|
+
};
|
|
38
|
+
readonly 'output.dry-run-diagnostic': {
|
|
39
|
+
readonly summary: "The command emitted dry-run follow-up guidance instead of writing files.";
|
|
40
|
+
readonly allowedAttributes: readonly [];
|
|
41
|
+
};
|
|
42
|
+
readonly 'output.next-steps-diagnostic': {
|
|
43
|
+
readonly summary: "The command emitted next-step guidance for interactive use.";
|
|
44
|
+
readonly allowedAttributes: readonly [];
|
|
45
|
+
};
|
|
46
|
+
readonly 'output.quiet-suppressed': {
|
|
47
|
+
readonly summary: "The command intentionally suppressed follow-up guidance because quiet mode is active.";
|
|
48
|
+
readonly allowedAttributes: readonly [];
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
export type TelemetryDecisionEventName = keyof typeof TELEMETRY_DECISION_EVENT_SCHEMA;
|
|
52
|
+
export declare function resolveTelemetryEnabled(explicit?: boolean | string | undefined): boolean;
|
|
53
|
+
export declare function resolveTelemetryExportMode(explicit?: TelemetryExportMode | string | undefined): TelemetryExportMode;
|
|
54
|
+
export declare function resolveTelemetryFilePath(explicit?: string | undefined): string;
|
|
55
|
+
export declare function resolveTelemetryOtlpEndpoint(explicit?: string | undefined): string;
|
|
56
|
+
export declare function setTelemetryEnabled(enabled: boolean): void;
|
|
57
|
+
export declare function configureTelemetry(options?: {
|
|
58
|
+
enabled?: boolean | string;
|
|
59
|
+
exportMode?: TelemetryExportMode | string;
|
|
60
|
+
filePath?: string;
|
|
61
|
+
otlpEndpoint?: string;
|
|
62
|
+
}): void;
|
|
63
|
+
export declare function isTelemetryEnabled(): boolean;
|
|
64
|
+
export declare function getTelemetryExportMode(): TelemetryExportMode;
|
|
65
|
+
export declare function flushTelemetry(): Promise<void>;
|
|
66
|
+
export declare function beginCommandSpan(commandName: string, attributes?: TelemetryAttributes): void;
|
|
67
|
+
export declare function finishCommandSpan(status?: TelemetryStatus): void;
|
|
68
|
+
export declare function withSpan<T>(name: string, fn: () => Promise<T> | T, attributes?: TelemetryAttributes): Promise<T>;
|
|
69
|
+
export declare function withSpanSync<T>(name: string, fn: () => T, attributes?: TelemetryAttributes): T;
|
|
70
|
+
export declare function emitDecisionEvent(name: TelemetryDecisionEventName, attributes?: TelemetryAttributes): void;
|
|
71
|
+
export declare function recordException(error: unknown, attributes?: TelemetryAttributes): void;
|
|
@@ -0,0 +1,597 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TELEMETRY_DECISION_EVENT_SCHEMA = void 0;
|
|
4
|
+
exports.resolveTelemetryEnabled = resolveTelemetryEnabled;
|
|
5
|
+
exports.resolveTelemetryExportMode = resolveTelemetryExportMode;
|
|
6
|
+
exports.resolveTelemetryFilePath = resolveTelemetryFilePath;
|
|
7
|
+
exports.resolveTelemetryOtlpEndpoint = resolveTelemetryOtlpEndpoint;
|
|
8
|
+
exports.setTelemetryEnabled = setTelemetryEnabled;
|
|
9
|
+
exports.configureTelemetry = configureTelemetry;
|
|
10
|
+
exports.isTelemetryEnabled = isTelemetryEnabled;
|
|
11
|
+
exports.getTelemetryExportMode = getTelemetryExportMode;
|
|
12
|
+
exports.flushTelemetry = flushTelemetry;
|
|
13
|
+
exports.beginCommandSpan = beginCommandSpan;
|
|
14
|
+
exports.finishCommandSpan = finishCommandSpan;
|
|
15
|
+
exports.withSpan = withSpan;
|
|
16
|
+
exports.withSpanSync = withSpanSync;
|
|
17
|
+
exports.emitDecisionEvent = emitDecisionEvent;
|
|
18
|
+
exports.recordException = recordException;
|
|
19
|
+
const node_fs_1 = require("node:fs");
|
|
20
|
+
const node_path_1 = require("node:path");
|
|
21
|
+
const node_perf_hooks_1 = require("node:perf_hooks");
|
|
22
|
+
const node_crypto_1 = require("node:crypto");
|
|
23
|
+
const TELEMETRY_ENABLED_ENV = 'ZTD_CLI_TELEMETRY';
|
|
24
|
+
const TELEMETRY_EXPORT_ENV = 'ZTD_CLI_TELEMETRY_EXPORT';
|
|
25
|
+
const TELEMETRY_FILE_ENV = 'ZTD_CLI_TELEMETRY_FILE';
|
|
26
|
+
const TELEMETRY_OTLP_ENDPOINT_ENV = 'ZTD_CLI_TELEMETRY_OTLP_ENDPOINT';
|
|
27
|
+
const DEFAULT_SCHEMA_VERSION = 1;
|
|
28
|
+
const DEFAULT_OTLP_HTTP_ENDPOINT = 'http://127.0.0.1:4318/v1/traces';
|
|
29
|
+
const DEFAULT_FILE_EXPORT_PATH = 'tmp/telemetry/ztd-cli.telemetry.jsonl';
|
|
30
|
+
const MAX_ATTRIBUTE_STRING_LENGTH = 160;
|
|
31
|
+
const REDACTED_VALUE = '[REDACTED]';
|
|
32
|
+
const OTLP_STATUS_OK = 1;
|
|
33
|
+
const OTLP_STATUS_ERROR = 2;
|
|
34
|
+
exports.TELEMETRY_DECISION_EVENT_SCHEMA = {
|
|
35
|
+
'command.selected': {
|
|
36
|
+
summary: 'A command path was selected and root command telemetry started.',
|
|
37
|
+
allowedAttributes: ['command'],
|
|
38
|
+
},
|
|
39
|
+
'command.completed': {
|
|
40
|
+
summary: 'A command path completed successfully.',
|
|
41
|
+
allowedAttributes: ['command'],
|
|
42
|
+
},
|
|
43
|
+
'model-gen.probe-mode': {
|
|
44
|
+
summary: 'model-gen resolved whether probing should use live PostgreSQL or ZTD fixtures.',
|
|
45
|
+
allowedAttributes: ['probeMode'],
|
|
46
|
+
},
|
|
47
|
+
'watch.invalid-with-dry-run': {
|
|
48
|
+
summary: 'ztd-config rejected an invalid watch plus dry-run option combination.',
|
|
49
|
+
allowedAttributes: [],
|
|
50
|
+
},
|
|
51
|
+
'command.options.resolved': {
|
|
52
|
+
summary: 'ztd-config resolved high-level option state that influences generation flow.',
|
|
53
|
+
allowedAttributes: ['dryRun', 'watch', 'quiet', 'shouldUpdateConfig', 'jsonPayload'],
|
|
54
|
+
},
|
|
55
|
+
'config.updated': {
|
|
56
|
+
summary: 'ztd-config persisted ddl-related project configuration changes.',
|
|
57
|
+
allowedAttributes: [],
|
|
58
|
+
},
|
|
59
|
+
'output.json-envelope': {
|
|
60
|
+
summary: 'The command emitted a machine-readable JSON envelope.',
|
|
61
|
+
allowedAttributes: [],
|
|
62
|
+
},
|
|
63
|
+
'watch.enabled': {
|
|
64
|
+
summary: 'ztd-config switched into watch mode after the initial generation.',
|
|
65
|
+
allowedAttributes: [],
|
|
66
|
+
},
|
|
67
|
+
'output.dry-run-diagnostic': {
|
|
68
|
+
summary: 'The command emitted dry-run follow-up guidance instead of writing files.',
|
|
69
|
+
allowedAttributes: [],
|
|
70
|
+
},
|
|
71
|
+
'output.next-steps-diagnostic': {
|
|
72
|
+
summary: 'The command emitted next-step guidance for interactive use.',
|
|
73
|
+
allowedAttributes: [],
|
|
74
|
+
},
|
|
75
|
+
'output.quiet-suppressed': {
|
|
76
|
+
summary: 'The command intentionally suppressed follow-up guidance because quiet mode is active.',
|
|
77
|
+
allowedAttributes: [],
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
class NoopTelemetrySpan {
|
|
81
|
+
constructor() {
|
|
82
|
+
this.id = 'noop';
|
|
83
|
+
}
|
|
84
|
+
end() {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
recordException() {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
class NoopTelemetrySink {
|
|
92
|
+
startSpan() {
|
|
93
|
+
return new NoopTelemetrySpan();
|
|
94
|
+
}
|
|
95
|
+
emitDecisionEvent() {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
emitException() {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
async flush() {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
class JsonLinesTelemetrySink {
|
|
106
|
+
constructor(writeLine) {
|
|
107
|
+
this.writeLine = writeLine;
|
|
108
|
+
this.nextSpanId = 1;
|
|
109
|
+
}
|
|
110
|
+
startSpan(name, parentSpanId, attributes) {
|
|
111
|
+
const spanId = `span-${this.nextSpanId++}`;
|
|
112
|
+
const startedAt = node_perf_hooks_1.performance.now();
|
|
113
|
+
this.write({
|
|
114
|
+
kind: 'span-start',
|
|
115
|
+
spanId,
|
|
116
|
+
parentSpanId,
|
|
117
|
+
spanName: name,
|
|
118
|
+
attributes: sanitizeAttributes(attributes),
|
|
119
|
+
});
|
|
120
|
+
return {
|
|
121
|
+
id: spanId,
|
|
122
|
+
end: (status) => {
|
|
123
|
+
this.write({
|
|
124
|
+
kind: 'span-end',
|
|
125
|
+
spanId,
|
|
126
|
+
parentSpanId,
|
|
127
|
+
spanName: name,
|
|
128
|
+
status,
|
|
129
|
+
durationMs: roundDuration(node_perf_hooks_1.performance.now() - startedAt),
|
|
130
|
+
});
|
|
131
|
+
},
|
|
132
|
+
recordException: (error, exceptionAttributes) => {
|
|
133
|
+
this.emitException(error, spanId, exceptionAttributes);
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
emitDecisionEvent(name, spanId, attributes) {
|
|
138
|
+
const schema = exports.TELEMETRY_DECISION_EVENT_SCHEMA[name];
|
|
139
|
+
this.write({
|
|
140
|
+
kind: 'decision',
|
|
141
|
+
eventName: name,
|
|
142
|
+
spanId,
|
|
143
|
+
attributes: sanitizeAttributes(attributes, schema.allowedAttributes),
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
emitException(error, spanId, attributes) {
|
|
147
|
+
this.write({
|
|
148
|
+
kind: 'exception',
|
|
149
|
+
spanId,
|
|
150
|
+
error: normalizeError(error),
|
|
151
|
+
attributes: sanitizeAttributes(attributes),
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
async flush() {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
write(payload) {
|
|
158
|
+
this.writeLine(JSON.stringify(buildTelemetryEnvelope(payload)));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
class DebugTelemetrySink {
|
|
162
|
+
constructor() {
|
|
163
|
+
this.nextSpanId = 1;
|
|
164
|
+
}
|
|
165
|
+
startSpan(name, parentSpanId, attributes) {
|
|
166
|
+
const spanId = `span-${this.nextSpanId++}`;
|
|
167
|
+
const startedAt = node_perf_hooks_1.performance.now();
|
|
168
|
+
this.write('span-start', name, spanId, parentSpanId, sanitizeAttributes(attributes));
|
|
169
|
+
return {
|
|
170
|
+
id: spanId,
|
|
171
|
+
end: (status) => {
|
|
172
|
+
this.write('span-end', name, spanId, parentSpanId, {
|
|
173
|
+
status,
|
|
174
|
+
durationMs: roundDuration(node_perf_hooks_1.performance.now() - startedAt),
|
|
175
|
+
});
|
|
176
|
+
},
|
|
177
|
+
recordException: (error, exceptionAttributes) => {
|
|
178
|
+
this.emitException(error, spanId, exceptionAttributes);
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
emitDecisionEvent(name, spanId, attributes) {
|
|
183
|
+
const schema = exports.TELEMETRY_DECISION_EVENT_SCHEMA[name];
|
|
184
|
+
this.write('decision', name, spanId, undefined, sanitizeAttributes(attributes, schema.allowedAttributes));
|
|
185
|
+
}
|
|
186
|
+
emitException(error, spanId, attributes) {
|
|
187
|
+
this.write('exception', normalizeError(error).message, spanId, undefined, sanitizeAttributes(attributes));
|
|
188
|
+
}
|
|
189
|
+
async flush() {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
write(kind, label, spanId, parentSpanId, data = {}) {
|
|
193
|
+
const summary = JSON.stringify(data);
|
|
194
|
+
const suffix = summary === '{}' ? '' : ` ${summary}`;
|
|
195
|
+
const parent = parentSpanId ? ` parent=${parentSpanId}` : '';
|
|
196
|
+
process.stderr.write(`[telemetry] ${kind} ${label} span=${spanId !== null && spanId !== void 0 ? spanId : 'none'}${parent}${suffix}\n`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
class OtlpHttpTelemetrySink {
|
|
200
|
+
constructor(endpoint) {
|
|
201
|
+
this.endpoint = endpoint;
|
|
202
|
+
this.activeSpans = new Map();
|
|
203
|
+
this.pendingExports = new Set();
|
|
204
|
+
}
|
|
205
|
+
startSpan(name, parentSpanId, attributes) {
|
|
206
|
+
var _a;
|
|
207
|
+
const parentSpan = parentSpanId ? this.activeSpans.get(parentSpanId) : undefined;
|
|
208
|
+
const spanId = (0, node_crypto_1.randomBytes)(8).toString('hex');
|
|
209
|
+
const spanRecord = {
|
|
210
|
+
traceId: (_a = parentSpan === null || parentSpan === void 0 ? void 0 : parentSpan.traceId) !== null && _a !== void 0 ? _a : (0, node_crypto_1.randomBytes)(16).toString('hex'),
|
|
211
|
+
spanId,
|
|
212
|
+
parentSpanId,
|
|
213
|
+
name,
|
|
214
|
+
startTimeUnixNano: currentTimeUnixNano(),
|
|
215
|
+
attributes: toOtlpAttributes(sanitizeAttributes(attributes)),
|
|
216
|
+
events: [],
|
|
217
|
+
};
|
|
218
|
+
this.activeSpans.set(spanId, spanRecord);
|
|
219
|
+
return {
|
|
220
|
+
id: spanId,
|
|
221
|
+
end: (status) => {
|
|
222
|
+
this.endSpan(spanId, status);
|
|
223
|
+
},
|
|
224
|
+
recordException: (error, exceptionAttributes) => {
|
|
225
|
+
this.emitException(error, spanId, exceptionAttributes);
|
|
226
|
+
},
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
emitDecisionEvent(name, spanId, attributes) {
|
|
230
|
+
const spanRecord = spanId ? this.activeSpans.get(spanId) : undefined;
|
|
231
|
+
if (!spanRecord) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const schema = exports.TELEMETRY_DECISION_EVENT_SCHEMA[name];
|
|
235
|
+
spanRecord.events.push({
|
|
236
|
+
timeUnixNano: currentTimeUnixNano(),
|
|
237
|
+
name,
|
|
238
|
+
attributes: toOtlpAttributes(sanitizeAttributes(attributes, schema.allowedAttributes)),
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
emitException(error, spanId, attributes) {
|
|
242
|
+
var _a, _b;
|
|
243
|
+
const spanRecord = spanId ? this.activeSpans.get(spanId) : undefined;
|
|
244
|
+
if (!spanRecord) {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
const normalized = normalizeError(error);
|
|
248
|
+
spanRecord.events.push({
|
|
249
|
+
timeUnixNano: currentTimeUnixNano(),
|
|
250
|
+
name: 'exception',
|
|
251
|
+
attributes: [
|
|
252
|
+
...toOtlpAttributes({
|
|
253
|
+
'exception.type': String((_a = normalized.name) !== null && _a !== void 0 ? _a : 'UnknownError'),
|
|
254
|
+
'exception.message': String((_b = normalized.message) !== null && _b !== void 0 ? _b : ''),
|
|
255
|
+
}),
|
|
256
|
+
...toOtlpAttributes(sanitizeAttributes(attributes)),
|
|
257
|
+
],
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
async flush() {
|
|
261
|
+
await Promise.allSettled([...this.pendingExports]);
|
|
262
|
+
}
|
|
263
|
+
endSpan(spanId, status) {
|
|
264
|
+
const spanRecord = this.activeSpans.get(spanId);
|
|
265
|
+
if (!spanRecord) {
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
this.activeSpans.delete(spanId);
|
|
269
|
+
const payload = {
|
|
270
|
+
resourceSpans: [
|
|
271
|
+
{
|
|
272
|
+
resource: {
|
|
273
|
+
attributes: toOtlpAttributes({
|
|
274
|
+
'service.name': 'ztd-cli',
|
|
275
|
+
'telemetry.export.mode': 'otlp',
|
|
276
|
+
}),
|
|
277
|
+
},
|
|
278
|
+
scopeSpans: [
|
|
279
|
+
{
|
|
280
|
+
scope: {
|
|
281
|
+
name: '@rawsql-ts/ztd-cli',
|
|
282
|
+
},
|
|
283
|
+
spans: [
|
|
284
|
+
{
|
|
285
|
+
traceId: spanRecord.traceId,
|
|
286
|
+
spanId: spanRecord.spanId,
|
|
287
|
+
parentSpanId: spanRecord.parentSpanId,
|
|
288
|
+
name: spanRecord.name,
|
|
289
|
+
kind: 1,
|
|
290
|
+
startTimeUnixNano: spanRecord.startTimeUnixNano,
|
|
291
|
+
endTimeUnixNano: currentTimeUnixNano(),
|
|
292
|
+
attributes: spanRecord.attributes,
|
|
293
|
+
events: spanRecord.events,
|
|
294
|
+
status: {
|
|
295
|
+
code: status === 'ok' ? OTLP_STATUS_OK : OTLP_STATUS_ERROR,
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
],
|
|
299
|
+
},
|
|
300
|
+
],
|
|
301
|
+
},
|
|
302
|
+
],
|
|
303
|
+
};
|
|
304
|
+
const exportPromise = fetch(this.endpoint, {
|
|
305
|
+
method: 'POST',
|
|
306
|
+
headers: {
|
|
307
|
+
'content-type': 'application/json',
|
|
308
|
+
},
|
|
309
|
+
body: JSON.stringify(payload),
|
|
310
|
+
})
|
|
311
|
+
.then(() => undefined)
|
|
312
|
+
.catch(() => undefined)
|
|
313
|
+
.finally(() => {
|
|
314
|
+
this.pendingExports.delete(exportPromise);
|
|
315
|
+
});
|
|
316
|
+
this.pendingExports.add(exportPromise);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
const NOOP_SINK = new NoopTelemetrySink();
|
|
320
|
+
let telemetrySink = NOOP_SINK;
|
|
321
|
+
let telemetryEnabled = false;
|
|
322
|
+
let telemetryExportMode = 'console';
|
|
323
|
+
const spanStack = [];
|
|
324
|
+
function resolveTelemetryEnabled(explicit) {
|
|
325
|
+
if (typeof explicit === 'boolean') {
|
|
326
|
+
return explicit;
|
|
327
|
+
}
|
|
328
|
+
if (typeof explicit === 'string') {
|
|
329
|
+
return isTruthy(explicit);
|
|
330
|
+
}
|
|
331
|
+
return isTruthy(process.env[TELEMETRY_ENABLED_ENV]);
|
|
332
|
+
}
|
|
333
|
+
function resolveTelemetryExportMode(explicit) {
|
|
334
|
+
return normalizeTelemetryExportMode(explicit !== null && explicit !== void 0 ? explicit : process.env[TELEMETRY_EXPORT_ENV]);
|
|
335
|
+
}
|
|
336
|
+
function resolveTelemetryFilePath(explicit) {
|
|
337
|
+
var _a;
|
|
338
|
+
return (_a = explicit !== null && explicit !== void 0 ? explicit : process.env[TELEMETRY_FILE_ENV]) !== null && _a !== void 0 ? _a : DEFAULT_FILE_EXPORT_PATH;
|
|
339
|
+
}
|
|
340
|
+
function resolveTelemetryOtlpEndpoint(explicit) {
|
|
341
|
+
var _a;
|
|
342
|
+
return (_a = explicit !== null && explicit !== void 0 ? explicit : process.env[TELEMETRY_OTLP_ENDPOINT_ENV]) !== null && _a !== void 0 ? _a : DEFAULT_OTLP_HTTP_ENDPOINT;
|
|
343
|
+
}
|
|
344
|
+
function setTelemetryEnabled(enabled) {
|
|
345
|
+
process.env[TELEMETRY_ENABLED_ENV] = enabled ? '1' : '0';
|
|
346
|
+
}
|
|
347
|
+
function configureTelemetry(options = {}) {
|
|
348
|
+
telemetryEnabled = resolveTelemetryEnabled(options.enabled);
|
|
349
|
+
telemetryExportMode = resolveTelemetryExportMode(options.exportMode);
|
|
350
|
+
if (!telemetryEnabled) {
|
|
351
|
+
telemetrySink = NOOP_SINK;
|
|
352
|
+
spanStack.length = 0;
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
telemetrySink = createTelemetrySink({
|
|
356
|
+
exportMode: telemetryExportMode,
|
|
357
|
+
filePath: resolveTelemetryFilePath(options.filePath),
|
|
358
|
+
otlpEndpoint: resolveTelemetryOtlpEndpoint(options.otlpEndpoint),
|
|
359
|
+
});
|
|
360
|
+
spanStack.length = 0;
|
|
361
|
+
}
|
|
362
|
+
function isTelemetryEnabled() {
|
|
363
|
+
return telemetryEnabled;
|
|
364
|
+
}
|
|
365
|
+
function getTelemetryExportMode() {
|
|
366
|
+
return telemetryExportMode;
|
|
367
|
+
}
|
|
368
|
+
async function flushTelemetry() {
|
|
369
|
+
await telemetrySink.flush();
|
|
370
|
+
}
|
|
371
|
+
function beginCommandSpan(commandName, attributes = {}) {
|
|
372
|
+
if (!telemetryEnabled) {
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
spanStack.length = 0;
|
|
376
|
+
const rootSpan = telemetrySink.startSpan(commandName, undefined, {
|
|
377
|
+
...attributes,
|
|
378
|
+
scope: 'command-root',
|
|
379
|
+
});
|
|
380
|
+
spanStack.push(rootSpan);
|
|
381
|
+
}
|
|
382
|
+
function finishCommandSpan(status = 'ok') {
|
|
383
|
+
var _a, _b;
|
|
384
|
+
if (!telemetryEnabled) {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
while (spanStack.length > 1) {
|
|
388
|
+
(_a = spanStack.pop()) === null || _a === void 0 ? void 0 : _a.end(status);
|
|
389
|
+
}
|
|
390
|
+
(_b = spanStack.pop()) === null || _b === void 0 ? void 0 : _b.end(status);
|
|
391
|
+
}
|
|
392
|
+
async function withSpan(name, fn, attributes = {}) {
|
|
393
|
+
var _a;
|
|
394
|
+
if (!telemetryEnabled) {
|
|
395
|
+
return await fn();
|
|
396
|
+
}
|
|
397
|
+
const parentSpanId = (_a = getCurrentSpan()) === null || _a === void 0 ? void 0 : _a.id;
|
|
398
|
+
const span = telemetrySink.startSpan(name, parentSpanId, attributes);
|
|
399
|
+
spanStack.push(span);
|
|
400
|
+
try {
|
|
401
|
+
const result = await fn();
|
|
402
|
+
span.end('ok');
|
|
403
|
+
return result;
|
|
404
|
+
}
|
|
405
|
+
catch (error) {
|
|
406
|
+
span.recordException(error);
|
|
407
|
+
span.end('error');
|
|
408
|
+
throw error;
|
|
409
|
+
}
|
|
410
|
+
finally {
|
|
411
|
+
removeSpan(span.id);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
function withSpanSync(name, fn, attributes = {}) {
|
|
415
|
+
var _a;
|
|
416
|
+
if (!telemetryEnabled) {
|
|
417
|
+
return fn();
|
|
418
|
+
}
|
|
419
|
+
const parentSpanId = (_a = getCurrentSpan()) === null || _a === void 0 ? void 0 : _a.id;
|
|
420
|
+
const span = telemetrySink.startSpan(name, parentSpanId, attributes);
|
|
421
|
+
spanStack.push(span);
|
|
422
|
+
try {
|
|
423
|
+
const result = fn();
|
|
424
|
+
span.end('ok');
|
|
425
|
+
return result;
|
|
426
|
+
}
|
|
427
|
+
catch (error) {
|
|
428
|
+
span.recordException(error);
|
|
429
|
+
span.end('error');
|
|
430
|
+
throw error;
|
|
431
|
+
}
|
|
432
|
+
finally {
|
|
433
|
+
removeSpan(span.id);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
function emitDecisionEvent(name, attributes = {}) {
|
|
437
|
+
var _a;
|
|
438
|
+
if (!telemetryEnabled) {
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
telemetrySink.emitDecisionEvent(name, (_a = getCurrentSpan()) === null || _a === void 0 ? void 0 : _a.id, attributes);
|
|
442
|
+
}
|
|
443
|
+
function recordException(error, attributes = {}) {
|
|
444
|
+
if (!telemetryEnabled) {
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
const currentSpan = getCurrentSpan();
|
|
448
|
+
if (currentSpan) {
|
|
449
|
+
currentSpan.recordException(error, attributes);
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
telemetrySink.emitException(error, undefined, attributes);
|
|
453
|
+
}
|
|
454
|
+
function createTelemetrySink(options) {
|
|
455
|
+
switch (options.exportMode) {
|
|
456
|
+
case 'console':
|
|
457
|
+
return new JsonLinesTelemetrySink((line) => {
|
|
458
|
+
process.stderr.write(`${line}\n`);
|
|
459
|
+
});
|
|
460
|
+
case 'debug':
|
|
461
|
+
return new DebugTelemetrySink();
|
|
462
|
+
case 'file': {
|
|
463
|
+
const absoluteFile = (0, node_path_1.resolve)(process.cwd(), options.filePath);
|
|
464
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(absoluteFile), { recursive: true });
|
|
465
|
+
return new JsonLinesTelemetrySink((line) => {
|
|
466
|
+
(0, node_fs_1.appendFileSync)(absoluteFile, `${line}\n`, 'utf8');
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
case 'otlp':
|
|
470
|
+
return new OtlpHttpTelemetrySink(options.otlpEndpoint);
|
|
471
|
+
default:
|
|
472
|
+
return NOOP_SINK;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
function buildTelemetryEnvelope(payload) {
|
|
476
|
+
return {
|
|
477
|
+
schemaVersion: DEFAULT_SCHEMA_VERSION,
|
|
478
|
+
type: 'telemetry',
|
|
479
|
+
timestamp: new Date().toISOString(),
|
|
480
|
+
...payload,
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
function getCurrentSpan() {
|
|
484
|
+
return spanStack[spanStack.length - 1];
|
|
485
|
+
}
|
|
486
|
+
function removeSpan(spanId) {
|
|
487
|
+
const index = spanStack.findIndex((span) => span.id === spanId);
|
|
488
|
+
if (index >= 0) {
|
|
489
|
+
spanStack.splice(index, 1);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
function isTruthy(value) {
|
|
493
|
+
if (!value) {
|
|
494
|
+
return false;
|
|
495
|
+
}
|
|
496
|
+
const normalized = value.trim().toLowerCase();
|
|
497
|
+
return normalized === '1' || normalized === 'true' || normalized === 'yes' || normalized === 'on';
|
|
498
|
+
}
|
|
499
|
+
function normalizeTelemetryExportMode(value) {
|
|
500
|
+
switch ((value !== null && value !== void 0 ? value : 'console').trim().toLowerCase()) {
|
|
501
|
+
case 'console':
|
|
502
|
+
case 'debug':
|
|
503
|
+
case 'file':
|
|
504
|
+
case 'otlp':
|
|
505
|
+
return (value !== null && value !== void 0 ? value : 'console').trim().toLowerCase();
|
|
506
|
+
default:
|
|
507
|
+
return 'console';
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
function sanitizeAttributes(attributes = {}, allowedKeys) {
|
|
511
|
+
const sanitized = {};
|
|
512
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
513
|
+
if (value === undefined) {
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
516
|
+
if (allowedKeys && !allowedKeys.includes(key)) {
|
|
517
|
+
continue;
|
|
518
|
+
}
|
|
519
|
+
sanitized[key] = sanitizeAttributeValue(key, value);
|
|
520
|
+
}
|
|
521
|
+
return sanitized;
|
|
522
|
+
}
|
|
523
|
+
function normalizeError(error) {
|
|
524
|
+
if (error instanceof Error) {
|
|
525
|
+
return {
|
|
526
|
+
name: error.name,
|
|
527
|
+
message: sanitizeStringValue('message', error.message),
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
return {
|
|
531
|
+
name: 'UnknownError',
|
|
532
|
+
message: sanitizeStringValue('message', String(error)),
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
function sanitizeAttributeValue(key, value) {
|
|
536
|
+
if (value === null || typeof value === 'number' || typeof value === 'boolean') {
|
|
537
|
+
return isSensitiveAttributeKey(key) ? REDACTED_VALUE : value;
|
|
538
|
+
}
|
|
539
|
+
return sanitizeStringValue(key, value);
|
|
540
|
+
}
|
|
541
|
+
// Telemetry safety policy intentionally distinguishes secrets from bulky but benign data. DSN detection covers both URL-style and libpq-style forms, while oversized or multiline values are truncated instead of redacted so exporters keep the boundary without leaking payload bodies.
|
|
542
|
+
function sanitizeStringValue(key, value) {
|
|
543
|
+
if (isSensitiveAttributeKey(key) || looksSensitive(value)) {
|
|
544
|
+
return REDACTED_VALUE;
|
|
545
|
+
}
|
|
546
|
+
if (value.includes('\n') || value.length > MAX_ATTRIBUTE_STRING_LENGTH) {
|
|
547
|
+
return `[TRUNCATED:${value.length}]`;
|
|
548
|
+
}
|
|
549
|
+
return value;
|
|
550
|
+
}
|
|
551
|
+
function isSensitiveAttributeKey(key) {
|
|
552
|
+
return [
|
|
553
|
+
/(?:^|\.)(?:sql|sqlText|query|queryText|statement)$/iu,
|
|
554
|
+
/(?:dsn|databaseUrl|connectionUrl|url|uri)$/iu,
|
|
555
|
+
/(?:password|secret|credential|authorization|api(?:_|-)?key|access(?:_|-)?key|(?:auth|bearer|access|refresh|session)?token)$/iu,
|
|
556
|
+
/(?:bindValue|bindValues|paramValue|paramValues)$/iu,
|
|
557
|
+
/(?:stack|dump)$/iu,
|
|
558
|
+
].some((pattern) => pattern.test(key));
|
|
559
|
+
}
|
|
560
|
+
function looksSensitive(value) {
|
|
561
|
+
const normalized = value.trim();
|
|
562
|
+
if (normalized.length === 0) {
|
|
563
|
+
return false;
|
|
564
|
+
}
|
|
565
|
+
return [
|
|
566
|
+
/\b(?:postgres(?:ql)?|mysql|mssql|redis):\/\/\S+/iu,
|
|
567
|
+
/\b(?:host|hostaddr|port|dbname|db|user|password|passfile|service|sslmode|sslcert|sslkey|sslrootcert|target_session_attrs)\s*=\s*(?:"[^"]*"|'[^']*'|[^\s]+)/iu,
|
|
568
|
+
/\b(?:password|pwd|secret|token|api(?:key|_key)|access(?:key|_key)|authorization)\s*[=:]\s*\S+/iu,
|
|
569
|
+
/\b(?:bearer|basic)\s+[A-Za-z0-9._~+\/=:-]{8,}\b/iu,
|
|
570
|
+
/\b(?:select|insert|update|delete|create|alter|drop|with)\b[\s\S]{0,120}\b(?:from|into|table|view|where|values|set)\b/iu,
|
|
571
|
+
].some((pattern) => pattern.test(normalized));
|
|
572
|
+
}
|
|
573
|
+
function toOtlpAttributes(attributes) {
|
|
574
|
+
return Object.entries(attributes).map(([key, value]) => ({
|
|
575
|
+
key,
|
|
576
|
+
value: toOtlpAnyValue(value),
|
|
577
|
+
}));
|
|
578
|
+
}
|
|
579
|
+
function toOtlpAnyValue(value) {
|
|
580
|
+
if (value === null) {
|
|
581
|
+
return { stringValue: 'null' };
|
|
582
|
+
}
|
|
583
|
+
if (typeof value === 'boolean') {
|
|
584
|
+
return { boolValue: value };
|
|
585
|
+
}
|
|
586
|
+
if (typeof value === 'number') {
|
|
587
|
+
return Number.isInteger(value) ? { intValue: value } : { doubleValue: value };
|
|
588
|
+
}
|
|
589
|
+
return { stringValue: value };
|
|
590
|
+
}
|
|
591
|
+
function currentTimeUnixNano() {
|
|
592
|
+
return (BigInt(Date.now()) * BigInt(1000000)).toString();
|
|
593
|
+
}
|
|
594
|
+
function roundDuration(value) {
|
|
595
|
+
return Math.round(value * 1000) / 1000;
|
|
596
|
+
}
|
|
597
|
+
//# sourceMappingURL=telemetry.js.map
|