diff --git a/bundler-tests/browser/webpack-4/webpack.config.mjs b/bundler-tests/browser/webpack-4/webpack.config.mjs index 05f3a82b490..b9e8adf90cd 100644 --- a/bundler-tests/browser/webpack-4/webpack.config.mjs +++ b/bundler-tests/browser/webpack-4/webpack.config.mjs @@ -14,17 +14,9 @@ export default { }, resolve: { alias: { - // Webpack 4 doesn't support package.json exports field, so we need to manually map subpath exports + // Webpack 4 doesn't support package.json exports field, so we need to manually map the browser-http subpath '@opentelemetry/otlp-exporter-base/browser-http': '@opentelemetry/otlp-exporter-base/build/esm/index-browser-http.js', - // @bufbuild/protobuf subpath exports (used by @opentelemetry/otlp-transformer) - // These paths are compatible with @bufbuild/protobuf v2.x - '@bufbuild/protobuf/codegenv1': - '@bufbuild/protobuf/dist/esm/codegenv1/index.js', - '@bufbuild/protobuf/wkt': '@bufbuild/protobuf/dist/esm/wkt/index.js', - '@bufbuild/protobuf/wire': '@bufbuild/protobuf/dist/esm/wire/index.js', - '@bufbuild/protobuf/reflect': - '@bufbuild/protobuf/dist/esm/reflect/index.js', }, }, module: { diff --git a/experimental/CHANGELOG.md b/experimental/CHANGELOG.md index 8664fa955e9..bb0ebabcd7b 100644 --- a/experimental/CHANGELOG.md +++ b/experimental/CHANGELOG.md @@ -46,8 +46,6 @@ For notes on migrating to 2.x / 0.200.x see [the upgrade guide](doc/upgrade-to-2 * test(instrumentation-http): replace uses of deprecated abort() [#6149](https://github.com/open-telemetry/opentelemetry-js/pull/6149) @cjihrig * refactor(configuration): simplify boolean check [#6158](https://github.com/open-telemetry/opentelemetry-js/pull/6158) @cjihrig * chore: disallow constructor parameter property syntax [#6187](https://github.com/open-telemetry/opentelemetry-js/pull/6187) @legendecas -* refactor(otlp-transformer): migrate from protobufjs to protobuf-es [#6179](https://github.com/open-telemetry/opentelemetry-js/pull/6179) @overbalance -* chore(otlp-transformer, sampler-composite): clean up tsconfig after protobuf-es migration [#6192](https://github.com/open-telemetry/opentelemetry-js/pull/6192) @overbalance * chore(instrumentation-grpc): use local protobuf-ts plugin instead of buf.build remote [#6202](https://github.com/open-telemetry/opentelemetry-js/pull/6202) @overbalance * test(otlp-transformer): add benchmark for ProtobufTraceSerializer [#6226](https://github.com/open-telemetry/opentelemetry-js/pull/6226) @overbalance diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/package.json b/experimental/packages/opentelemetry-instrumentation-grpc/package.json index 363c594e9da..fd7b858b25d 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/package.json +++ b/experimental/packages/opentelemetry-instrumentation-grpc/package.json @@ -61,6 +61,7 @@ "@types/mocha": "10.0.10", "@types/node": "18.6.5", "@types/sinon": "17.0.4", + "@typescript/vfs": "1.6.2", "mocha": "11.7.5", "nyc": "17.1.0", "sinon": "18.0.1", diff --git a/experimental/packages/otlp-transformer/buf.gen.yaml b/experimental/packages/otlp-transformer/buf.gen.yaml deleted file mode 100644 index 2dfb1e5164e..00000000000 --- a/experimental/packages/otlp-transformer/buf.gen.yaml +++ /dev/null @@ -1,8 +0,0 @@ -version: v2 -plugins: - - local: protoc-gen-es - out: src/generated - opt: - - target=ts -inputs: - - directory: protos diff --git a/experimental/packages/otlp-transformer/buf.yaml b/experimental/packages/otlp-transformer/buf.yaml deleted file mode 100644 index 04309e4f879..00000000000 --- a/experimental/packages/otlp-transformer/buf.yaml +++ /dev/null @@ -1,3 +0,0 @@ -version: v2 -modules: - - path: protos diff --git a/experimental/packages/otlp-transformer/package.json b/experimental/packages/otlp-transformer/package.json index ac728fa96ef..5ca4e145e9c 100644 --- a/experimental/packages/otlp-transformer/package.json +++ b/experimental/packages/otlp-transformer/package.json @@ -17,7 +17,9 @@ "compile": "tsc --build tsconfig.json tsconfig.esm.json tsconfig.esnext.json", "clean": "tsc --build --clean tsconfig.json tsconfig.esm.json tsconfig.esnext.json", "protos": "npm run submodule && npm run protos:generate", - "protos:generate": "buf generate", + "protos:generate:js": "pbjs -t static-module -p ./protos -w commonjs --null-defaults -o ./src/generated/root.js ./protos/opentelemetry/proto/common/v1/common.proto ./protos/opentelemetry/proto/resource/v1/resource.proto ./protos/opentelemetry/proto/trace/v1/trace.proto ./protos/opentelemetry/proto/collector/trace/v1/trace_service.proto ./protos/opentelemetry/proto/metrics/v1/metrics.proto ./protos/opentelemetry/proto/collector/metrics/v1/metrics_service.proto ./protos/opentelemetry/proto/logs/v1/logs.proto ./protos/opentelemetry/proto/collector/logs/v1/logs_service.proto", + "protos:generate:ts": "pbts -o ./src/generated/root.d.ts ./src/generated/root.js", + "protos:generate": "npm run protos:generate:js && npm run protos:generate:ts", "lint": "eslint . --ext .ts", "lint:fix": "eslint . --ext .ts --fix", "tdd": "npm run test -- --watch-extensions ts --watch", @@ -61,8 +63,6 @@ "@opentelemetry/api": "^1.3.0" }, "devDependencies": { - "@bufbuild/buf": "1.47.2", - "@bufbuild/protoc-gen-es": "2.2.3", "@opentelemetry/api": "1.9.0", "@types/mocha": "10.0.10", "@types/webpack-env": "1.16.3", @@ -75,18 +75,19 @@ "karma-webpack": "5.0.1", "mocha": "11.7.5", "nyc": "17.1.0", + "protobufjs-cli": "1.1.3", "ts-loader": "9.5.4", "typescript": "5.0.4", "webpack": "5.101.3" }, "dependencies": { - "@bufbuild/protobuf": "2.2.3", "@opentelemetry/api-logs": "0.208.0", "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0", "@opentelemetry/sdk-logs": "0.208.0", "@opentelemetry/sdk-metrics": "2.2.0", - "@opentelemetry/sdk-trace-base": "2.2.0" + "@opentelemetry/sdk-trace-base": "2.2.0", + "protobufjs": "7.3.0" }, "homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/otlp-transformer", "sideEffects": false diff --git a/experimental/packages/otlp-transformer/src/common/protobuf/protobuf-export-type.ts b/experimental/packages/otlp-transformer/src/common/protobuf/protobuf-export-type.ts new file mode 100644 index 00000000000..c84d5311c13 --- /dev/null +++ b/experimental/packages/otlp-transformer/src/common/protobuf/protobuf-export-type.ts @@ -0,0 +1,22 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as protobuf from 'protobufjs'; + +export interface ExportType unknown }> { + encode(message: T, writer?: protobuf.Writer): protobuf.Writer; + decode(reader: protobuf.Reader | Uint8Array, length?: number): R; +} diff --git a/experimental/packages/otlp-transformer/src/common/utils.ts b/experimental/packages/otlp-transformer/src/common/utils.ts index 3fc4f58c932..f4f8cb65e41 100644 --- a/experimental/packages/otlp-transformer/src/common/utils.ts +++ b/experimental/packages/otlp-transformer/src/common/utils.ts @@ -16,6 +16,7 @@ import type { OtlpEncodingOptions, Fixed64, LongBits } from './internal-types'; import { HrTime } from '@opentelemetry/api'; +import { hrTimeToNanoseconds } from '@opentelemetry/core'; import { hexToBinary } from './hex-to-binary'; export function hrTimeToNanos(hrTime: HrTime): bigint { @@ -41,6 +42,9 @@ export function encodeAsString(hrTime: HrTime): string { return nanos.toString(); } +const encodeTimestamp = + typeof BigInt !== 'undefined' ? encodeAsString : hrTimeToNanoseconds; + export type HrTimeEncodeFunction = (hrTime: HrTime) => Fixed64; export type SpanContextEncodeFunction = ( spanContext: string @@ -64,47 +68,12 @@ function optionalHexToBinary(str: string | undefined): Uint8Array | undefined { return hexToBinary(str); } -/** - * Convert hex string to base64 (for protobuf JSON format). - */ -export function hexToBase64(hex: string): string { - const bytes = hexToBinary(hex); - // Works in both Node.js and browser - if (typeof Buffer !== 'undefined') { - return Buffer.from(bytes).toString('base64'); - } - // Browser fallback using spread to avoid string concatenation in loop - return btoa(String.fromCharCode(...bytes)); -} - -function optionalHexToBase64(str: string | undefined): string | undefined { - if (str === undefined) return undefined; - return hexToBase64(str); -} - const DEFAULT_ENCODER: Encoder = { encodeHrTime: encodeAsLongBits, encodeSpanContext: hexToBinary, encodeOptionalSpanContext: optionalHexToBinary, }; -/** - * Encoder for protobuf JSON format (used with fromJson). - * Uses string timestamps and base64 for bytes. - */ -export const PROTOBUF_JSON_ENCODER: Encoder = { - encodeHrTime: encodeAsString, - encodeSpanContext: hexToBase64, - encodeOptionalSpanContext: optionalHexToBase64, -}; - -/** @internal */ -export function isOtlpEncoder( - obj: OtlpEncodingOptions | Encoder | undefined -): obj is Encoder { - return obj !== undefined && 'encodeHrTime' in obj; -} - export function getOtlpEncoder(options?: OtlpEncodingOptions): Encoder { if (options === undefined) { return DEFAULT_ENCODER; @@ -113,7 +82,7 @@ export function getOtlpEncoder(options?: OtlpEncodingOptions): Encoder { const useLongBits = options.useLongBits ?? true; const useHex = options.useHex ?? false; return { - encodeHrTime: useLongBits ? encodeAsLongBits : encodeAsString, + encodeHrTime: useLongBits ? encodeAsLongBits : encodeTimestamp, encodeSpanContext: useHex ? identity : hexToBinary, encodeOptionalSpanContext: useHex ? identity : optionalHexToBinary, }; diff --git a/experimental/packages/otlp-transformer/src/logs/internal.ts b/experimental/packages/otlp-transformer/src/logs/internal.ts index 68809ceadfc..510206d37c9 100644 --- a/experimental/packages/otlp-transformer/src/logs/internal.ts +++ b/experimental/packages/otlp-transformer/src/logs/internal.ts @@ -22,7 +22,7 @@ import { IResourceLogs, } from './internal-types'; import { Resource } from '@opentelemetry/resources'; -import { Encoder, getOtlpEncoder, isOtlpEncoder } from '../common/utils'; +import { Encoder, getOtlpEncoder } from '../common/utils'; import { createInstrumentationScope, createResource, @@ -35,9 +35,9 @@ import { LogAttributes } from '@opentelemetry/api-logs'; export function createExportLogsServiceRequest( logRecords: ReadableLogRecord[], - options?: OtlpEncodingOptions | Encoder + options?: OtlpEncodingOptions ): IExportLogsServiceRequest { - const encoder = isOtlpEncoder(options) ? options : getOtlpEncoder(options); + const encoder = getOtlpEncoder(options); return { resourceLogs: logRecordsToResourceLogs(logRecords, encoder), }; diff --git a/experimental/packages/otlp-transformer/src/logs/protobuf/logs.ts b/experimental/packages/otlp-transformer/src/logs/protobuf/logs.ts index 80c67aff4ea..a5b32453b68 100644 --- a/experimental/packages/otlp-transformer/src/logs/protobuf/logs.ts +++ b/experimental/packages/otlp-transformer/src/logs/protobuf/logs.ts @@ -13,16 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { toBinary, fromBinary, fromJsonString } from '@bufbuild/protobuf'; +import * as root from '../../generated/root'; + +import { IExportLogsServiceRequest } from '../internal-types'; import { IExportLogsServiceResponse } from '../export-response'; + import { createExportLogsServiceRequest } from '../internal'; import { ReadableLogRecord } from '@opentelemetry/sdk-logs'; +import { ExportType } from '../../common/protobuf/protobuf-export-type'; import { ISerializer } from '../../i-serializer'; -import { - ExportLogsServiceRequestSchema, - ExportLogsServiceResponseSchema, -} from '../../generated/opentelemetry/proto/collector/logs/v1/logs_service_pb'; -import { PROTOBUF_JSON_ENCODER } from '../../common/utils'; + +const logsResponseType = root.opentelemetry.proto.collector.logs.v1 + .ExportLogsServiceResponse as ExportType; + +const logsRequestType = root.opentelemetry.proto.collector.logs.v1 + .ExportLogsServiceRequest as ExportType; /* * @experimental this serializer may receive breaking changes in minor versions, pin this package's version when using this constant @@ -32,24 +37,10 @@ export const ProtobufLogsSerializer: ISerializer< IExportLogsServiceResponse > = { serializeRequest: (arg: ReadableLogRecord[]) => { - const request = createExportLogsServiceRequest(arg, PROTOBUF_JSON_ENCODER); - const message = fromJsonString( - ExportLogsServiceRequestSchema, - JSON.stringify(request) - ); - return toBinary(ExportLogsServiceRequestSchema, message); + const request = createExportLogsServiceRequest(arg); + return logsRequestType.encode(request).finish(); }, deserializeResponse: (arg: Uint8Array) => { - const response = fromBinary(ExportLogsServiceResponseSchema, arg); - return { - partialSuccess: response.partialSuccess - ? { - rejectedLogRecords: Number( - response.partialSuccess.rejectedLogRecords - ), - errorMessage: response.partialSuccess.errorMessage, - } - : undefined, - }; + return logsResponseType.decode(arg); }, }; diff --git a/experimental/packages/otlp-transformer/src/metrics/internal.ts b/experimental/packages/otlp-transformer/src/metrics/internal.ts index ee06c3de298..50feb9c60fa 100644 --- a/experimental/packages/otlp-transformer/src/metrics/internal.ts +++ b/experimental/packages/otlp-transformer/src/metrics/internal.ts @@ -35,7 +35,7 @@ import { IResourceMetrics, IScopeMetrics, } from './internal-types'; -import { Encoder, getOtlpEncoder, isOtlpEncoder } from '../common/utils'; +import { Encoder, getOtlpEncoder } from '../common/utils'; import { createInstrumentationScope, createResource, @@ -44,9 +44,9 @@ import { export function toResourceMetrics( resourceMetrics: ResourceMetrics, - options?: OtlpEncodingOptions | Encoder + options?: OtlpEncodingOptions ): IResourceMetrics { - const encoder = isOtlpEncoder(options) ? options : getOtlpEncoder(options); + const encoder = getOtlpEncoder(options); const processedResource = createResource(resourceMetrics.resource); return { resource: processedResource, @@ -209,7 +209,7 @@ function toAggregationTemporality( export function createExportMetricsServiceRequest( resourceMetrics: ResourceMetrics[], - options?: OtlpEncodingOptions | Encoder + options?: OtlpEncodingOptions ): IExportMetricsServiceRequest { return { resourceMetrics: resourceMetrics.map(metrics => diff --git a/experimental/packages/otlp-transformer/src/metrics/protobuf/metrics.ts b/experimental/packages/otlp-transformer/src/metrics/protobuf/metrics.ts index ee61370362d..ee21ca93eb2 100644 --- a/experimental/packages/otlp-transformer/src/metrics/protobuf/metrics.ts +++ b/experimental/packages/otlp-transformer/src/metrics/protobuf/metrics.ts @@ -14,43 +14,29 @@ * limitations under the License. */ -import { toBinary, fromBinary, fromJsonString } from '@bufbuild/protobuf'; +import * as root from '../../generated/root'; import { ISerializer } from '../../i-serializer'; +import { IExportMetricsServiceRequest } from '../internal-types'; +import { ExportType } from '../../common/protobuf/protobuf-export-type'; import { createExportMetricsServiceRequest } from '../internal'; import { ResourceMetrics } from '@opentelemetry/sdk-metrics'; import { IExportMetricsServiceResponse } from '../export-response'; -import { - ExportMetricsServiceRequestSchema, - ExportMetricsServiceResponseSchema, -} from '../../generated/opentelemetry/proto/collector/metrics/v1/metrics_service_pb'; -import { PROTOBUF_JSON_ENCODER } from '../../common/utils'; + +const metricsResponseType = root.opentelemetry.proto.collector.metrics.v1 + .ExportMetricsServiceResponse as ExportType; + +const metricsRequestType = root.opentelemetry.proto.collector.metrics.v1 + .ExportMetricsServiceRequest as ExportType; export const ProtobufMetricsSerializer: ISerializer< ResourceMetrics, IExportMetricsServiceResponse > = { serializeRequest: (arg: ResourceMetrics) => { - const request = createExportMetricsServiceRequest( - [arg], - PROTOBUF_JSON_ENCODER - ); - const message = fromJsonString( - ExportMetricsServiceRequestSchema, - JSON.stringify(request) - ); - return toBinary(ExportMetricsServiceRequestSchema, message); + const request = createExportMetricsServiceRequest([arg]); + return metricsRequestType.encode(request).finish(); }, deserializeResponse: (arg: Uint8Array) => { - const response = fromBinary(ExportMetricsServiceResponseSchema, arg); - return { - partialSuccess: response.partialSuccess - ? { - rejectedDataPoints: Number( - response.partialSuccess.rejectedDataPoints - ), - errorMessage: response.partialSuccess.errorMessage, - } - : undefined, - }; + return metricsResponseType.decode(arg); }, }; diff --git a/experimental/packages/otlp-transformer/src/trace/internal.ts b/experimental/packages/otlp-transformer/src/trace/internal.ts index 42d1fc853fb..cbfef6f28d1 100644 --- a/experimental/packages/otlp-transformer/src/trace/internal.ts +++ b/experimental/packages/otlp-transformer/src/trace/internal.ts @@ -32,7 +32,7 @@ import { ISpan, } from './internal-types'; import { OtlpEncodingOptions } from '../common/internal-types'; -import { getOtlpEncoder, isOtlpEncoder } from '../common/utils'; +import { getOtlpEncoder } from '../common/utils'; // Span flags constants matching the OTLP specification const SPAN_FLAGS_CONTEXT_HAS_IS_REMOTE_MASK = 0x100; @@ -107,11 +107,27 @@ export function toOtlpSpanEvent( }; } +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + export function createExportTraceServiceRequest( spans: ReadableSpan[], - options?: OtlpEncodingOptions | Encoder + options?: OtlpEncodingOptions ): IExportTraceServiceRequest { - const encoder = isOtlpEncoder(options) ? options : getOtlpEncoder(options); + const encoder = getOtlpEncoder(options); return { resourceSpans: spanRecordsToResourceSpans(spans, encoder), }; diff --git a/experimental/packages/otlp-transformer/src/trace/protobuf/trace.ts b/experimental/packages/otlp-transformer/src/trace/protobuf/trace.ts index cc7210a3702..87d5f481fe0 100644 --- a/experimental/packages/otlp-transformer/src/trace/protobuf/trace.ts +++ b/experimental/packages/otlp-transformer/src/trace/protobuf/trace.ts @@ -14,38 +14,29 @@ * limitations under the License. */ -import { toBinary, fromBinary, fromJsonString } from '@bufbuild/protobuf'; +import * as root from '../../generated/root'; import { ISerializer } from '../../i-serializer'; +import { ExportType } from '../../common/protobuf/protobuf-export-type'; +import { IExportTraceServiceRequest } from '../internal-types'; import { ReadableSpan } from '@opentelemetry/sdk-trace-base'; import { createExportTraceServiceRequest } from '../internal'; import { IExportTraceServiceResponse } from '../export-response'; -import { - ExportTraceServiceRequestSchema, - ExportTraceServiceResponseSchema, -} from '../../generated/opentelemetry/proto/collector/trace/v1/trace_service_pb'; -import { PROTOBUF_JSON_ENCODER } from '../../common/utils'; + +const traceResponseType = root.opentelemetry.proto.collector.trace.v1 + .ExportTraceServiceResponse as ExportType; + +const traceRequestType = root.opentelemetry.proto.collector.trace.v1 + .ExportTraceServiceRequest as ExportType; export const ProtobufTraceSerializer: ISerializer< ReadableSpan[], IExportTraceServiceResponse > = { serializeRequest: (arg: ReadableSpan[]) => { - const request = createExportTraceServiceRequest(arg, PROTOBUF_JSON_ENCODER); - const message = fromJsonString( - ExportTraceServiceRequestSchema, - JSON.stringify(request) - ); - return toBinary(ExportTraceServiceRequestSchema, message); + const request = createExportTraceServiceRequest(arg); + return traceRequestType.encode(request).finish(); }, deserializeResponse: (arg: Uint8Array) => { - const response = fromBinary(ExportTraceServiceResponseSchema, arg); - return { - partialSuccess: response.partialSuccess - ? { - rejectedSpans: Number(response.partialSuccess.rejectedSpans), - errorMessage: response.partialSuccess.errorMessage, - } - : undefined, - }; + return traceResponseType.decode(arg); }, }; diff --git a/experimental/packages/otlp-transformer/test/logs.test.ts b/experimental/packages/otlp-transformer/test/logs.test.ts index b3bdf6148f1..4ddd4ff3b45 100644 --- a/experimental/packages/otlp-transformer/test/logs.test.ts +++ b/experimental/packages/otlp-transformer/test/logs.test.ts @@ -19,12 +19,8 @@ import { Resource, resourceFromAttributes } from '@opentelemetry/resources'; import * as assert from 'assert'; import { ReadableLogRecord } from '@opentelemetry/sdk-logs'; import { SeverityNumber } from '@opentelemetry/api-logs'; -import { hexToBase64 } from '../src/common/utils'; -import { fromBinary, toBinary, create, toJson } from '@bufbuild/protobuf'; -import { - ExportLogsServiceRequestSchema, - ExportLogsServiceResponseSchema, -} from '../src/generated/opentelemetry/proto/collector/logs/v1/logs_service_pb'; +import { toBase64 } from './utils'; +import * as root from '../src/generated/root'; import { OtlpEncodingOptions } from '../src/common/internal-types'; import { ESeverityNumber, @@ -101,15 +97,9 @@ function createExpectedLogJson( }; } -// Returns untyped object for JSON comparison (toJson output differs from typed interface) -function createExpectedLogProtobuf(): unknown { - // protobuf JSON format uses base64 for bytes - const traceId = hexToBase64('00000000000000000000000000000001'); - const spanId = hexToBase64('0000000000000002'); - - // protobuf JSON format uses string representation for 64-bit integers - const timeUnixNano = '1680253513123241635'; - const observedTimeUnixNano = '1683526948965142784'; +function createExpectedLogProtobuf(): IExportLogsServiceRequest { + const traceId = toBase64('00000000000000000000000000000001'); + const spanId = toBase64('0000000000000002'); return { resourceLogs: [ @@ -121,16 +111,16 @@ function createExpectedLogProtobuf(): unknown { value: { stringValue: 'some attribute value' }, }, ], + droppedAttributesCount: 0, }, scopeLogs: [ { scope: { name: 'scope_name_1', version: '0.1.0' }, logRecords: [ { - timeUnixNano: timeUnixNano, - observedTimeUnixNano: observedTimeUnixNano, - // protobuf-es toJson outputs enums as strings - severityNumber: 'SEVERITY_NUMBER_ERROR', + timeUnixNano: 1680253513123241700, + observedTimeUnixNano: 1683526948965142800, + severityNumber: ESeverityNumber.SEVERITY_NUMBER_ERROR, severityText: 'error', body: { stringValue: 'some_log_body' }, eventName: 'some.event.name', @@ -140,6 +130,7 @@ function createExpectedLogProtobuf(): unknown { value: { stringValue: 'some attribute value' }, }, ], + droppedAttributesCount: 0, flags: 1, traceId: traceId, spanId: spanId, @@ -334,34 +325,39 @@ describe('Logs', () => { it('serializes an export request', () => { const serialized = ProtobufLogsSerializer.serializeRequest([log_1_1_1]); assert.ok(serialized, 'serialized response is undefined'); - const decoded = fromBinary(ExportLogsServiceRequestSchema, serialized); - const expected = createExpectedLogProtobuf(); - // toJson converts to protobuf JSON format (strings for 64-bit ints, base64 for bytes) - const decodedJson = toJson(ExportLogsServiceRequestSchema, decoded); - assert.deepStrictEqual(decodedJson, expected); - }); + const decoded = + root.opentelemetry.proto.collector.logs.v1.ExportLogsServiceRequest.decode( + serialized + ); - it('serializes an empty request', () => { - const serialized = ProtobufLogsSerializer.serializeRequest([]); - assert.ok(serialized, 'serialized response is undefined'); - const decoded = fromBinary(ExportLogsServiceRequestSchema, serialized); - assert.deepStrictEqual( - toJson(ExportLogsServiceRequestSchema, decoded), - {} - ); + const expected = createExpectedLogProtobuf(); + const decodedObj = + root.opentelemetry.proto.collector.logs.v1.ExportLogsServiceRequest.toObject( + decoded, + { + // This incurs some precision loss that's taken into account in createExpectedLogsProtobuf() + // Using String here will incur the same precision loss on browser only, using Number to prevent having to + // have different assertions for browser and Node.js + longs: Number, + // Convert to String (Base64) as otherwise the type will be different for Node.js (Buffer) and Browser (Uint8Array) + // and this fails assertions. + bytes: String, + } + ); + + assert.deepStrictEqual(decodedObj, expected); }); it('deserializes a response', () => { - const response = create(ExportLogsServiceResponseSchema, { - partialSuccess: { - errorMessage: 'foo', - rejectedLogRecords: BigInt(1), - }, - }); - const protobufSerializedResponse = toBinary( - ExportLogsServiceResponseSchema, - response - ); + const protobufSerializedResponse = + root.opentelemetry.proto.collector.logs.v1.ExportLogsServiceResponse.encode( + { + partialSuccess: { + errorMessage: 'foo', + rejectedLogRecords: 1, + }, + } + ).finish(); const deserializedResponse = ProtobufLogsSerializer.deserializeResponse( protobufSerializedResponse @@ -372,7 +368,10 @@ describe('Logs', () => { 'partialSuccess not present in the deserialized message' ); assert.equal(deserializedResponse.partialSuccess.errorMessage, 'foo'); - assert.equal(deserializedResponse.partialSuccess.rejectedLogRecords, 1); + assert.equal( + Number(deserializedResponse.partialSuccess.rejectedLogRecords), + 1 + ); }); it('does not throw when deserializing an empty response', () => { diff --git a/experimental/packages/otlp-transformer/test/metrics.test.ts b/experimental/packages/otlp-transformer/test/metrics.test.ts index e6b1046342f..ffd100febb3 100644 --- a/experimental/packages/otlp-transformer/test/metrics.test.ts +++ b/experimental/packages/otlp-transformer/test/metrics.test.ts @@ -24,12 +24,8 @@ import { import * as assert from 'assert'; import { createExportMetricsServiceRequest } from '../src/metrics/internal'; import { EAggregationTemporality } from '../src/metrics/internal-types'; -import { hrTime } from '@opentelemetry/core'; -import { fromBinary, toBinary, create, toJson } from '@bufbuild/protobuf'; -import { - ExportMetricsServiceRequestSchema, - ExportMetricsServiceResponseSchema, -} from '../src/generated/opentelemetry/proto/collector/metrics/v1/metrics_service_pb'; +import { hrTime, hrTimeToNanoseconds } from '@opentelemetry/core'; +import * as root from '../src/generated/root'; import { encodeAsLongBits, encodeAsString } from '../src/common/utils'; import { ProtobufMetricsSerializer } from '../src/metrics/protobuf'; import { JsonMetricsSerializer } from '../src/metrics/json'; @@ -320,7 +316,8 @@ describe('Metrics', () => { scopeMetrics: [ { scope: { - ...expectedScope, + name: 'mylib', + version: '0.1.0', schemaUrl: expectedSchemaUrl, }, metrics: metricData, @@ -815,43 +812,23 @@ describe('Metrics', () => { ]) ); assert.ok(serialized, 'serialized response is undefined'); - const decoded = fromBinary(ExportMetricsServiceRequestSchema, serialized); - // toJson converts to protobuf JSON format (strings for 64-bit ints) - const decodedJson = toJson(ExportMetricsServiceRequestSchema, decoded); + const decoded = + root.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceRequest.decode( + serialized + ); - // protobuf JSON format uses string representation for 64-bit integers - const expectedProtobufAttributes = [ - { - key: 'string-attribute', - value: { stringValue: 'some attribute value' }, - }, - { key: 'int-attribute', value: { intValue: '1' } }, - { key: 'double-attribute', value: { doubleValue: 1.1 } }, - { key: 'boolean-attribute', value: { boolValue: true } }, - { - key: 'array-attribute', - value: { - arrayValue: { - values: [ - { stringValue: 'attribute value 1' }, - { stringValue: 'attribute value 2' }, - ], - }, - }, - }, - ]; + const decodedObj = + root.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceRequest.toObject( + decoded, + { + longs: Number, + } + ); const expected = { resourceMetrics: [ { - resource: { - attributes: [ - { - key: 'resource-attribute', - value: { stringValue: 'resource attribute value' }, - }, - ], - }, + resource: expectedResource, scopeMetrics: [ { scope: expectedScope, @@ -864,15 +841,14 @@ describe('Metrics', () => { sum: { dataPoints: [ { - attributes: expectedProtobufAttributes, - // encodeAsString preserves full precision via BigInt - startTimeUnixNano: encodeAsString(START_TIME), - timeUnixNano: encodeAsString(END_TIME), - asInt: '10', + attributes: expectedAttributes, + startTimeUnixNano: hrTimeToNanoseconds(START_TIME), + timeUnixNano: hrTimeToNanoseconds(END_TIME), + asInt: 10, }, ], - // protobuf-es toJson outputs enums as strings - aggregationTemporality: 'AGGREGATION_TEMPORALITY_DELTA', + aggregationTemporality: + EAggregationTemporality.AGGREGATION_TEMPORALITY_DELTA, isMonotonic: true, }, }, @@ -882,35 +858,19 @@ describe('Metrics', () => { }, ], }; - assert.deepStrictEqual(decodedJson, expected); - }); - - it('serializes an empty request', () => { - const serialized = ProtobufMetricsSerializer.serializeRequest( - createResourceMetrics([]) - ); - assert.ok(serialized, 'serialized response is undefined'); - const decoded = fromBinary(ExportMetricsServiceRequestSchema, serialized); - const decodedJson = toJson(ExportMetricsServiceRequestSchema, decoded); - // Empty metrics still has resource and scope, just no metric data - assert.ok(decodedJson, 'decoded response should exist'); - assert.ok( - typeof decodedJson === 'object' && decodedJson !== null, - 'decoded should be an object' - ); + assert.deepStrictEqual(decodedObj, expected); }); it('deserializes a response', () => { - const response = create(ExportMetricsServiceResponseSchema, { - partialSuccess: { - errorMessage: 'foo', - rejectedDataPoints: BigInt(1), - }, - }); - const protobufSerializedResponse = toBinary( - ExportMetricsServiceResponseSchema, - response - ); + const protobufSerializedResponse = + root.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceResponse.encode( + { + partialSuccess: { + errorMessage: 'foo', + rejectedDataPoints: 1, + }, + } + ).finish(); const deserializedResponse = ProtobufMetricsSerializer.deserializeResponse( @@ -922,7 +882,10 @@ describe('Metrics', () => { 'partialSuccess not present in the deserialized message' ); assert.equal(deserializedResponse.partialSuccess.errorMessage, 'foo'); - assert.equal(deserializedResponse.partialSuccess.rejectedDataPoints, 1); + assert.equal( + Number(deserializedResponse.partialSuccess.rejectedDataPoints), + 1 + ); }); it('does not throw when deserializing an empty response', () => { diff --git a/experimental/packages/otlp-transformer/test/trace.test.ts b/experimental/packages/otlp-transformer/test/trace.test.ts index 5b272a5a3f8..5a1aaf13a23 100644 --- a/experimental/packages/otlp-transformer/test/trace.test.ts +++ b/experimental/packages/otlp-transformer/test/trace.test.ts @@ -13,17 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { fromBinary, toBinary, create, toJson } from '@bufbuild/protobuf'; -import { - ExportTraceServiceRequestSchema, - ExportTraceServiceResponseSchema, -} from '../src/generated/opentelemetry/proto/collector/trace/v1/trace_service_pb'; +import * as root from '../src/generated/root'; import { SpanKind, SpanStatusCode, TraceFlags } from '@opentelemetry/api'; import { TraceState } from '@opentelemetry/core'; import { Resource, resourceFromAttributes } from '@opentelemetry/resources'; import { ReadableSpan } from '@opentelemetry/sdk-trace-base'; import * as assert from 'assert'; -import { hexToBase64 } from '../src/common/utils'; +import { toBase64 } from './utils'; import { OtlpEncodingOptions } from '../src/common/internal-types'; import { ESpanKind, EStatusCode } from '../src/trace/internal-types'; import { createExportTraceServiceRequest } from '../src/trace/internal'; @@ -146,17 +142,15 @@ function createExpectedSpanJson(options: OtlpEncodingOptions) { } function createExpectedSpanProtobuf() { - // protobuf JSON format uses string representation for 64-bit integers - const startTime = '1640715557342725388'; - const endTime = '1640715558642725388'; - const eventTime = '1640715558542725388'; - - // protobuf JSON format uses base64 for bytes - const traceId = hexToBase64('00000000000000000000000000000001'); - const spanId = hexToBase64('0000000000000002'); - const parentSpanId = hexToBase64('0000000000000001'); - const linkSpanId = hexToBase64('0000000000000003'); - const linkTraceId = hexToBase64('00000000000000000000000000000002'); + const startTime = 1640715557342725400; + const endTime = 1640715558642725400; + const eventTime = 1640715558542725400; + + const traceId = toBase64('00000000000000000000000000000001'); + const spanId = toBase64('0000000000000002'); + const parentSpanId = toBase64('0000000000000001'); + const linkSpanId = toBase64('0000000000000003'); + const linkTraceId = toBase64('00000000000000000000000000000002'); return { resourceSpans: [ @@ -168,6 +162,7 @@ function createExpectedSpanProtobuf() { value: { stringValue: 'resource attribute value' }, }, ], + droppedAttributesCount: 0, }, scopeSpans: [ { @@ -179,46 +174,54 @@ function createExpectedSpanProtobuf() { traceState: 'span=bar', parentSpanId: parentSpanId, name: 'span-name', - // protobuf-es toJson outputs enums as strings - kind: 'SPAN_KIND_CLIENT', - startTimeUnixNano: startTime, - endTimeUnixNano: endTime, - attributes: [ + kind: ESpanKind.SPAN_KIND_CLIENT, + links: [ { - key: 'string-attribute', - value: { stringValue: 'some attribute value' }, + droppedAttributesCount: 0, + spanId: linkSpanId, + traceId: linkTraceId, + traceState: 'link=foo', + attributes: [ + { + key: 'link-attribute', + value: { + stringValue: 'string value', + }, + }, + ], + flags: 0x101, // TraceFlags (0x01) | HAS_IS_REMOTE }, ], + startTimeUnixNano: startTime, + endTimeUnixNano: endTime, events: [ { - name: 'some event', - timeUnixNano: eventTime, + droppedAttributesCount: 0, attributes: [ { key: 'event-attribute', - value: { stringValue: 'some string value' }, + value: { + stringValue: 'some string value', + }, }, ], + name: 'some event', + timeUnixNano: eventTime, }, ], - links: [ + attributes: [ { - traceId: linkTraceId, - spanId: linkSpanId, - traceState: 'link=foo', - attributes: [ - { - key: 'link-attribute', - value: { stringValue: 'string value' }, - }, - ], - // TraceFlags (0x01) | HAS_IS_REMOTE - flags: 0x101, + key: 'string-attribute', + value: { stringValue: 'some attribute value' }, }, ], - status: { code: 'STATUS_CODE_OK' }, - // TraceFlags (0x01) | HAS_IS_REMOTE - flags: 0x101, + droppedAttributesCount: 0, + droppedEventsCount: 0, + droppedLinksCount: 0, + status: { + code: EStatusCode.STATUS_CODE_OK, + }, + flags: 0x101, // TraceFlags (0x01) | HAS_IS_REMOTE }, ], schemaUrl: 'http://url.to.schema', @@ -474,34 +477,37 @@ describe('Trace', () => { it('serializes an export request', () => { const serialized = ProtobufTraceSerializer.serializeRequest([span]); assert.ok(serialized, 'serialized response is undefined'); - const decoded = fromBinary(ExportTraceServiceRequestSchema, serialized); + const decoded = + root.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest.decode( + serialized + ); const expected = createExpectedSpanProtobuf(); - // toJson converts to protobuf JSON format (strings for 64-bit ints, base64 for bytes) - const decodedJson = toJson(ExportTraceServiceRequestSchema, decoded); - assert.deepStrictEqual(decodedJson, expected); - }); - - it('serializes an empty request', () => { - const serialized = ProtobufTraceSerializer.serializeRequest([]); - assert.ok(serialized, 'serialized response is undefined'); - const decoded = fromBinary(ExportTraceServiceRequestSchema, serialized); - assert.deepStrictEqual( - toJson(ExportTraceServiceRequestSchema, decoded), - {} - ); + const decodedObj = + root.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest.toObject( + decoded, + { + // This incurs some precision loss that's taken into account in createExpectedSpanProtobuf() + // Using String here will incur the same precision loss on browser only, using Number to prevent having to + // have different assertions for browser and Node.js + longs: Number, + // Convert to String (Base64) as otherwise the type will be different for Node.js (Buffer) and Browser (Uint8Array) + // and this fails assertions. + bytes: String, + } + ); + assert.deepStrictEqual(decodedObj, expected); }); it('deserializes a response', () => { - const response = create(ExportTraceServiceResponseSchema, { - partialSuccess: { - errorMessage: 'foo', - rejectedSpans: BigInt(1), - }, - }); - const protobufSerializedResponse = toBinary( - ExportTraceServiceResponseSchema, - response - ); + const protobufSerializedResponse = + root.opentelemetry.proto.collector.trace.v1.ExportTraceServiceResponse.encode( + { + partialSuccess: { + errorMessage: 'foo', + rejectedSpans: 1, + }, + } + ).finish(); const deserializedResponse = ProtobufTraceSerializer.deserializeResponse( protobufSerializedResponse @@ -512,7 +518,10 @@ describe('Trace', () => { 'partialSuccess not present in the deserialized message' ); assert.equal(deserializedResponse.partialSuccess.errorMessage, 'foo'); - assert.equal(deserializedResponse.partialSuccess.rejectedSpans, 1); + assert.equal( + Number(deserializedResponse.partialSuccess.rejectedSpans), + 1 + ); }); it('does not throw when deserializing an empty response', () => { diff --git a/experimental/packages/otlp-transformer/test/utils.ts b/experimental/packages/otlp-transformer/test/utils.ts new file mode 100644 index 00000000000..f9856f5f507 --- /dev/null +++ b/experimental/packages/otlp-transformer/test/utils.ts @@ -0,0 +1,32 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hexToBinary } from '../src/common/hex-to-binary'; + +/** + * utility function to convert a string representing a hex value to a base64 string + * that represents the bytes of that hex value. This is needed as we need to support Node.js 14 + * where btoa() does not exist, and the Browser, where Buffer does not exist. + * @param hexStr + */ +export function toBase64(hexStr: string) { + if (typeof btoa !== 'undefined') { + const decoder = new TextDecoder('utf8'); + return btoa(decoder.decode(hexToBinary(hexStr))); + } + + return Buffer.from(hexToBinary(hexStr)).toString('base64'); +} diff --git a/experimental/packages/otlp-transformer/tsconfig.esm.json b/experimental/packages/otlp-transformer/tsconfig.esm.json index 0dc676825ce..b2f0a9b99c9 100644 --- a/experimental/packages/otlp-transformer/tsconfig.esm.json +++ b/experimental/packages/otlp-transformer/tsconfig.esm.json @@ -1,12 +1,15 @@ { "extends": "../../../tsconfig.base.esm.json", "compilerOptions": { + "allowJs": true, "outDir": "build/esm", "rootDir": "src", "tsBuildInfoFile": "build/esm/tsconfig.esm.tsbuildinfo" }, "include": [ - "src/**/*.ts" + "src/**/*.ts", + "src/generated/*.js", + "src/generated/*.ts" ], "references": [ { diff --git a/experimental/packages/otlp-transformer/tsconfig.esnext.json b/experimental/packages/otlp-transformer/tsconfig.esnext.json index 56f7465cebf..ff98b47cd16 100644 --- a/experimental/packages/otlp-transformer/tsconfig.esnext.json +++ b/experimental/packages/otlp-transformer/tsconfig.esnext.json @@ -1,12 +1,15 @@ { "extends": "../../../tsconfig.base.esnext.json", "compilerOptions": { + "allowJs": true, "outDir": "build/esnext", "rootDir": "src", "tsBuildInfoFile": "build/esnext/tsconfig.esnext.tsbuildinfo" }, "include": [ - "src/**/*.ts" + "src/**/*.ts", + "src/generated/*.js", + "src/generated/*.ts" ], "references": [ { diff --git a/experimental/packages/otlp-transformer/tsconfig.json b/experimental/packages/otlp-transformer/tsconfig.json index cb92fea5754..d68d60fa7e7 100644 --- a/experimental/packages/otlp-transformer/tsconfig.json +++ b/experimental/packages/otlp-transformer/tsconfig.json @@ -1,12 +1,15 @@ { "extends": "../../../tsconfig.base.json", "compilerOptions": { + "allowJs": true, "outDir": "build", "rootDir": "." }, "files": [], "include": [ "src/**/*.ts", + "src/generated/*.js", + "src/generated/*.ts", "test/**/*.ts" ], "references": [ diff --git a/experimental/packages/sampler-composite/tsconfig.esm.json b/experimental/packages/sampler-composite/tsconfig.esm.json index 34a69779c35..5fe96d554ba 100644 --- a/experimental/packages/sampler-composite/tsconfig.esm.json +++ b/experimental/packages/sampler-composite/tsconfig.esm.json @@ -1,6 +1,7 @@ { "extends": "../../../tsconfig.base.esm.json", "compilerOptions": { + "allowJs": true, "outDir": "build/esm", "rootDir": "src", "tsBuildInfoFile": "build/esm/tsconfig.esm.tsbuildinfo" diff --git a/experimental/packages/sampler-composite/tsconfig.esnext.json b/experimental/packages/sampler-composite/tsconfig.esnext.json index 762878aef92..17ed0461704 100644 --- a/experimental/packages/sampler-composite/tsconfig.esnext.json +++ b/experimental/packages/sampler-composite/tsconfig.esnext.json @@ -1,6 +1,7 @@ { "extends": "../../../tsconfig.base.esnext.json", "compilerOptions": { + "allowJs": true, "outDir": "build/esnext", "rootDir": "src", "tsBuildInfoFile": "build/esnext/tsconfig.esnext.tsbuildinfo" diff --git a/experimental/packages/sampler-composite/tsconfig.json b/experimental/packages/sampler-composite/tsconfig.json index 601cb95eb89..eb6f0a3a273 100644 --- a/experimental/packages/sampler-composite/tsconfig.json +++ b/experimental/packages/sampler-composite/tsconfig.json @@ -1,6 +1,7 @@ { "extends": "../../../tsconfig.base.json", "compilerOptions": { + "allowJs": true, "outDir": "build", "rootDir": "." }, diff --git a/package-lock.json b/package-lock.json index d257f72b747..9ea6f5268d1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1018,6 +1018,7 @@ "@types/mocha": "10.0.10", "@types/node": "18.6.5", "@types/sinon": "17.0.4", + "@typescript/vfs": "1.6.2", "mocha": "11.7.5", "nyc": "17.1.0", "sinon": "18.0.1", @@ -1230,17 +1231,15 @@ "version": "0.208.0", "license": "Apache-2.0", "dependencies": { - "@bufbuild/protobuf": "2.2.3", "@opentelemetry/api-logs": "0.208.0", "@opentelemetry/core": "2.2.0", "@opentelemetry/resources": "2.2.0", "@opentelemetry/sdk-logs": "0.208.0", "@opentelemetry/sdk-metrics": "2.2.0", - "@opentelemetry/sdk-trace-base": "2.2.0" + "@opentelemetry/sdk-trace-base": "2.2.0", + "protobufjs": "7.3.0" }, "devDependencies": { - "@bufbuild/buf": "1.47.2", - "@bufbuild/protoc-gen-es": "2.2.3", "@opentelemetry/api": "1.9.0", "@types/mocha": "10.0.10", "@types/webpack-env": "1.16.3", @@ -1253,6 +1252,7 @@ "karma-webpack": "5.0.1", "mocha": "11.7.5", "nyc": "17.1.0", + "protobufjs-cli": "1.1.3", "ts-loader": "9.5.4", "typescript": "5.0.4", "webpack": "5.101.3" @@ -1264,148 +1264,28 @@ "@opentelemetry/api": "^1.3.0" } }, - "experimental/packages/otlp-transformer/node_modules/@bufbuild/buf": { - "version": "1.47.2", - "resolved": "https://registry.npmjs.org/@bufbuild/buf/-/buf-1.47.2.tgz", - "integrity": "sha512-glY5kCAoO4+a7HvDb+BLOdoHSdCk4mdXdkp53H8JFz7maOnkxCiHHXgRX+taFyEu25N8ybn7NjZFrZSdRwq2sA==", - "dev": true, + "experimental/packages/otlp-transformer/node_modules/protobufjs": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.3.0.tgz", + "integrity": "sha512-YWD03n3shzV9ImZRX3ccbjqLxj7NokGN0V/ESiBV5xWqrommYHYiihuIyavq03pWSGqlyvYUFmfoMKd+1rPA/g==", "hasInstallScript": true, - "license": "Apache-2.0", - "bin": { - "buf": "bin/buf", - "protoc-gen-buf-breaking": "bin/protoc-gen-buf-breaking", - "protoc-gen-buf-lint": "bin/protoc-gen-buf-lint" - }, - "engines": { - "node": ">=12" + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" }, - "optionalDependencies": { - "@bufbuild/buf-darwin-arm64": "1.47.2", - "@bufbuild/buf-darwin-x64": "1.47.2", - "@bufbuild/buf-linux-aarch64": "1.47.2", - "@bufbuild/buf-linux-armv7": "1.47.2", - "@bufbuild/buf-linux-x64": "1.47.2", - "@bufbuild/buf-win32-arm64": "1.47.2", - "@bufbuild/buf-win32-x64": "1.47.2" - } - }, - "experimental/packages/otlp-transformer/node_modules/@bufbuild/buf-darwin-arm64": { - "version": "1.47.2", - "resolved": "https://registry.npmjs.org/@bufbuild/buf-darwin-arm64/-/buf-darwin-arm64-1.47.2.tgz", - "integrity": "sha512-74WerFn06y+azgVfsnzhfbI5wla/OLPDnIvaNJBWHaqya/3bfascJkDylW2GVNHmwG1K/cscpmcc/RJPaO7ntQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": ">=12" - } - }, - "experimental/packages/otlp-transformer/node_modules/@bufbuild/buf-darwin-x64": { - "version": "1.47.2", - "resolved": "https://registry.npmjs.org/@bufbuild/buf-darwin-x64/-/buf-darwin-x64-1.47.2.tgz", - "integrity": "sha512-adAiOacOQe8Ym/YXPCEiq9mrPeKRmDtF2TgqPWTcDy6mF7TqR7hMJINkEEuMd1EeACmXnzMOnXlm9ICtvdYgPg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "experimental/packages/otlp-transformer/node_modules/@bufbuild/buf-linux-aarch64": { - "version": "1.47.2", - "resolved": "https://registry.npmjs.org/@bufbuild/buf-linux-aarch64/-/buf-linux-aarch64-1.47.2.tgz", - "integrity": "sha512-52vY+Owffr5diw2PyfQJqH+Fld6zW6NhNZak4zojvc2MjZKubWM0TfNyM9jXz2YrwyB+cyxkabE60nBI80m37w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "experimental/packages/otlp-transformer/node_modules/@bufbuild/buf-linux-armv7": { - "version": "1.47.2", - "resolved": "https://registry.npmjs.org/@bufbuild/buf-linux-armv7/-/buf-linux-armv7-1.47.2.tgz", - "integrity": "sha512-g9KtpObDeHZ/VG/0b5ZCieOao7L/WYZ0fPqFSs4N07D3APgEDhJG6vLyUcDgJMDgyLcgkNjNz0+XdYQb/tXyQw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "experimental/packages/otlp-transformer/node_modules/@bufbuild/buf-linux-x64": { - "version": "1.47.2", - "resolved": "https://registry.npmjs.org/@bufbuild/buf-linux-x64/-/buf-linux-x64-1.47.2.tgz", - "integrity": "sha512-MODCK2BzD1Mgoyr+5Sp8xA8qMNdytj8hYheyhA5NnCGTkQf8sfqAjpBSAAmKk6Zar8HOlVXML6tzE/ioDFFGwQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "experimental/packages/otlp-transformer/node_modules/@bufbuild/buf-win32-arm64": { - "version": "1.47.2", - "resolved": "https://registry.npmjs.org/@bufbuild/buf-win32-arm64/-/buf-win32-arm64-1.47.2.tgz", - "integrity": "sha512-563YKYWJl3LrCY3G3+zuhb8HwOs6DzWslwGPFkKV2hwHyWyvd1DR1JjiLvw9zX64IKNctQ0HempSqc3kcboaqQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "experimental/packages/otlp-transformer/node_modules/@bufbuild/buf-win32-x64": { - "version": "1.47.2", - "resolved": "https://registry.npmjs.org/@bufbuild/buf-win32-x64/-/buf-win32-x64-1.47.2.tgz", - "integrity": "sha512-Sqcdv7La2xBDh3bTdEYb2f4UTMMqCcYe/D0RELhvQ5wDn6I35V3/2YT1OF5fRuf0BZLCo0OdO37S9L47uHSz2g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" + "node": ">=12.0.0" } }, "experimental/packages/sampler-composite": { @@ -3330,63 +3210,6 @@ "node": ">=12" } }, - "node_modules/@bufbuild/protobuf": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.2.3.tgz", - "integrity": "sha512-tFQoXHJdkEOSwj5tRIZSPNUuXK3RaR7T1nUrPgbYX1pUbvqqaaZAsfo+NXBPsz5rZMSKVFrgK1WL8Q/MSLvprg==", - "license": "(Apache-2.0 AND BSD-3-Clause)" - }, - "node_modules/@bufbuild/protoc-gen-es": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@bufbuild/protoc-gen-es/-/protoc-gen-es-2.2.3.tgz", - "integrity": "sha512-hdhIV9NmwXXy24DcbnArauv6L5Dv2PjkO9gz2DUhiZ9HPRpP+rmpT8zo5LohjJiuA7YIQGGKKWSKpRg+xcdLSQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@bufbuild/protobuf": "^2.2.3", - "@bufbuild/protoplugin": "2.2.3" - }, - "bin": { - "protoc-gen-es": "bin/protoc-gen-es" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@bufbuild/protobuf": "2.2.3" - }, - "peerDependenciesMeta": { - "@bufbuild/protobuf": { - "optional": true - } - } - }, - "node_modules/@bufbuild/protoplugin": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@bufbuild/protoplugin/-/protoplugin-2.2.3.tgz", - "integrity": "sha512-UsV7mj6NJTZrqIYJK+jNFnnj5tOS7wgNXKyMjebFEpf+OX6pfXE+nx+QPjumOfu4GxdVPfEDnKuwISgqlXSQqw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@bufbuild/protobuf": "2.2.3", - "@typescript/vfs": "^1.5.2", - "typescript": "5.4.5" - } - }, - "node_modules/@bufbuild/protoplugin/node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "node_modules/@bundled-es-modules/cookie": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@bundled-es-modules/cookie/-/cookie-2.0.1.tgz", @@ -4397,6 +4220,19 @@ "url": "https://opencollective.com/js-sdsl" } }, + "node_modules/@jsdoc/salty": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.9.tgz", + "integrity": "sha512-yYxMVH7Dqw6nO0d5NIV8OQWnitU8k6vXH8NtgqAfIa/IUqRMxRv/NUJJ08VEKbAakwxlgBl5PJdrU0dMPStsnw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=v12.0.0" + } + }, "node_modules/@jsonjoy.com/base64": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", @@ -7176,6 +7012,31 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/methods": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", @@ -8843,6 +8704,13 @@ "node": ">= 6" } }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true, + "license": "MIT" + }, "node_modules/body-parser": { "version": "1.20.3", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", @@ -9395,6 +9263,19 @@ ], "license": "CC-BY-4.0" }, + "node_modules/catharsis": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", + "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.15" + }, + "engines": { + "node": ">= 10" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -11385,6 +11266,93 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=4.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/escodegen/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/eslint": { "version": "8.57.1", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", @@ -14577,6 +14545,82 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/js2xmlparser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", + "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "xmlcreate": "^2.0.4" + } + }, + "node_modules/jsdoc": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.5.tgz", + "integrity": "sha512-P4C6MWP9yIlMiK8nwoZvxN84vb6MsnXcHuy7XzVOvQoCizWX5JFCBsWIIWKXBltpoRZXddUOVQmCTOZt9yDj9g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@babel/parser": "^7.20.15", + "@jsdoc/salty": "^0.2.1", + "@types/markdown-it": "^14.1.1", + "bluebird": "^3.7.2", + "catharsis": "^0.9.0", + "escape-string-regexp": "^2.0.0", + "js2xmlparser": "^4.0.2", + "klaw": "^3.0.0", + "markdown-it": "^14.1.0", + "markdown-it-anchor": "^8.6.7", + "marked": "^4.0.10", + "mkdirp": "^1.0.4", + "requizzle": "^0.2.3", + "strip-json-comments": "^3.1.0", + "underscore": "~1.13.2" + }, + "bin": { + "jsdoc": "jsdoc.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/jsdoc/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jsdoc/node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "dev": true, + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/jsdoc/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -15188,6 +15232,16 @@ "node": ">=0.10.0" } }, + "node_modules/klaw": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", + "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.9" + } + }, "node_modules/launch-editor": { "version": "2.12.0", "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.12.0.tgz", @@ -16262,6 +16316,17 @@ "markdown-it": "bin/markdown-it.mjs" } }, + "node_modules/markdown-it-anchor": { + "version": "8.6.7", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", + "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", + "dev": true, + "license": "Unlicense", + "peerDependencies": { + "@types/markdown-it": "*", + "markdown-it": "*" + } + }, "node_modules/markdown-it/node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -20142,6 +20207,69 @@ "node": ">=12.0.0" } }, + "node_modules/protobufjs-cli": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/protobufjs-cli/-/protobufjs-cli-1.1.3.tgz", + "integrity": "sha512-MqD10lqF+FMsOayFiNOdOGNlXc4iKDCf0ZQPkPR+gizYh9gqUeGTWulABUCdI+N67w5RfJ6xhgX4J8pa8qmMXQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "chalk": "^4.0.0", + "escodegen": "^1.13.0", + "espree": "^9.0.0", + "estraverse": "^5.1.0", + "glob": "^8.0.0", + "jsdoc": "^4.0.0", + "minimist": "^1.2.0", + "semver": "^7.1.2", + "tmp": "^0.2.1", + "uglify-js": "^3.7.7" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "protobufjs": "^7.0.0" + } + }, + "node_modules/protobufjs-cli/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/protobufjs-cli/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/protocols": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.2.tgz", @@ -20763,6 +20891,16 @@ "dev": true, "license": "MIT" }, + "node_modules/requizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz", + "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21" + } + }, "node_modules/resolve": { "version": "1.22.11", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", @@ -23363,7 +23501,6 @@ "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", "dev": true, "license": "BSD-2-Clause", - "optional": true, "bin": { "uglifyjs": "bin/uglifyjs" }, @@ -23371,6 +23508,13 @@ "node": ">=0.8.0" } }, + "node_modules/underscore": { + "version": "1.13.7", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz", + "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==", + "dev": true, + "license": "MIT" + }, "node_modules/undici": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/undici/-/undici-7.16.0.tgz", @@ -24988,6 +25132,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/xmlcreate": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", + "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/xorshift": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/xorshift/-/xorshift-1.2.0.tgz",