@sentio/sdk 4.0.0-rc.2 → 4.0.0-rc.4

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.
@@ -2,30 +2,34 @@ import {
2
2
  type AccountConfig,
3
3
  type ContractConfig,
4
4
  type DataBinding,
5
+ type DBResponse,
5
6
  type Empty,
6
7
  EmptySchema,
7
- type PreprocessStreamRequest,
8
8
  type ProcessBindingResponse,
9
9
  ProcessBindingResponseSchema,
10
10
  ProcessBindingsRequestSchema,
11
11
  ProcessConfigRequestSchema,
12
12
  type ProcessConfigResponse,
13
+ type ProcessResult,
13
14
  type ProcessStreamRequest,
14
- ProcessStreamResponseSchema,
15
+ ProcessStreamRequestSchema,
16
+ ProcessStreamResponseV3Schema,
15
17
  StartRequestSchema,
16
18
  type TemplateInstance,
19
+ TemplateInstanceSchema,
17
20
  type TimeseriesResult,
18
21
  UpdateTemplatesRequestSchema
19
22
  } from '@sentio/protos'
20
23
  import { create, type MessageInitShape } from '@bufbuild/protobuf'
21
24
  import { type HandlerContext } from '@connectrpc/connect'
22
25
  import {
26
+ DataBindingContext,
23
27
  Endpoints,
24
28
  IDataBindingContext,
29
+ mergeProcessResults,
25
30
  PluginManager,
26
- ProcessorServiceImpl,
27
31
  State,
28
- StoreContext
32
+ ProcessorServiceImplV3
29
33
  } from '@sentio/runtime'
30
34
 
31
35
  import { AptosFacet } from './aptos-facet.js'
@@ -40,7 +44,7 @@ import { DatabaseSchemaState } from '../core/database-schema.js'
40
44
  import { IotaFacet } from './iota-facet.js'
41
45
  import { ChainInfo } from '@sentio/chain'
42
46
 
43
- type ProcessStreamResponseInit = MessageInitShape<typeof ProcessStreamResponseSchema>
47
+ type ProcessStreamResponseV3Init = MessageInitShape<typeof ProcessStreamResponseV3Schema>
44
48
 
45
49
  export const TEST_CONTEXT = {} as HandlerContext
46
50
 
@@ -52,10 +56,11 @@ export function cleanTest() {
52
56
  }
53
57
 
54
58
  export class TestProcessorServer {
55
- service: ProcessorServiceImpl
59
+ service: ProcessorServiceImplV3
56
60
  contractConfigs: ContractConfig[]
57
61
  accountConfigs: AccountConfig[]
58
62
  storeContext: TestStoreContext
63
+ private nextProcessId = 1
59
64
 
60
65
  aptos: AptosFacet
61
66
  eth: EthFacet
@@ -69,7 +74,7 @@ export class TestProcessorServer {
69
74
  constructor(loader: () => Promise<any>, httpEndpoints: Record<string, string> = {}) {
70
75
  cleanTest()
71
76
 
72
- this.service = new ProcessorServiceImpl(loader)
77
+ this.service = new ProcessorServiceImplV3(loader)
73
78
  this.aptos = new AptosFacet(this)
74
79
  this.solana = new SolanaFacet(this)
75
80
  this.eth = new EthFacet(this)
@@ -84,8 +89,8 @@ export class TestProcessorServer {
84
89
  }
85
90
 
86
91
  // start a memory database for testing
87
- const subject = new Subject<ProcessStreamResponseInit>()
88
- this.storeContext = new TestStoreContext(subject, 1)
92
+ const subject = new Subject<ProcessStreamResponseV3Init>()
93
+ this.storeContext = new TestStoreContext(subject, 1, this.service)
89
94
  this._db = new MemoryDatabase(this.storeContext)
90
95
  }
91
96
 
@@ -104,7 +109,8 @@ export class TestProcessorServer {
104
109
  }
105
110
 
106
111
  stop(request: Empty = create(EmptySchema), context = TEST_CONTEXT) {
107
- return this.service.stop(request, context)
112
+ this._db.stop()
113
+ return request
108
114
  }
109
115
 
110
116
  async getConfig(
@@ -121,43 +127,96 @@ export class TestProcessorServer {
121
127
  context: HandlerContext = TEST_CONTEXT
122
128
  ): Promise<ProcessBindingResponse> {
123
129
  const req = create(ProcessBindingsRequestSchema, request)
124
- return PluginManager.INSTANCE.dbContextLocalStorage.run(this.storeContext, async () => {
125
- const ret = await this.service.processBindings(req, context)
126
- if (ret.result?.states?.configUpdated) {
127
- // template may changed
130
+ return this.processBindingList(req.bindings, context)
131
+ }
132
+
133
+ async processBinding(request: DataBinding, context: HandlerContext = TEST_CONTEXT): Promise<ProcessBindingResponse> {
134
+ return this.processBindingList([request], context)
135
+ }
136
+
137
+ private async processBindingList(
138
+ bindings: DataBinding[],
139
+ context: HandlerContext = TEST_CONTEXT
140
+ ): Promise<ProcessBindingResponse> {
141
+ const results: ProcessResult[] = []
142
+ for (const binding of bindings) {
143
+ const result = await this.processBindingV3(binding, context)
144
+ results.push(result)
145
+
146
+ if (result.states?.configUpdated) {
128
147
  await PluginManager.INSTANCE.updateTemplates(
129
148
  create(UpdateTemplatesRequestSchema, {
130
- chainId: req.bindings[0].chainId,
149
+ chainId: binding.chainId,
131
150
  templateInstances: this.storeContext.templateInstances
132
151
  })
133
152
  )
134
153
  }
135
- return create(ProcessBindingResponseSchema, ret)
154
+ }
155
+ return create(ProcessBindingResponseSchema, {
156
+ result: mergeProcessResults(results)
136
157
  })
137
158
  }
138
159
 
139
- async processBinding(request: DataBinding, context: HandlerContext = TEST_CONTEXT): Promise<ProcessBindingResponse> {
140
- const ret = await PluginManager.INSTANCE.dbContextLocalStorage.run(this.storeContext, () => {
141
- return this.service.processBindings(create(ProcessBindingsRequestSchema, { bindings: [request] }), context)
142
- })
143
- if (ret.result?.states?.configUpdated) {
144
- // template may changed
145
- await PluginManager.INSTANCE.updateTemplates(
146
- create(UpdateTemplatesRequestSchema, {
147
- chainId: request.chainId,
148
- templateInstances: this.storeContext.templateInstances
149
- })
150
- )
151
- }
152
- return create(ProcessBindingResponseSchema, ret)
153
- }
160
+ private processBindingV3(request: DataBinding, context: HandlerContext): Promise<ProcessResult> {
161
+ const processId = this.nextProcessId++
162
+ const subject = this.storeContext.subject
154
163
 
155
- processBindingsStream(requests: AsyncIterable<ProcessStreamRequest>, context: HandlerContext): never {
156
- throw new Error('Method not implemented.')
164
+ return new Promise((resolve, reject) => {
165
+ const subscription = subject.subscribe({
166
+ next: (response) => {
167
+ if (response.processId !== processId) {
168
+ return
169
+ }
170
+ if (response.value?.case === 'tplRequest') {
171
+ this.storeContext.applyTemplateRequest(
172
+ (response.value.value.templates ?? []).map((template) => create(TemplateInstanceSchema, template)),
173
+ response.value.value.remove ?? false
174
+ )
175
+ }
176
+ if (response.value?.case === 'result') {
177
+ subscription.unsubscribe()
178
+ // The service always emits a fully-formed ProcessResult message here; use it directly.
179
+ // Do NOT re-`create(ProcessResultSchema, ...)` — that re-validates every field and throws
180
+ // on results carrying loosely-typed values (e.g. a hex string in an int32 field), which
181
+ // the old unary processBindings path passed through untouched.
182
+ const result = response.value.value as ProcessResult
183
+ // The V3 service reports handler failures as a result with `states.error` set (via
184
+ // DataBindingContext.error) rather than erroring the stream. Surface it as a thrown
185
+ // error so tests observe the same behavior as the old unary processBindings path.
186
+ if (result.states?.error) {
187
+ reject(new Error(result.states.error))
188
+ } else {
189
+ resolve(result)
190
+ }
191
+ }
192
+ },
193
+ error: (e) => {
194
+ subscription.unsubscribe()
195
+ reject(e)
196
+ }
197
+ })
198
+
199
+ this.service
200
+ .handleRequest(
201
+ create(ProcessStreamRequestSchema, {
202
+ processId,
203
+ value: {
204
+ case: 'binding',
205
+ value: request
206
+ }
207
+ }),
208
+ undefined,
209
+ subject
210
+ )
211
+ .catch((e) => {
212
+ subscription.unsubscribe()
213
+ reject(e)
214
+ })
215
+ })
157
216
  }
158
217
 
159
- preprocessBindingsStream(requests: AsyncIterable<PreprocessStreamRequest>, context: HandlerContext): never {
160
- throw new Error('Method not implemented.')
218
+ processBindingsStream(requests: AsyncIterable<ProcessStreamRequest>, context: HandlerContext) {
219
+ return this.service.processBindingsStream(requests, context)
161
220
  }
162
221
 
163
222
  // processBindingsStream(request: AsyncIterable<ProcessStreamRequest>, context: HandlerContext) {
@@ -172,17 +231,37 @@ export class TestProcessorServer {
172
231
  }
173
232
  }
174
233
 
175
- class TestStoreContext extends StoreContext implements IDataBindingContext {
234
+ class TestStoreContext extends DataBindingContext implements IDataBindingContext {
176
235
  constructor(
177
- readonly subject: Subject<ProcessStreamResponseInit>,
178
- processId: number
236
+ subject: Subject<ProcessStreamResponseV3Init>,
237
+ processId: number,
238
+ private readonly service: ProcessorServiceImplV3
179
239
  ) {
180
- super(subject, processId)
240
+ super(processId, subject)
181
241
  }
182
242
 
183
243
  templateInstances: TemplateInstance[] = []
184
244
 
185
- sendTemplateRequest(templates: Array<TemplateInstance>, remove: boolean): void {
245
+ result(dbResult: DBResponse, processId = this.processId): void {
246
+ // Resolve a request issued directly from this context (e.g. `service.store.get(...)` in a test,
247
+ // which goes through the TestStoreContext rather than a per-binding context). opIds are globally
248
+ // unique, so this is a no-op when the request originated from the service's per-binding context.
249
+ super.result(dbResult)
250
+ // Forward to the service's per-binding context for requests issued while processing a binding.
251
+ void this.service.handleRequest(
252
+ create(ProcessStreamRequestSchema, {
253
+ processId,
254
+ value: {
255
+ case: 'dbResult',
256
+ value: dbResult
257
+ }
258
+ }),
259
+ undefined,
260
+ this.subject
261
+ )
262
+ }
263
+
264
+ applyTemplateRequest(templates: Array<TemplateInstance>, remove: boolean): void {
186
265
  if (remove) {
187
266
  this.templateInstances = this.templateInstances.filter(
188
267
  (i) => !templates.find((t) => t.templateId === i.templateId && t.contract?.address === i.contract?.address)
@@ -191,7 +270,12 @@ class TestStoreContext extends StoreContext implements IDataBindingContext {
191
270
  this.templateInstances.push(...templates)
192
271
  }
193
272
  }
273
+
274
+ sendTemplateRequest(templates: Array<TemplateInstance>, remove: boolean): void {
275
+ this.applyTemplateRequest(templates, remove)
276
+ }
277
+
194
278
  sendTimeseriesRequest(timeseries: Array<TimeseriesResult>): void {
195
- throw new Error('Method not implemented.')
279
+ // Test helpers currently expose metric/event/export results through ProcessResult.
196
280
  }
197
281
  }