@sentio/sdk 4.1.0-rc.2 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/base-context.d.ts.map +1 -1
- package/dist/core/base-context.js +0 -3
- package/dist/core/base-context.js.map +1 -1
- package/dist/core/event-logger.d.ts.map +1 -1
- package/dist/core/event-logger.js +3 -16
- package/dist/core/event-logger.js.map +1 -1
- package/dist/core/meter.d.ts.map +1 -1
- package/dist/core/meter.js +1 -18
- package/dist/core/meter.js.map +1 -1
- package/dist/core/normalization.d.ts +0 -3
- package/dist/core/normalization.d.ts.map +1 -1
- package/dist/core/normalization.js +0 -61
- package/dist/core/normalization.js.map +1 -1
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +1 -1
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/metric-utils.d.ts +6 -1
- package/dist/testing/metric-utils.d.ts.map +1 -1
- package/dist/testing/metric-utils.js +111 -11
- package/dist/testing/metric-utils.js.map +1 -1
- package/dist/testing/test-processor-server.d.ts +0 -309
- package/dist/testing/test-processor-server.d.ts.map +1 -1
- package/dist/testing/test-processor-server.js +8 -0
- package/dist/testing/test-processor-server.js.map +1 -1
- package/dist/{tsdown.config.ts → tsdown.config.js} +8 -1
- package/package.json +4 -4
- package/src/core/base-context.ts +0 -3
- package/src/core/event-logger.ts +2 -18
- package/src/core/meter.ts +1 -18
- package/src/core/normalization.ts +0 -65
- package/src/testing/index.ts +10 -1
- package/src/testing/metric-utils.ts +126 -12
- package/src/testing/test-processor-server.ts +8 -0
- package/src/{tsdown.config.ts → tsdown.config.js} +8 -1
package/src/testing/index.ts
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
export { TestProcessorServer } from './test-processor-server.js'
|
|
2
|
-
export {
|
|
2
|
+
export {
|
|
3
|
+
MetricValueToNumber,
|
|
4
|
+
firstCounterValue,
|
|
5
|
+
firstGaugeValue,
|
|
6
|
+
countersOf,
|
|
7
|
+
gaugesOf,
|
|
8
|
+
eventsOf,
|
|
9
|
+
eventField,
|
|
10
|
+
eventFieldValue
|
|
11
|
+
} from './metric-utils.js'
|
|
3
12
|
|
|
4
13
|
export { loadTestProvidersFromEnv } from './test-provider.js' // TODO make the interface more standard and then export
|
|
5
14
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { MetricValue, ProcessResult } from '@sentio/protos'
|
|
1
|
+
import type { MetricValue, ProcessResult, RichStruct, RichValue, TimeseriesResult } from '@sentio/protos'
|
|
2
|
+
import { TimeseriesResult_TimeseriesType } from '@sentio/protos'
|
|
2
3
|
import { Numberish, BigDecimal } from '../core/index.js'
|
|
3
4
|
import { bytesToBigInt } from '../utils/conversion.js'
|
|
4
5
|
|
|
@@ -24,26 +25,139 @@ export function MetricValueToNumber(v: MetricValue | undefined): Numberish | und
|
|
|
24
25
|
}
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
// The legacy gauges/counters/events fields were dropped in v4; metrics and events
|
|
29
|
+
// now travel exclusively as TimeseriesResult entries tagged by type. These helpers
|
|
30
|
+
// recover the per-type views (and values) that tests used to read off the legacy
|
|
31
|
+
// fields. The metric value lives at data.fields.value (see core/numberish.ts
|
|
32
|
+
// toTimeSeriesData); event payload fields are flattened into data.fields.
|
|
33
|
+
function RichValueToNumber(v: RichValue | undefined): Numberish | undefined {
|
|
34
|
+
if (v === undefined) {
|
|
29
35
|
return undefined
|
|
30
36
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return
|
|
37
|
+
switch (v.value.case) {
|
|
38
|
+
case 'floatValue':
|
|
39
|
+
return v.value.value
|
|
40
|
+
case 'bigintValue': {
|
|
41
|
+
let intValue = bytesToBigInt(v.value.value.data)
|
|
42
|
+
if (v.value.value.negative) {
|
|
43
|
+
intValue = -intValue
|
|
44
|
+
}
|
|
45
|
+
return intValue
|
|
34
46
|
}
|
|
47
|
+
case 'bigdecimalValue': {
|
|
48
|
+
const bd = v.value.value
|
|
49
|
+
if (bd.value === undefined) {
|
|
50
|
+
return undefined
|
|
51
|
+
}
|
|
52
|
+
let intValue = bytesToBigInt(bd.value.data)
|
|
53
|
+
if (bd.value.negative) {
|
|
54
|
+
intValue = -intValue
|
|
55
|
+
}
|
|
56
|
+
return new BigDecimal(`${intValue}e${bd.exp}`)
|
|
57
|
+
}
|
|
58
|
+
default:
|
|
59
|
+
return undefined
|
|
35
60
|
}
|
|
36
|
-
return undefined
|
|
37
61
|
}
|
|
38
62
|
|
|
39
|
-
|
|
40
|
-
|
|
63
|
+
function timeseriesOf(result: ProcessResult | undefined, type: TimeseriesResult_TimeseriesType): TimeseriesResult[] {
|
|
64
|
+
return result?.timeseriesResult.filter((t) => t.type === type) ?? []
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function countersOf(result: ProcessResult | undefined): TimeseriesResult[] {
|
|
68
|
+
return timeseriesOf(result, TimeseriesResult_TimeseriesType.COUNTER)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function gaugesOf(result: ProcessResult | undefined): TimeseriesResult[] {
|
|
72
|
+
return timeseriesOf(result, TimeseriesResult_TimeseriesType.GAUGE)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function eventsOf(result: ProcessResult | undefined): TimeseriesResult[] {
|
|
76
|
+
return timeseriesOf(result, TimeseriesResult_TimeseriesType.EVENT)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Read a string field off a TimeseriesResult's data struct (e.g. an event's
|
|
80
|
+
// `message` or a flattened payload attribute). Returns undefined if absent or
|
|
81
|
+
// not a string.
|
|
82
|
+
export function eventField(ts: TimeseriesResult | undefined, key: string): string | undefined {
|
|
83
|
+
const v = ts?.data?.fields?.[key]?.value
|
|
84
|
+
return v?.case === 'stringValue' ? v.value : undefined
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Convert a RichValue back to a plain JS value (inverse of core/normalization.ts
|
|
88
|
+
// normalizeToRichValue), so event payload fields — including nested structs — can
|
|
89
|
+
// be asserted with deep equality.
|
|
90
|
+
function richValueToJs(v: RichValue | undefined): unknown {
|
|
91
|
+
if (v === undefined) {
|
|
41
92
|
return undefined
|
|
42
93
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return
|
|
94
|
+
switch (v.value.case) {
|
|
95
|
+
case 'nullValue':
|
|
96
|
+
return null
|
|
97
|
+
case 'stringValue':
|
|
98
|
+
case 'boolValue':
|
|
99
|
+
case 'floatValue':
|
|
100
|
+
return v.value.value
|
|
101
|
+
case 'bigintValue': {
|
|
102
|
+
let n = bytesToBigInt(v.value.value.data)
|
|
103
|
+
if (v.value.value.negative) {
|
|
104
|
+
n = -n
|
|
105
|
+
}
|
|
106
|
+
return n
|
|
107
|
+
}
|
|
108
|
+
case 'bigdecimalValue': {
|
|
109
|
+
const bd = v.value.value
|
|
110
|
+
if (bd.value === undefined) {
|
|
111
|
+
return undefined
|
|
112
|
+
}
|
|
113
|
+
let n = bytesToBigInt(bd.value.data)
|
|
114
|
+
if (bd.value.negative) {
|
|
115
|
+
n = -n
|
|
116
|
+
}
|
|
117
|
+
return new BigDecimal(`${n}e${bd.exp}`)
|
|
118
|
+
}
|
|
119
|
+
case 'structValue':
|
|
120
|
+
return richStructToJs(v.value.value)
|
|
121
|
+
case 'listValue':
|
|
122
|
+
return v.value.value.values.map(richValueToJs)
|
|
123
|
+
default:
|
|
124
|
+
return undefined
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function richStructToJs(s: RichStruct | undefined): Record<string, unknown> {
|
|
129
|
+
const out: Record<string, unknown> = {}
|
|
130
|
+
if (s) {
|
|
131
|
+
for (const [k, v] of Object.entries(s.fields)) {
|
|
132
|
+
out[k] = richValueToJs(v)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return out
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Read an arbitrary event payload field off a TimeseriesResult's data struct as a
|
|
139
|
+
// plain JS value (strings, bigints, nested objects, ...).
|
|
140
|
+
export function eventFieldValue(ts: TimeseriesResult | undefined, key: string): unknown {
|
|
141
|
+
return richValueToJs(ts?.data?.fields?.[key])
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function firstTimeseriesValue(
|
|
145
|
+
result: ProcessResult | undefined,
|
|
146
|
+
type: TimeseriesResult_TimeseriesType,
|
|
147
|
+
name: string
|
|
148
|
+
): Numberish | undefined {
|
|
149
|
+
for (const ts of timeseriesOf(result, type)) {
|
|
150
|
+
if (ts.metadata?.name === name) {
|
|
151
|
+
return RichValueToNumber(ts.data?.fields?.value)
|
|
46
152
|
}
|
|
47
153
|
}
|
|
48
154
|
return undefined
|
|
49
155
|
}
|
|
156
|
+
|
|
157
|
+
export function firstCounterValue(result: ProcessResult | undefined, name: string): Numberish | undefined {
|
|
158
|
+
return firstTimeseriesValue(result, TimeseriesResult_TimeseriesType.COUNTER, name)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function firstGaugeValue(result: ProcessResult | undefined, name: string): Numberish | undefined {
|
|
162
|
+
return firstTimeseriesValue(result, TimeseriesResult_TimeseriesType.GAUGE, name)
|
|
163
|
+
}
|
|
@@ -162,6 +162,10 @@ export class TestProcessorServer {
|
|
|
162
162
|
const subject = this.storeContext.subject
|
|
163
163
|
|
|
164
164
|
return new Promise((resolve, reject) => {
|
|
165
|
+
// The V3 service streams timeseries separately as `tsRequest` batches and clears
|
|
166
|
+
// `timeseriesResult` from the final `result` message. Collect the batches here and fold
|
|
167
|
+
// them back in so test helpers can read metrics/events off `result.timeseriesResult`.
|
|
168
|
+
const collectedTimeseries: TimeseriesResult[] = []
|
|
165
169
|
const subscription = subject.subscribe({
|
|
166
170
|
next: (response) => {
|
|
167
171
|
if (response.processId !== processId) {
|
|
@@ -173,6 +177,9 @@ export class TestProcessorServer {
|
|
|
173
177
|
response.value.value.remove ?? false
|
|
174
178
|
)
|
|
175
179
|
}
|
|
180
|
+
if (response.value?.case === 'tsRequest') {
|
|
181
|
+
collectedTimeseries.push(...((response.value.value.data ?? []) as TimeseriesResult[]))
|
|
182
|
+
}
|
|
176
183
|
if (response.value?.case === 'result') {
|
|
177
184
|
subscription.unsubscribe()
|
|
178
185
|
// The service always emits a fully-formed ProcessResult message here; use it directly.
|
|
@@ -186,6 +193,7 @@ export class TestProcessorServer {
|
|
|
186
193
|
if (result.states?.error) {
|
|
187
194
|
reject(new Error(result.states.error))
|
|
188
195
|
} else {
|
|
196
|
+
result.timeseriesResult = collectedTimeseries
|
|
189
197
|
resolve(result)
|
|
190
198
|
}
|
|
191
199
|
}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
// NOTE: This config is intentionally plain JavaScript (not TypeScript). It is
|
|
2
|
+
// copied verbatim to @sentio/sdk/dist and loaded by `sentio build` from the
|
|
3
|
+
// user's node_modules. Node refuses to strip types from .ts files under
|
|
4
|
+
// node_modules ("Stripping types is currently unsupported for files under
|
|
5
|
+
// node_modules"), so a .ts config fails to load there. A .js config has no types
|
|
6
|
+
// to strip and loads natively on every Node version and package manager. Keep it
|
|
7
|
+
// .js — do not rename to .ts.
|
|
1
8
|
import { defineConfig } from 'tsdown'
|
|
2
9
|
|
|
3
10
|
let env
|
|
@@ -17,7 +24,7 @@ function sentioRegistrationGuard() {
|
|
|
17
24
|
// Set the flag only (no code change) so the module is force-kept without
|
|
18
25
|
// counting as a transform (avoids a spurious broken-sourcemap warning).
|
|
19
26
|
handler() {
|
|
20
|
-
return { moduleSideEffects: 'no-treeshake'
|
|
27
|
+
return { moduleSideEffects: 'no-treeshake' }
|
|
21
28
|
}
|
|
22
29
|
}
|
|
23
30
|
}
|