@sentio/sdk 2.39.4-rc.8 → 2.39.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.
Files changed (37) hide show
  1. package/lib/eth/builtin/internal/eacaggregatorproxy-processor.d.ts.map +1 -1
  2. package/lib/eth/builtin/internal/erc1155-processor.d.ts.map +1 -1
  3. package/lib/eth/builtin/internal/erc20-processor.d.ts.map +1 -1
  4. package/lib/eth/builtin/internal/erc20bytes-processor.d.ts.map +1 -1
  5. package/lib/eth/builtin/internal/erc721-processor.d.ts.map +1 -1
  6. package/lib/eth/builtin/internal/weth9-processor.d.ts.map +1 -1
  7. package/lib/fuel/context.d.ts.map +1 -1
  8. package/lib/solana/solana-processor.d.ts +0 -1
  9. package/lib/solana/solana-processor.d.ts.map +1 -1
  10. package/lib/store/codegen.js +3 -3
  11. package/lib/store/codegen.js.map +1 -1
  12. package/lib/store/decorators.d.ts +1 -1
  13. package/lib/store/decorators.d.ts.map +1 -1
  14. package/lib/store/decorators.js +61 -60
  15. package/lib/store/decorators.js.map +1 -1
  16. package/lib/store/schema.d.ts.map +1 -1
  17. package/lib/store/schema.js +38 -0
  18. package/lib/store/schema.js.map +1 -1
  19. package/lib/store/store.d.ts +3 -1
  20. package/lib/store/store.d.ts.map +1 -1
  21. package/lib/store/store.js +38 -13
  22. package/lib/store/store.js.map +1 -1
  23. package/lib/store/types.d.ts +2 -20
  24. package/lib/store/types.d.ts.map +1 -1
  25. package/lib/store/types.js +1 -14
  26. package/lib/store/types.js.map +1 -1
  27. package/lib/utils/price.d.ts +30 -30
  28. package/lib/utils/price.d.ts.map +1 -1
  29. package/lib/utils/price.js +5 -4
  30. package/lib/utils/price.js.map +1 -1
  31. package/package.json +4 -4
  32. package/src/store/codegen.ts +3 -3
  33. package/src/store/decorators.ts +66 -62
  34. package/src/store/schema.ts +40 -0
  35. package/src/store/store.ts +43 -15
  36. package/src/store/types.ts +2 -23
  37. package/src/utils/price.ts +6 -4
@@ -15,8 +15,8 @@ import {
15
15
  TypeConverters,
16
16
  ValueConverter
17
17
  } from './convert.js'
18
- import { getStore } from './store.js'
19
18
  import { RichStruct } from '@sentio/protos'
19
+ import { getStore } from './store.js'
20
20
 
21
21
  type Constructor = { new (...args: any[]): any }
22
22
 
@@ -28,73 +28,77 @@ function handleError(entity: string, key: string, fn: () => any) {
28
28
  }
29
29
  }
30
30
 
31
- export function Entity(name: string) {
31
+ export function Entity(entityName: string) {
32
32
  return function <T extends Constructor>(BaseClass: T) {
33
- return class extends BaseClass {
34
- static entityName = name
35
- readonly _data: RichStruct = { fields: {}, entityName: name }
33
+ const meta: Record<string, ValueConverter<any>> = (BaseClass as any).meta || {}
34
+ const target = BaseClass.prototype
35
+ for (const [propertyKey, type] of Object.entries(meta)) {
36
+ if (type.isRelation && type.relationName) {
37
+ const relationName = type.relationName
38
+ const idGetter = function (this: any) {
39
+ return handleError(this.constructor.entityName, propertyKey, () => type!.to(this._data.fields[propertyKey]))
40
+ }
41
+ const idSetter = function (this: any, value: any) {
42
+ this._data.fields[propertyKey] = handleError(this.constructor.entityName, propertyKey, () =>
43
+ type!.from(value)
44
+ )
45
+ }
46
+ const idKey = type.isArray ? propertyKey + 'IDs' : propertyKey + 'ID'
36
47
 
37
- constructor(...args: any[]) {
38
- super()
39
- const meta = (BaseClass as any).meta
40
- for (const [propertyKey, t] of Object.entries(meta)) {
41
- const converter = t as ValueConverter<any>
42
- if (converter.isRelation && converter.relationName) {
43
- const relationName = converter.relationName
44
- const idGetter = () => {
45
- return handleError(name, propertyKey, () => converter.to(this._data.fields[propertyKey]))
48
+ Reflect.defineProperty(target, idKey, {
49
+ get: idGetter,
50
+ set: idSetter
51
+ })
52
+ Reflect.defineProperty(target, propertyKey, {
53
+ get: function () {
54
+ const ids = idGetter.call(this)
55
+ if (Array.isArray(ids)) {
56
+ return Promise.all(
57
+ ids.map((id) => {
58
+ return getStore()?.get(relationName, id)
59
+ })
60
+ )
61
+ } else {
62
+ return getStore()?.get(relationName, ids)
46
63
  }
47
- const idSetter = (value: any) => {
48
- this._data.fields[propertyKey] = handleError(name, propertyKey, () => converter.from(value))
64
+ },
65
+ set: function (value) {
66
+ if (value instanceof Promise) {
67
+ value.then((v) => {
68
+ idSetter.call(this, v)
69
+ })
70
+ } else {
71
+ idSetter.call(this, value)
49
72
  }
50
- const idKey = converter.isArray ? propertyKey + 'IDs' : propertyKey + 'ID'
51
-
52
- Object.defineProperty(this, idKey, {
53
- get: idGetter,
54
- set: idSetter
55
- })
56
-
57
- Object.defineProperty(this, propertyKey, {
58
- get: () => {
59
- const ids = idGetter()
60
- if (Array.isArray(ids)) {
61
- return Promise.all(
62
- ids.map((id) => {
63
- return getStore()?.get(relationName, id)
64
- })
65
- )
66
- } else {
67
- return getStore()?.get(relationName, ids)
68
- }
69
- },
70
- set: (value) => {
71
- if (value instanceof Promise) {
72
- value.then((v) => {
73
- idSetter(v)
74
- })
75
- } else {
76
- idSetter(value)
77
- }
78
- }
79
- })
80
- } else {
81
- Object.defineProperty(this, propertyKey, {
82
- get: () => {
83
- return handleError(name, propertyKey, () => converter.to(this._data.fields[propertyKey]))
84
- },
85
- set: (value) => {
86
- this._data.fields[propertyKey] = handleError(name, propertyKey, () => converter.from(value))
87
- }
88
- })
89
73
  }
90
- const initData = args[0]
91
- if (initData) {
92
- for (const [key, value] of Object.entries(initData)) {
93
- if (this.hasOwnProperty(key)) {
94
- this[key] = value
95
- }
96
- }
74
+ })
75
+ } else {
76
+ Reflect.defineProperty(target, propertyKey, {
77
+ configurable: true,
78
+ get: function () {
79
+ return handleError(this.constructor.entityName, propertyKey, () => type!.to(this._data.fields[propertyKey]))
80
+ },
81
+ set: function (value) {
82
+ this._data.fields[propertyKey] = handleError(this.constructor.entityName, propertyKey, () =>
83
+ type!.from(value)
84
+ )
97
85
  }
86
+ })
87
+ }
88
+ }
89
+
90
+ return class extends BaseClass {
91
+ readonly _data: RichStruct = { fields: {} }
92
+ static entityName = entityName
93
+ constructor(...args: any[]) {
94
+ super()
95
+ for (const key of Object.getOwnPropertyNames(this)) {
96
+ if (BaseClass.prototype.hasOwnProperty(key)) {
97
+ delete this[key]
98
+ }
99
+ }
100
+ if (args[0]) {
101
+ Object.assign(this, args[0])
98
102
  }
99
103
  }
100
104
  }
@@ -1,5 +1,6 @@
1
1
  import { buildASTSchema, DocumentNode, extendSchema, GraphQLSchema, parse, validateSchema } from 'graphql/index.js'
2
2
  import * as fs from 'node:fs'
3
+ import { GraphQLObjectType, GraphQLOutputType, isListType, isNonNullType } from 'graphql'
3
4
 
4
5
  const customScalars = ['BigInt', 'BigDecimal', 'Timestamp', 'JSON', 'Bytes', 'ID']
5
6
 
@@ -19,12 +20,51 @@ const baseSchema = buildASTSchema(
19
20
  `)
20
21
  )
21
22
 
23
+ function getElemType(type: GraphQLOutputType) {
24
+ if (isNonNullType(type)) {
25
+ return getElemType(type.ofType)
26
+ }
27
+ if (isListType(type)) {
28
+ return getElemType(type.ofType)
29
+ }
30
+ return type
31
+ }
32
+
33
+ function checkRelations(schema: GraphQLSchema) {
34
+ for (const t of Object.values(schema.getTypeMap())) {
35
+ if (t.name.startsWith('__')) {
36
+ continue
37
+ }
38
+ if (t instanceof GraphQLObjectType) {
39
+ for (const f of Object.values(t.getFields())) {
40
+ if (f.astNode) {
41
+ for (const d of f.astNode.directives ?? []) {
42
+ if (d.name.value === 'derivedFrom') {
43
+ const arg = (d.arguments ?? []).find((a) => a.name.value === 'field')
44
+ if (!arg || !arg.value || arg.value.kind !== 'StringValue') {
45
+ throw new Error(`@derivedFrom directive must have a 'field' argument`)
46
+ }
47
+ const fieldName = arg.value.value
48
+ const targetType = getElemType(f.type) as GraphQLObjectType
49
+ // Check if the target type has a field with the same name
50
+ if (!targetType.getFields()[fieldName]) {
51
+ throw new Error(`Field '${fieldName}' not found in type '${targetType.name}'`)
52
+ }
53
+ }
54
+ }
55
+ }
56
+ }
57
+ }
58
+ }
59
+ }
60
+
22
61
  export function buildSchema(doc: DocumentNode): GraphQLSchema {
23
62
  const schema = extendSchema(baseSchema, doc)
24
63
  const errors = validateSchema(schema).filter((err) => !/query root/i.test(err.message))
25
64
  if (errors.length > 0) {
26
65
  throw errors[0]
27
66
  }
67
+ checkRelations(schema)
28
68
  return schema
29
69
  }
30
70
 
@@ -2,7 +2,7 @@ import { StoreContext } from './context.js'
2
2
  import { DatabaseSchema } from '../core/index.js'
3
3
  import { BigDecimal } from '@sentio/bigdecimal'
4
4
  import { Bytes, Float, ID, Int, Timestamp } from './types.js'
5
- import type { RichStruct, RichValue } from '@sentio/protos'
5
+ import type { Entity as EntityStruct, RichValue } from '@sentio/protos'
6
6
  import { DBRequest_DBOperator, DBResponse } from '@sentio/protos'
7
7
  import { toBigInteger } from './convert.js'
8
8
  import { PluginManager } from '@sentio/runtime'
@@ -17,20 +17,36 @@ export interface EntityClass<T> {
17
17
  new (data: Partial<T>): T
18
18
  }
19
19
 
20
+ function getEntityName<T>(entity: EntityClass<T> | T | string): string {
21
+ if (entity == null) {
22
+ throw new Error("can't figure out entityName from undefined")
23
+ }
24
+ if (typeof entity == 'string') {
25
+ return entity
26
+ }
27
+ if (typeof entity == 'function') {
28
+ return (entity as any).entityName
29
+ }
30
+ if (typeof entity == 'object') {
31
+ return (entity.constructor as any).entityName
32
+ }
33
+ throw new Error(`can't figure out entityName from ${typeof entity}`)
34
+ }
35
+
20
36
  export class Store {
21
37
  constructor(private readonly context: StoreContext) {}
22
38
 
23
39
  async get<T extends Entity>(entity: EntityClass<T> | string, id: ID): Promise<T | undefined> {
24
40
  const promise = this.context.sendRequest({
25
41
  get: {
26
- entity: typeof entity == 'string' ? entity : entity.prototype.entityName,
42
+ entity: getEntityName(entity),
27
43
  id: id.toString()
28
44
  }
29
45
  })
30
46
 
31
47
  const data = (await promise) as DBResponse
32
- if (data.entities?.entities[0]) {
33
- const entityData = data.entities.entities[0]
48
+ if (data.entityList?.entities[0]) {
49
+ const entityData = data.entityList?.entities[0]
34
50
  return this.newEntity(entity, entityData)
35
51
  }
36
52
 
@@ -45,18 +61,17 @@ export class Store {
45
61
  if (id) {
46
62
  if (Array.isArray(id)) {
47
63
  for (const i of id) {
48
- const items = (entity as any).prototype.entityName
49
- request.entity.push(items)
64
+ request.entity.push(getEntityName(entity))
50
65
  request.id.push(i.toString())
51
66
  }
52
67
  } else {
53
- request.entity.push((entity as any).prototype.entityName)
68
+ request.entity.push(getEntityName(entity))
54
69
  request.id.push(id)
55
70
  }
56
71
  } else {
57
72
  const entities = Array.isArray(entity) ? entity : [entity]
58
73
  for (const e of entities) {
59
- request.entity.push(e.constructor.prototype.entityName)
74
+ request.entity.push(getEntityName(entity))
60
75
  request.id.push((e as Entity).id.toString())
61
76
  }
62
77
  }
@@ -70,7 +85,7 @@ export class Store {
70
85
  const entities = Array.isArray(entity) ? entity : [entity]
71
86
  const promise = this.context.sendRequest({
72
87
  upsert: {
73
- entity: entities.map((e) => e.constructor.prototype.entityName),
88
+ entity: entities.map((e) => getEntityName(e)),
74
89
  // data: entities.map((e) => serialize(e.data)),
75
90
  id: entities.map((e) => e.id.toString()),
76
91
  entityData: entities.map((e: any) => e._data)
@@ -80,13 +95,13 @@ export class Store {
80
95
  await promise
81
96
  }
82
97
 
83
- async *list<T extends Entity>(entity: EntityClass<T>, filters?: ListFilter<T>[]) {
98
+ async *listIterator<T extends Entity>(entity: EntityClass<T>, filters?: ListFilter<T>[]) {
84
99
  let cursor: string | undefined = undefined
85
100
 
86
101
  while (true) {
87
102
  const promise = this.context.sendRequest({
88
103
  list: {
89
- entity: entity.prototype.entityName,
104
+ entity: getEntityName(entity),
90
105
  cursor,
91
106
  filters:
92
107
  filters?.map((f) => ({
@@ -97,7 +112,7 @@ export class Store {
97
112
  }
98
113
  })
99
114
  const response = (await promise) as DBResponse
100
- for (const data of response.entities?.entities || []) {
115
+ for (const data of response.entityList?.entities || []) {
101
116
  yield this.newEntity(entity, data)
102
117
  }
103
118
  if (!response.nextCursor) {
@@ -107,12 +122,25 @@ export class Store {
107
122
  }
108
123
  }
109
124
 
110
- private newEntity<T extends Entity>(entity: EntityClass<T> | string, data: RichStruct) {
125
+ async list<T extends Entity>(entity: EntityClass<T>, filters?: ListFilter<T>[]) {
126
+ // TODO Array.fromAsync when upgrade to node 22
127
+ return this.fromAsync(this.listIterator(entity, filters))
128
+ }
129
+
130
+ private async fromAsync<T>(gen: AsyncIterable<T>): Promise<T[]> {
131
+ const out: T[] = []
132
+ for await (const x of gen) {
133
+ out.push(x)
134
+ }
135
+ return out
136
+ }
137
+
138
+ private newEntity<T extends Entity>(entity: EntityClass<T> | string, data: EntityStruct) {
111
139
  if (typeof entity == 'string') {
112
140
  let en = DatabaseSchema.findEntity(entity)
113
141
  if (!en) {
114
142
  // it is an interface
115
- en = DatabaseSchema.findEntity(data.entityName)
143
+ en = DatabaseSchema.findEntity(data.entity)
116
144
  if (!en) {
117
145
  throw new Error(`Entity ${entity} not found`)
118
146
  }
@@ -121,7 +149,7 @@ export class Store {
121
149
  }
122
150
 
123
151
  const res = new (entity as EntityClass<T>)({}) as T
124
- ;(res as any)._data = data
152
+ ;(res as any)._data = data.data
125
153
  return res
126
154
  }
127
155
  }
@@ -1,29 +1,8 @@
1
- export type ID = (string | Uint8Array) & { __id__?: void }
1
+ export type ID = string | Uint8Array
2
2
  export type String = string
3
- export type Int = number & { __int__?: void }
3
+ export type Int = number
4
4
  export type Float = number
5
5
  export type Boolean = boolean
6
6
  export type Timestamp = Date
7
7
  export type Bytes = Uint8Array
8
8
  export type BigInt = bigint
9
-
10
- export class Struct<T = unknown, S = unknown> {
11
- readonly TYPE!: T
12
- constructor(readonly schema: S) {}
13
- }
14
- export type Infer<T extends Struct<any>> = T['TYPE']
15
- export type ObjectSchema = Record<string, Struct<any, any>>
16
-
17
- export function object<S extends ObjectSchema>(schema: S): Struct<ObjectType<S>, S> {
18
- return new Struct(schema ?? null)
19
- }
20
-
21
- export type Simplify<T> = T extends any[] | Date ? T : { [K in keyof T]: T[K] } & NonNullable<unknown>
22
-
23
- export type ObjectType<S extends ObjectSchema> = Simplify<{ [K in keyof S]: Infer<S[K]> }>
24
-
25
- const StringStruct = new Struct<string, null>(null)
26
-
27
- const UU = object({
28
- test: StringStruct
29
- })
@@ -88,10 +88,12 @@ export async function getPriceByTypeOrSymbolInternal(
88
88
  return res.price
89
89
  })
90
90
  .catch((e) => {
91
- if (e.code === Status.NOT_FOUND) {
92
- setTimeout(() => {
93
- priceMap.delete(key)
94
- }, 1000)
91
+ setTimeout(() => {
92
+ priceMap.delete(key)
93
+ }, 1000)
94
+
95
+ if (e.code === Status.NOT_FOUND || e.code === Status.UNKNOWN) {
96
+ console.error('price not found for ', JSON.stringify(coinId), ' at ', dateStr)
95
97
  return undefined
96
98
  }
97
99
  // TODO maybe use small set of error