@sentio/sdk 2.36.1 → 2.37.0-rc.2

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 (74) hide show
  1. package/lib/core/base-context.d.ts +4 -0
  2. package/lib/core/base-context.d.ts.map +1 -1
  3. package/lib/core/base-context.js +20 -4
  4. package/lib/core/base-context.js.map +1 -1
  5. package/lib/core/core-plugin.d.ts.map +1 -1
  6. package/lib/core/core-plugin.js +6 -0
  7. package/lib/core/core-plugin.js.map +1 -1
  8. package/lib/core/database-schema.d.ts +8 -0
  9. package/lib/core/database-schema.d.ts.map +1 -0
  10. package/lib/core/database-schema.js +10 -0
  11. package/lib/core/database-schema.js.map +1 -0
  12. package/lib/core/index.d.ts +1 -0
  13. package/lib/core/index.d.ts.map +1 -1
  14. package/lib/core/index.js +1 -0
  15. package/lib/core/index.js.map +1 -1
  16. package/lib/fuel/fuel-processor.d.ts.map +1 -1
  17. package/lib/fuel/fuel-processor.js +51 -23
  18. package/lib/fuel/fuel-processor.js.map +1 -1
  19. package/lib/store/codegen.d.ts +4 -0
  20. package/lib/store/codegen.d.ts.map +1 -0
  21. package/lib/store/codegen.js +180 -0
  22. package/lib/store/codegen.js.map +1 -0
  23. package/lib/store/context.d.ts +2 -0
  24. package/lib/store/context.d.ts.map +1 -0
  25. package/lib/store/context.js +2 -0
  26. package/lib/store/context.js.map +1 -0
  27. package/lib/store/decorators.d.ts +7 -0
  28. package/lib/store/decorators.d.ts.map +1 -0
  29. package/lib/store/decorators.js +7 -0
  30. package/lib/store/decorators.js.map +1 -0
  31. package/lib/store/entity.d.ts +18 -0
  32. package/lib/store/entity.d.ts.map +1 -0
  33. package/lib/store/entity.js +51 -0
  34. package/lib/store/entity.js.map +1 -0
  35. package/lib/store/index.d.ts +6 -0
  36. package/lib/store/index.d.ts.map +1 -0
  37. package/lib/store/index.js +6 -0
  38. package/lib/store/index.js.map +1 -0
  39. package/lib/store/run.d.ts +2 -0
  40. package/lib/store/run.d.ts.map +1 -0
  41. package/lib/store/run.js +11 -0
  42. package/lib/store/run.js.map +1 -0
  43. package/lib/store/schema.d.ts +7 -0
  44. package/lib/store/schema.d.ts.map +1 -0
  45. package/lib/store/schema.js +30 -0
  46. package/lib/store/schema.js.map +1 -0
  47. package/lib/store/store.d.ts +12 -0
  48. package/lib/store/store.d.ts.map +1 -0
  49. package/lib/store/store.js +61 -0
  50. package/lib/store/store.js.map +1 -0
  51. package/lib/store/types.d.ts +10 -0
  52. package/lib/store/types.d.ts.map +1 -0
  53. package/lib/store/types.js +2 -0
  54. package/lib/store/types.js.map +1 -0
  55. package/lib/testing/test-processor-server.d.ts +2 -5
  56. package/lib/testing/test-processor-server.d.ts.map +1 -1
  57. package/lib/testing/test-processor-server.js +2 -2
  58. package/lib/testing/test-processor-server.js.map +1 -1
  59. package/package.json +8 -5
  60. package/src/core/base-context.ts +22 -4
  61. package/src/core/core-plugin.ts +7 -0
  62. package/src/core/database-schema.ts +11 -0
  63. package/src/core/index.ts +1 -0
  64. package/src/fuel/fuel-processor.ts +64 -39
  65. package/src/store/codegen.ts +213 -0
  66. package/src/store/context.ts +1 -0
  67. package/src/store/decorators.ts +9 -0
  68. package/src/store/entity.ts +61 -0
  69. package/src/store/index.ts +5 -0
  70. package/src/store/run.ts +10 -0
  71. package/src/store/schema.ts +35 -0
  72. package/src/store/store.ts +68 -0
  73. package/src/store/types.ts +10 -0
  74. package/src/testing/test-processor-server.ts +13 -2
@@ -0,0 +1,213 @@
1
+ import {
2
+ DirectiveNode,
3
+ GraphQLEnumType,
4
+ GraphQLField,
5
+ GraphQLInterfaceType,
6
+ GraphQLList,
7
+ GraphQLNonNull,
8
+ GraphQLObjectType,
9
+ GraphQLOutputType,
10
+ GraphQLScalarType,
11
+ GraphQLSchema,
12
+ Kind,
13
+ isObjectType,
14
+ isInterfaceType,
15
+ isListType
16
+ } from 'graphql'
17
+ import * as fs from 'node:fs'
18
+ import path from 'path'
19
+ import mkdirp from 'mkdirp'
20
+ import { schemaFromFile } from './schema.js'
21
+ import chalk from 'chalk'
22
+
23
+ export async function codegen(srcDir: string, outputDir: string) {
24
+ for (const file of fs.readdirSync(srcDir)) {
25
+ const f = path.join(srcDir, file)
26
+ const filePath = path.parse(f)
27
+ if (filePath.ext == '.graphql') {
28
+ const { schema, source } = schemaFromFile(f)
29
+ const target = path.join(outputDir, filePath.name + '.ts')
30
+ await codegenInternal(schema, source, target)
31
+ console.log(chalk.green(`Generated ${target}`))
32
+ }
33
+ }
34
+ }
35
+
36
+ async function codegenInternal(schema: GraphQLSchema, source: string, target: string) {
37
+ const results: string[] = [
38
+ '/* Autogenerated file. Do not edit manually. */\n',
39
+ '/* tslint:disable */',
40
+ '/* eslint-disable */',
41
+ "import {entity, derivedFrom, BigDecimal, DateTime, Json, Bytes, ID, Entity, Store} from '@sentio/sdk/store'",
42
+ `import { DatabaseSchema } from "@sentio/sdk"`
43
+ ]
44
+
45
+ for (const t of Object.values(schema.getTypeMap())) {
46
+ if (t.name.startsWith('__')) {
47
+ continue
48
+ }
49
+
50
+ if (t instanceof GraphQLObjectType) {
51
+ const entityContent = genEntity(t)
52
+ results.push(entityContent)
53
+ }
54
+ if (t instanceof GraphQLEnumType) {
55
+ results.push(genEnum(t))
56
+ }
57
+ if (t instanceof GraphQLInterfaceType) {
58
+ results.push(genInterface(t))
59
+ }
60
+ }
61
+
62
+ const contents =
63
+ results.join('\n') +
64
+ `\n
65
+ const source = \`${source.replaceAll('`', '`')}\`
66
+ DatabaseSchema.register(source)
67
+ `
68
+ await mkdirp(path.dirname(target))
69
+
70
+ fs.writeFileSync(target, contents)
71
+ }
72
+
73
+ const JsTypes: Record<string, string> = {
74
+ ID: 'string',
75
+ String: 'string',
76
+ Int: 'number',
77
+ Float: 'number',
78
+ Boolean: 'boolean',
79
+ BigInt: 'bigint',
80
+ BigDecimal: 'BigDecimal',
81
+ DateTime: 'Date',
82
+ Json: 'any',
83
+ Bytes: 'Uint8Array'
84
+ }
85
+ const graphqlTypes = Object.entries(JsTypes).reduce(
86
+ (acc, [k, v]) => {
87
+ acc[v] = k
88
+ return acc
89
+ },
90
+ {} as Record<string, string>
91
+ )
92
+
93
+ function genType(type: GraphQLOutputType): string {
94
+ if (type instanceof GraphQLNonNull) {
95
+ return genType(type.ofType)
96
+ } else if (type instanceof GraphQLScalarType) {
97
+ return type.name
98
+ } else if (type instanceof GraphQLObjectType || type instanceof GraphQLInterfaceType) {
99
+ return type.name
100
+ } else if (type instanceof GraphQLList) {
101
+ return `Array<${genType(type.ofType)}>`
102
+ } else if (type instanceof GraphQLEnumType) {
103
+ return type.name
104
+ } else {
105
+ throw new Error('Unsupported type: ' + type)
106
+ }
107
+ }
108
+
109
+ function isObject(type: GraphQLOutputType) {
110
+ if (type instanceof GraphQLNonNull) {
111
+ return isObject(type.ofType)
112
+ } else if (type instanceof GraphQLList) {
113
+ return isObject(type.ofType)
114
+ }
115
+ return isObjectType(type) || isInterfaceType(type)
116
+ }
117
+
118
+ function isList(type: GraphQLOutputType) {
119
+ if (type instanceof GraphQLNonNull) {
120
+ return isListType(type.ofType)
121
+ } else {
122
+ return isListType(type)
123
+ }
124
+ }
125
+
126
+ function getElementType(type: GraphQLOutputType) {
127
+ if (type instanceof GraphQLNonNull) {
128
+ return getElementType(type.ofType)
129
+ } else if (type instanceof GraphQLList) {
130
+ return type.ofType
131
+ }
132
+ return type
133
+ }
134
+
135
+ function genField(field: GraphQLField<any, any>) {
136
+ const isNonNull = field.type instanceof GraphQLNonNull
137
+ const directives = field.astNode?.directives?.map((d) => '\t' + directive2decorator(d) + '\n') || []
138
+
139
+ const type = genType(field.type)
140
+ const returnType = isNonNull ? type : `${type} | undefined`
141
+
142
+ if (isObject(field.type)) {
143
+ const t = getElementType(field.type)
144
+ const typeAsArg = isInterfaceType(t) ? `"${t}"` : genType(t)
145
+
146
+ if (isList(field.type)) {
147
+ return `${directives.join()}\tget ${field.name}(): Promise<${genType(t)}[]> { return this.getFieldObjectArray(${typeAsArg}, "${field.name}") as Promise<${genType(t)}[]> }
148
+ set ${field.name}(value: Array<${type}> | ID[]) { this.set("${field.name}", value) }
149
+ get ${field.name}Ids(): ID[] { return this.get("${field.name}") }`
150
+ }
151
+
152
+ return `${directives.join()}\tget ${field.name}(): Promise<${genType(t)} | undefined> { return this.getFieldObject(${typeAsArg},"${field.name}") as Promise<${genType(t)} | undefined> }
153
+ set ${field.name}(value: ${type} | ID) { this.set("${field.name}", value) }
154
+ get ${field.name}Id(): ID | undefined { return this.get("${field.name}") }`
155
+ }
156
+
157
+ return `${directives.join()}\tget ${field.name}(): ${returnType} { return this.get("${field.name}") }
158
+ set ${field.name}(value: ${type}) { this.set("${field.name}", value) }`
159
+ }
160
+
161
+ function genEntity(t: GraphQLObjectType<any, any>) {
162
+ const decorators = t.astNode?.directives?.map(directive2decorator) || []
163
+
164
+ let impls = ''
165
+ if (t.getInterfaces().length > 0) {
166
+ impls +=
167
+ ' implements ' +
168
+ t
169
+ .getInterfaces()
170
+ .map((i) => i.name)
171
+ .join(', ')
172
+ }
173
+
174
+ return `
175
+ ${decorators.join('\n')}
176
+ export class ${t.name} extends Entity${impls} {
177
+ constructor(data: Partial<${t.name}>) {
178
+ super(data)
179
+ }
180
+ ${Object.values(t.getFields()).map(genField).join('\n')}
181
+ }`
182
+ }
183
+
184
+ function genInterface(t: GraphQLInterfaceType) {
185
+ return `
186
+ export interface ${t.name} {
187
+ ${Object.values(t.getFields())
188
+ .map((f) => `\t${f.name}: ${genType(f.type)}`)
189
+ .join('\n')}
190
+ }`
191
+ }
192
+
193
+ export function directive2decorator(directive: DirectiveNode) {
194
+ let s = `@${directive.name.value}`
195
+ if (directive.arguments?.length) {
196
+ s += `(${directive.arguments
197
+ ?.map((arg) => {
198
+ return arg.value.kind === Kind.STRING ? `"${arg.value.value}"` : `${arg.value}`
199
+ })
200
+ .join(', ')})`
201
+ }
202
+ return s
203
+ }
204
+
205
+ function genEnum(t: GraphQLEnumType) {
206
+ return `
207
+ export enum ${t.name} {
208
+ ${t
209
+ .getValues()
210
+ .map((v) => `\t${v.name}`)
211
+ .join(', ')}
212
+ }`
213
+ }
@@ -0,0 +1 @@
1
+ export { StoreContext } from '@sentio/runtime'
@@ -0,0 +1,9 @@
1
+ type Constructor = { new (...args: any[]): any }
2
+
3
+ export function entity<T extends Constructor>(constructor: T, context: any) {
4
+ return constructor
5
+ }
6
+
7
+ export function derivedFrom(field: string) {
8
+ return function (target: any, context: any) {}
9
+ }
@@ -0,0 +1,61 @@
1
+ import { Store } from './store.js'
2
+ import { ID } from './types.js'
3
+
4
+ export interface EntityClass<T extends Entity> {
5
+ new (data: any): T
6
+ }
7
+
8
+ export abstract class Entity {
9
+ get id(): ID {
10
+ return this.get('id')
11
+ }
12
+
13
+ private _store: Store | undefined
14
+ data: Record<string, any> = {}
15
+ protected constructor(data: Record<string, any>) {
16
+ Object.entries(data).forEach(([key, value]) => {
17
+ if (Array.isArray(value)) {
18
+ this.data[key] = value.map((v) => this.getIdFromEntity(v))
19
+ } else {
20
+ this.data[key] = this.getIdFromEntity(value)
21
+ }
22
+ })
23
+ }
24
+
25
+ private getIdFromEntity(entity: any): any {
26
+ if (entity instanceof Entity) {
27
+ return entity.id
28
+ } else if (typeof entity === 'object' && entity.id) {
29
+ return entity.id
30
+ }
31
+ return entity
32
+ }
33
+
34
+ set store(store: Store) {
35
+ this._store = store
36
+ }
37
+
38
+ get<T>(field: string): T {
39
+ return this.data[field]
40
+ }
41
+
42
+ set<T>(field: string, value: T | T[] | ID | ID[]): void {
43
+ if (Array.isArray(value) && value instanceof Entity) {
44
+ this.data[field] = value.map((v) => (v as Entity).id)
45
+ } else if (value instanceof Entity) {
46
+ this.data[field] = (value as Entity).id
47
+ }
48
+ this.data[field] = value
49
+ }
50
+
51
+ protected getFieldObject<T extends Entity>(entity: EntityClass<T> | string, field: string): Promise<T | undefined> {
52
+ const id = this.data[field]
53
+ return id ? (this._store?.get(entity, id) as Promise<T>) : Promise.resolve(undefined)
54
+ }
55
+
56
+ protected getFieldObjectArray<T extends Entity>(entity: EntityClass<T>, field: string): Promise<T[]> {
57
+ const ids = this.data[field]
58
+ const promises = ids.map((id: string) => this._store?.get(entity, id))
59
+ return Promise.all(promises) as Promise<T[]>
60
+ }
61
+ }
@@ -0,0 +1,5 @@
1
+ export * from './decorators.js'
2
+ export * from './types.js'
3
+ export * from './entity.js'
4
+ export * from './store.js'
5
+ export * from './context.js'
@@ -0,0 +1,10 @@
1
+ import { codegen } from './codegen.js'
2
+
3
+ if (process.argv.length > 3) {
4
+ const srcFile = process.argv[2]
5
+ const targetDir = process.argv[3]
6
+ await codegen(srcFile, targetDir)
7
+ } else {
8
+ console.error('Not enough argument')
9
+ process.exit(1)
10
+ }
@@ -0,0 +1,35 @@
1
+ import { buildASTSchema, DocumentNode, extendSchema, GraphQLSchema, parse, validateSchema } from 'graphql/index.js'
2
+ import * as fs from 'node:fs'
3
+
4
+ const customScalars = ['BigInt', 'BigDecimal', 'DateTime', 'JSON', 'Bytes', 'ID']
5
+
6
+ const baseSchema = buildASTSchema(
7
+ parse(`
8
+ directive @entity on OBJECT
9
+ directive @query on INTERFACE
10
+ directive @derivedFrom(field: String!) on FIELD_DEFINITION
11
+ directive @unique on FIELD_DEFINITION
12
+ directive @index(fields: [String!] unique: Boolean) repeatable on OBJECT | FIELD_DEFINITION
13
+ directive @fulltext(query: String!) on FIELD_DEFINITION
14
+ directive @cardinality(value: Int!) on OBJECT | FIELD_DEFINITION
15
+ directive @byteWeight(value: Float!) on FIELD_DEFINITION
16
+ directive @variant on OBJECT # legacy
17
+ directive @jsonField on OBJECT # legacy
18
+ ${customScalars.map((name) => 'scalar ' + name).join('\n')}
19
+ `)
20
+ )
21
+
22
+ export function buildSchema(doc: DocumentNode): GraphQLSchema {
23
+ const schema = extendSchema(baseSchema, doc)
24
+ const errors = validateSchema(schema).filter((err) => !/query root/i.test(err.message))
25
+ if (errors.length > 0) {
26
+ throw errors[0]
27
+ }
28
+ return schema
29
+ }
30
+
31
+ export function schemaFromFile(filePath: string) {
32
+ const source = fs.readFileSync(filePath, 'utf-8')
33
+ const doc = parse(source)
34
+ return { schema: buildSchema(doc), source }
35
+ }
@@ -0,0 +1,68 @@
1
+ import { Entity, EntityClass } from './entity.js'
2
+ import { StoreContext } from './context.js'
3
+
4
+ export class Store {
5
+ constructor(private readonly context: StoreContext) {}
6
+
7
+ async get<T extends Entity>(entity: EntityClass<T> | string, id: string): Promise<T | undefined> {
8
+ const promise = this.context.sendRequest({
9
+ get: {
10
+ entity: typeof entity == 'string' ? entity : entity.name,
11
+ id
12
+ }
13
+ })
14
+
15
+ const data = (await promise) as any
16
+ if (data?.['id'] != null) {
17
+ return this.newEntity(entity as EntityClass<T>, data)
18
+ }
19
+ return undefined
20
+ }
21
+
22
+ async delete(entity: EntityClass<any>, id: string | string[]): Promise<void> {
23
+ await this.context.sendRequest({
24
+ delete: {
25
+ entity: entity.name,
26
+ id: Array.isArray(id) ? id : [id]
27
+ }
28
+ })
29
+ }
30
+
31
+ async upsert<T extends Entity>(entity: T | T[]): Promise<T> {
32
+ const promise = this.context.sendRequest({
33
+ upsert: {
34
+ entity: entity.constructor.name,
35
+ data: Array.isArray(entity) ? entity.map((e) => e.data) : [entity.data]
36
+ }
37
+ })
38
+
39
+ if (Array.isArray(entity)) {
40
+ entity.forEach((e) => (e.store = this))
41
+ } else {
42
+ entity.store = this
43
+ }
44
+
45
+ return promise as Promise<T>
46
+ }
47
+
48
+ async list<T extends Entity>(entity: EntityClass<T>, limit?: number, offset?: number): Promise<T[]> {
49
+ const promise = this.context.sendRequest({
50
+ list: {
51
+ entity: entity.name,
52
+ limit,
53
+ offset
54
+ }
55
+ })
56
+
57
+ const list = (await promise) as any[]
58
+ return list.map((data) => {
59
+ return this.newEntity(entity, data)
60
+ })
61
+ }
62
+
63
+ private newEntity<T extends Entity>(entity: EntityClass<T>, data: any) {
64
+ const e = new (entity as EntityClass<T>)(data)
65
+ e.store = this
66
+ return e
67
+ }
68
+ }
@@ -0,0 +1,10 @@
1
+ export type { BigDecimal } from '@sentio/bigdecimal'
2
+
3
+ export type ID = string
4
+ export type String = string
5
+ export type Int = number
6
+ export type Float = number
7
+ export type Boolean = boolean
8
+ export type DateTime = Date
9
+ export type Json = any
10
+ export type Bytes = Uint8Array
@@ -2,12 +2,16 @@ import {
2
2
  AccountConfig,
3
3
  ContractConfig,
4
4
  DataBinding,
5
+ DeepPartial,
5
6
  Empty,
6
7
  ProcessBindingResponse,
7
8
  ProcessBindingsRequest,
8
9
  ProcessConfigRequest,
9
10
  ProcessConfigResponse,
10
11
  ProcessorServiceImplementation,
12
+ ProcessStreamRequest,
13
+ ProcessStreamResponse,
14
+ ServerStreamingMethodResult,
11
15
  StartRequest
12
16
  } from '@sentio/protos'
13
17
  import { CallContext } from 'nice-grpc-common'
@@ -80,7 +84,14 @@ export class TestProcessorServer implements ProcessorServiceImplementation {
80
84
  return this.service.processBindings({ bindings: [request] }, context)
81
85
  }
82
86
 
83
- processBindingsStream(request: AsyncIterable<DataBinding>, context: CallContext) {
84
- return this.service.processBindingsStream(request, context)
87
+ processBindingsStream(
88
+ requests: AsyncIterable<ProcessStreamRequest>,
89
+ context: CallContext
90
+ ): ServerStreamingMethodResult<DeepPartial<ProcessStreamResponse>> {
91
+ throw new Error('Method not implemented.')
85
92
  }
93
+
94
+ // processBindingsStream(request: AsyncIterable<ProcessStreamRequest>, context: CallContext) {
95
+ // return this.service.processBindingsStream(request, context)
96
+ // }
86
97
  }