@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.
Files changed (35) hide show
  1. package/dist/core/base-context.d.ts.map +1 -1
  2. package/dist/core/base-context.js +0 -3
  3. package/dist/core/base-context.js.map +1 -1
  4. package/dist/core/event-logger.d.ts.map +1 -1
  5. package/dist/core/event-logger.js +3 -16
  6. package/dist/core/event-logger.js.map +1 -1
  7. package/dist/core/meter.d.ts.map +1 -1
  8. package/dist/core/meter.js +1 -18
  9. package/dist/core/meter.js.map +1 -1
  10. package/dist/core/normalization.d.ts +0 -3
  11. package/dist/core/normalization.d.ts.map +1 -1
  12. package/dist/core/normalization.js +0 -61
  13. package/dist/core/normalization.js.map +1 -1
  14. package/dist/testing/index.d.ts +1 -1
  15. package/dist/testing/index.d.ts.map +1 -1
  16. package/dist/testing/index.js +1 -1
  17. package/dist/testing/index.js.map +1 -1
  18. package/dist/testing/metric-utils.d.ts +6 -1
  19. package/dist/testing/metric-utils.d.ts.map +1 -1
  20. package/dist/testing/metric-utils.js +111 -11
  21. package/dist/testing/metric-utils.js.map +1 -1
  22. package/dist/testing/test-processor-server.d.ts +0 -309
  23. package/dist/testing/test-processor-server.d.ts.map +1 -1
  24. package/dist/testing/test-processor-server.js +8 -0
  25. package/dist/testing/test-processor-server.js.map +1 -1
  26. package/dist/{tsdown.config.ts → tsdown.config.js} +8 -1
  27. package/package.json +4 -4
  28. package/src/core/base-context.ts +0 -3
  29. package/src/core/event-logger.ts +2 -18
  30. package/src/core/meter.ts +1 -18
  31. package/src/core/normalization.ts +0 -65
  32. package/src/testing/index.ts +10 -1
  33. package/src/testing/metric-utils.ts +126 -12
  34. package/src/testing/test-processor-server.ts +8 -0
  35. package/src/{tsdown.config.ts → tsdown.config.js} +8 -1
@@ -1,5 +1,14 @@
1
1
  export { TestProcessorServer } from './test-processor-server.js'
2
- export { MetricValueToNumber, firstCounterValue, firstGaugeValue } from './metric-utils.js'
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
- export function firstCounterValue(result: ProcessResult | undefined, name: string): Numberish | undefined {
28
- if (!result) {
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
- for (const counter of result.counters) {
32
- if (counter.metadata?.name === name) {
33
- return MetricValueToNumber(counter.metricValue)
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
- export function firstGaugeValue(result: ProcessResult | undefined, name: string): Numberish | undefined {
40
- if (!result) {
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
- for (const gauge of result.gauges) {
44
- if (gauge.metadata?.name === name) {
45
- return MetricValueToNumber(gauge.metricValue)
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' as const }
27
+ return { moduleSideEffects: 'no-treeshake' }
21
28
  }
22
29
  }
23
30
  }