confluent-schema-registry 3.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (173) hide show
  1. package/.dockerignore +2 -0
  2. package/.prettierrc.js +8 -0
  3. package/CHANGELOG.md +166 -0
  4. package/Dockerfile +10 -0
  5. package/LICENSE +21 -0
  6. package/README.md +44 -0
  7. package/bin/avdlToAVSC.sh +9 -0
  8. package/dist/@types.d.ts +93 -0
  9. package/dist/@types.js +10 -0
  10. package/dist/@types.js.map +1 -0
  11. package/dist/AvroHelper.d.ts +12 -0
  12. package/dist/AvroHelper.js +67 -0
  13. package/dist/AvroHelper.js.map +1 -0
  14. package/dist/JsonHelper.d.ts +7 -0
  15. package/dist/JsonHelper.js +20 -0
  16. package/dist/JsonHelper.js.map +1 -0
  17. package/dist/JsonSchema.d.ts +31 -0
  18. package/dist/JsonSchema.js +58 -0
  19. package/dist/JsonSchema.js.map +1 -0
  20. package/dist/ProtoHelper.d.ts +7 -0
  21. package/dist/ProtoHelper.js +23 -0
  22. package/dist/ProtoHelper.js.map +1 -0
  23. package/dist/ProtoSchema.d.ts +14 -0
  24. package/dist/ProtoSchema.js +66 -0
  25. package/dist/ProtoSchema.js.map +1 -0
  26. package/dist/SchemaRegistry.d.ts +48 -0
  27. package/dist/SchemaRegistry.js +250 -0
  28. package/dist/SchemaRegistry.js.map +1 -0
  29. package/dist/api/index.d.ts +43 -0
  30. package/dist/api/index.js +90 -0
  31. package/dist/api/index.js.map +1 -0
  32. package/dist/api/middleware/confluentEncoderMiddleware.d.ts +3 -0
  33. package/dist/api/middleware/confluentEncoderMiddleware.js +31 -0
  34. package/dist/api/middleware/confluentEncoderMiddleware.js.map +1 -0
  35. package/dist/api/middleware/errorMiddleware.d.ts +3 -0
  36. package/dist/api/middleware/errorMiddleware.js +20 -0
  37. package/dist/api/middleware/errorMiddleware.js.map +1 -0
  38. package/dist/api/middleware/userAgent.d.ts +3 -0
  39. package/dist/api/middleware/userAgent.js +18 -0
  40. package/dist/api/middleware/userAgent.js.map +1 -0
  41. package/dist/cache.d.ts +20 -0
  42. package/dist/cache.js +24 -0
  43. package/dist/cache.js.map +1 -0
  44. package/dist/constants.d.ts +11 -0
  45. package/dist/constants.js +15 -0
  46. package/dist/constants.js.map +1 -0
  47. package/dist/errors.d.ts +14 -0
  48. package/dist/errors.js +26 -0
  49. package/dist/errors.js.map +1 -0
  50. package/dist/index.d.ts +4 -0
  51. package/dist/index.js +13 -0
  52. package/dist/index.js.map +1 -0
  53. package/dist/schemaTypeResolver.d.ts +4 -0
  54. package/dist/schemaTypeResolver.js +80 -0
  55. package/dist/schemaTypeResolver.js.map +1 -0
  56. package/dist/utils/avdlToAVSC.d.ts +2 -0
  57. package/dist/utils/avdlToAVSC.js +85 -0
  58. package/dist/utils/avdlToAVSC.js.map +1 -0
  59. package/dist/utils/index.d.ts +2 -0
  60. package/dist/utils/index.js +9 -0
  61. package/dist/utils/index.js.map +1 -0
  62. package/dist/utils/readAVSC.d.ts +3 -0
  63. package/dist/utils/readAVSC.js +33 -0
  64. package/dist/utils/readAVSC.js.map +1 -0
  65. package/dist/wireDecoder.d.ts +7 -0
  66. package/dist/wireDecoder.js +8 -0
  67. package/dist/wireDecoder.js.map +1 -0
  68. package/dist/wireEncoder.d.ts +3 -0
  69. package/dist/wireEncoder.js +10 -0
  70. package/dist/wireEncoder.js.map +1 -0
  71. package/dockest-error.json +11 -0
  72. package/dockest.ts +30 -0
  73. package/jest.setup.ts +60 -0
  74. package/package.json +56 -0
  75. package/release/CHANGELOG.md +166 -0
  76. package/release/LICENSE +21 -0
  77. package/release/README.md +44 -0
  78. package/release/dist/@types.d.ts +93 -0
  79. package/release/dist/@types.js +10 -0
  80. package/release/dist/@types.js.map +1 -0
  81. package/release/dist/AvroHelper.d.ts +12 -0
  82. package/release/dist/AvroHelper.js +67 -0
  83. package/release/dist/AvroHelper.js.map +1 -0
  84. package/release/dist/JsonHelper.d.ts +7 -0
  85. package/release/dist/JsonHelper.js +20 -0
  86. package/release/dist/JsonHelper.js.map +1 -0
  87. package/release/dist/JsonSchema.d.ts +31 -0
  88. package/release/dist/JsonSchema.js +58 -0
  89. package/release/dist/JsonSchema.js.map +1 -0
  90. package/release/dist/ProtoHelper.d.ts +7 -0
  91. package/release/dist/ProtoHelper.js +23 -0
  92. package/release/dist/ProtoHelper.js.map +1 -0
  93. package/release/dist/ProtoSchema.d.ts +14 -0
  94. package/release/dist/ProtoSchema.js +66 -0
  95. package/release/dist/ProtoSchema.js.map +1 -0
  96. package/release/dist/SchemaRegistry.d.ts +48 -0
  97. package/release/dist/SchemaRegistry.js +250 -0
  98. package/release/dist/SchemaRegistry.js.map +1 -0
  99. package/release/dist/api/index.d.ts +43 -0
  100. package/release/dist/api/index.js +90 -0
  101. package/release/dist/api/index.js.map +1 -0
  102. package/release/dist/api/middleware/confluentEncoderMiddleware.d.ts +3 -0
  103. package/release/dist/api/middleware/confluentEncoderMiddleware.js +31 -0
  104. package/release/dist/api/middleware/confluentEncoderMiddleware.js.map +1 -0
  105. package/release/dist/api/middleware/errorMiddleware.d.ts +3 -0
  106. package/release/dist/api/middleware/errorMiddleware.js +20 -0
  107. package/release/dist/api/middleware/errorMiddleware.js.map +1 -0
  108. package/release/dist/api/middleware/userAgent.d.ts +3 -0
  109. package/release/dist/api/middleware/userAgent.js +18 -0
  110. package/release/dist/api/middleware/userAgent.js.map +1 -0
  111. package/release/dist/cache.d.ts +20 -0
  112. package/release/dist/cache.js +24 -0
  113. package/release/dist/cache.js.map +1 -0
  114. package/release/dist/constants.d.ts +11 -0
  115. package/release/dist/constants.js +15 -0
  116. package/release/dist/constants.js.map +1 -0
  117. package/release/dist/errors.d.ts +14 -0
  118. package/release/dist/errors.js +26 -0
  119. package/release/dist/errors.js.map +1 -0
  120. package/release/dist/index.d.ts +4 -0
  121. package/release/dist/index.js +13 -0
  122. package/release/dist/index.js.map +1 -0
  123. package/release/dist/schemaTypeResolver.d.ts +4 -0
  124. package/release/dist/schemaTypeResolver.js +80 -0
  125. package/release/dist/schemaTypeResolver.js.map +1 -0
  126. package/release/dist/utils/avdlToAVSC.d.ts +2 -0
  127. package/release/dist/utils/avdlToAVSC.js +85 -0
  128. package/release/dist/utils/avdlToAVSC.js.map +1 -0
  129. package/release/dist/utils/index.d.ts +2 -0
  130. package/release/dist/utils/index.js +9 -0
  131. package/release/dist/utils/index.js.map +1 -0
  132. package/release/dist/utils/readAVSC.d.ts +3 -0
  133. package/release/dist/utils/readAVSC.js +33 -0
  134. package/release/dist/utils/readAVSC.js.map +1 -0
  135. package/release/dist/wireDecoder.d.ts +7 -0
  136. package/release/dist/wireDecoder.js +8 -0
  137. package/release/dist/wireDecoder.js.map +1 -0
  138. package/release/dist/wireEncoder.d.ts +3 -0
  139. package/release/dist/wireEncoder.js +10 -0
  140. package/release/dist/wireEncoder.js.map +1 -0
  141. package/release/package.json +56 -0
  142. package/src/@types.ts +105 -0
  143. package/src/AvroHelper.ts +91 -0
  144. package/src/JsonHelper.ts +35 -0
  145. package/src/JsonSchema.ts +80 -0
  146. package/src/ProtoHelper.ts +38 -0
  147. package/src/ProtoSchema.ts +80 -0
  148. package/src/SchemaRegistry.avro.spec.ts +558 -0
  149. package/src/SchemaRegistry.json.spec.ts +364 -0
  150. package/src/SchemaRegistry.newApi.spec.ts +622 -0
  151. package/src/SchemaRegistry.protobuf.spec.ts +372 -0
  152. package/src/SchemaRegistry.spec.ts +252 -0
  153. package/src/SchemaRegistry.ts +387 -0
  154. package/src/api/index.spec.ts +23 -0
  155. package/src/api/index.ts +121 -0
  156. package/src/api/middleware/confluentEncoderMiddleware.ts +36 -0
  157. package/src/api/middleware/errorMiddleware.spec.ts +67 -0
  158. package/src/api/middleware/errorMiddleware.ts +37 -0
  159. package/src/api/middleware/userAgent.spec.ts +53 -0
  160. package/src/api/middleware/userAgent.ts +19 -0
  161. package/src/cache.ts +34 -0
  162. package/src/constants.ts +13 -0
  163. package/src/errors.ts +26 -0
  164. package/src/index.ts +4 -0
  165. package/src/schemaTypeResolver.ts +101 -0
  166. package/src/utils/avdlToAVSC.spec.ts +79 -0
  167. package/src/utils/avdlToAVSC.ts +106 -0
  168. package/src/utils/index.ts +2 -0
  169. package/src/utils/readAVSC.spec.ts +23 -0
  170. package/src/utils/readAVSC.ts +36 -0
  171. package/src/wireDecoder.ts +5 -0
  172. package/src/wireEncoder.ts +10 -0
  173. package/tsconfig.json +22 -0
@@ -0,0 +1,91 @@
1
+ import {
2
+ AvroSchema,
3
+ RawAvroSchema,
4
+ AvroOptions,
5
+ ConfluentSchema,
6
+ SchemaHelper,
7
+ ConfluentSubject,
8
+ ProtocolOptions,
9
+ AvroConfluentSchema,
10
+ } from './@types'
11
+ import { ConfluentSchemaRegistryArgumentError } from './errors'
12
+ import avro, { ForSchemaOptions, Schema, Type } from 'avsc'
13
+ import { SchemaResponse, SchemaType } from './@types'
14
+
15
+ type TypeHook = (schema: Schema, opts: ForSchemaOptions) => Type
16
+ export default class AvroHelper implements SchemaHelper {
17
+ private getRawAvroSchema(schema: ConfluentSchema): RawAvroSchema {
18
+ return (typeof schema.schema === 'string'
19
+ ? JSON.parse(schema.schema)
20
+ : schema.schema) as RawAvroSchema
21
+ }
22
+
23
+ public getAvroSchema(schema: ConfluentSchema | RawAvroSchema, opts?: AvroOptions) {
24
+ const rawSchema: RawAvroSchema = this.isRawAvroSchema(schema)
25
+ ? schema
26
+ : this.getRawAvroSchema(schema)
27
+ // @ts-ignore TODO: Fix typings for Schema...
28
+
29
+ const addReferencedSchemas = (userHook?: TypeHook): TypeHook => (
30
+ schema: avro.Schema,
31
+ opts: ForSchemaOptions,
32
+ ) => {
33
+ const avroOpts = opts as AvroOptions
34
+ avroOpts?.referencedSchemas?.forEach(subSchema => {
35
+ const rawSubSchema = this.getRawAvroSchema(subSchema)
36
+ avroOpts.typeHook = userHook
37
+ avro.Type.forSchema(rawSubSchema, avroOpts)
38
+ })
39
+ if (userHook) {
40
+ return userHook(schema, opts)
41
+ }
42
+ }
43
+
44
+ const avroSchema = avro.Type.forSchema(rawSchema, {
45
+ ...opts,
46
+ typeHook: addReferencedSchemas(opts?.typeHook),
47
+ })
48
+
49
+ return avroSchema
50
+ }
51
+
52
+ public validate(avroSchema: AvroSchema): void {
53
+ if (!avroSchema.name) {
54
+ throw new ConfluentSchemaRegistryArgumentError(`Invalid name: ${avroSchema.name}`)
55
+ }
56
+ }
57
+
58
+ public getSubject(
59
+ schema: AvroConfluentSchema,
60
+ // @ts-ignore
61
+ avroSchema: AvroSchema,
62
+ separator: string,
63
+ ): ConfluentSubject {
64
+ const rawSchema: RawAvroSchema = this.getRawAvroSchema(schema)
65
+
66
+ if (!rawSchema.namespace) {
67
+ throw new ConfluentSchemaRegistryArgumentError(`Invalid namespace: ${rawSchema.namespace}`)
68
+ }
69
+
70
+ const subject: ConfluentSubject = {
71
+ name: [rawSchema.namespace, rawSchema.name].join(separator),
72
+ }
73
+ return subject
74
+ }
75
+
76
+ private isRawAvroSchema(schema: ConfluentSchema | RawAvroSchema): schema is RawAvroSchema {
77
+ const asRawAvroSchema = schema as RawAvroSchema
78
+ return asRawAvroSchema.name != null && asRawAvroSchema.type != null
79
+ }
80
+
81
+ public toConfluentSchema(data: SchemaResponse): AvroConfluentSchema {
82
+ return { type: SchemaType.AVRO, schema: data.schema, references: data.references }
83
+ }
84
+
85
+ updateOptionsFromSchemaReferences(
86
+ referencedSchemas: AvroConfluentSchema[],
87
+ options: ProtocolOptions = {},
88
+ ): ProtocolOptions {
89
+ return { ...options, [SchemaType.AVRO]: { ...options[SchemaType.AVRO], referencedSchemas } }
90
+ }
91
+ }
@@ -0,0 +1,35 @@
1
+ import {
2
+ Schema,
3
+ SchemaHelper,
4
+ ConfluentSubject,
5
+ SchemaResponse,
6
+ SchemaType,
7
+ ProtocolOptions,
8
+ JsonConfluentSchema,
9
+ } from './@types'
10
+ import { ConfluentSchemaRegistryError } from './errors'
11
+
12
+ export default class JsonHelper implements SchemaHelper {
13
+ public validate(_schema: Schema): void {
14
+ return
15
+ }
16
+
17
+ public getSubject(
18
+ _confluentSchema: JsonConfluentSchema,
19
+ _schema: Schema,
20
+ _separator: string,
21
+ ): ConfluentSubject {
22
+ throw new ConfluentSchemaRegistryError('not implemented yet')
23
+ }
24
+
25
+ public toConfluentSchema(data: SchemaResponse): JsonConfluentSchema {
26
+ return { type: SchemaType.JSON, schema: data.schema, references: data.references }
27
+ }
28
+
29
+ updateOptionsFromSchemaReferences(
30
+ referencedSchemas: JsonConfluentSchema[],
31
+ options: ProtocolOptions = {},
32
+ ): ProtocolOptions {
33
+ return { ...options, [SchemaType.JSON]: { ...options[SchemaType.JSON], referencedSchemas } }
34
+ }
35
+ }
@@ -0,0 +1,80 @@
1
+ import { Schema, JsonOptions, JsonConfluentSchema } from './@types'
2
+ import Ajv from 'ajv'
3
+ import { ConfluentSchemaRegistryValidationError } from './errors'
4
+
5
+ interface BaseAjvValidationError {
6
+ data?: unknown
7
+ schema?: unknown
8
+ }
9
+ interface OldAjvValidationError extends BaseAjvValidationError {
10
+ dataPath: string
11
+ instancePath?: string
12
+ }
13
+ interface NewAjvValidationError extends BaseAjvValidationError {
14
+ instancePath: string
15
+ }
16
+
17
+ type AjvValidationError = OldAjvValidationError | NewAjvValidationError
18
+
19
+ export interface ValidateFunction {
20
+ (this: any, data: any): boolean
21
+ errors?: null | AjvValidationError[]
22
+ }
23
+ export default class JsonSchema implements Schema {
24
+ private validate: ValidateFunction
25
+
26
+ constructor(schema: JsonConfluentSchema, opts?: JsonOptions) {
27
+ this.validate = this.getJsonSchema(schema, opts)
28
+ }
29
+
30
+ private getJsonSchema(schema: JsonConfluentSchema, opts?: JsonOptions) {
31
+ const ajv = opts?.ajvInstance ?? new Ajv(opts)
32
+ const referencedSchemas = opts?.referencedSchemas
33
+ if (referencedSchemas) {
34
+ referencedSchemas.forEach(rawSchema => {
35
+ const $schema = JSON.parse(rawSchema.schema)
36
+ ajv.addSchema($schema, $schema['$id'])
37
+ })
38
+ }
39
+ const validate = ajv.compile(JSON.parse(schema.schema))
40
+ return validate
41
+ }
42
+
43
+ private validatePayload(payload: any) {
44
+ const paths: string[][] = []
45
+ if (!this.isValid(payload, { errorHook: path => paths.push(path) })) {
46
+ throw new ConfluentSchemaRegistryValidationError('invalid payload', paths)
47
+ }
48
+ }
49
+
50
+ public toBuffer(payload: object): Buffer {
51
+ this.validatePayload(payload)
52
+ return Buffer.from(JSON.stringify(payload))
53
+ }
54
+
55
+ public fromBuffer(buffer: Buffer): any {
56
+ const payload = JSON.parse(buffer.toString())
57
+ this.validatePayload(payload)
58
+ return payload
59
+ }
60
+
61
+ public isValid(
62
+ payload: object,
63
+ opts?: { errorHook: (path: Array<string>, value: any, type?: any) => void },
64
+ ): boolean {
65
+ if (!this.validate(payload)) {
66
+ if (opts === null || opts === void 0 ? void 0 : opts.errorHook) {
67
+ for (const err of this.validate.errors??[]) {
68
+ const path = this.isOldAjvValidationError(err) ? err.dataPath : err.instancePath
69
+ opts?.errorHook([path], err.data, err.schema)
70
+ }
71
+ }
72
+ return false
73
+ }
74
+ return true
75
+ }
76
+
77
+ private isOldAjvValidationError(error: AjvValidationError): error is OldAjvValidationError {
78
+ return (error as OldAjvValidationError).dataPath != null
79
+ }
80
+ }
@@ -0,0 +1,38 @@
1
+ import {
2
+ Schema,
3
+ SchemaHelper,
4
+ ConfluentSubject,
5
+ SchemaResponse,
6
+ SchemaType,
7
+ ProtocolOptions,
8
+ ProtoConfluentSchema,
9
+ } from './@types'
10
+ import { ConfluentSchemaRegistryError } from './errors'
11
+
12
+ export default class ProtoHelper implements SchemaHelper {
13
+ public validate(_schema: Schema): void {
14
+ return
15
+ }
16
+
17
+ public getSubject(
18
+ _confluentSchema: ProtoConfluentSchema,
19
+ _schema: Schema,
20
+ _separator: string,
21
+ ): ConfluentSubject {
22
+ throw new ConfluentSchemaRegistryError('not implemented yet')
23
+ }
24
+
25
+ public toConfluentSchema(data: SchemaResponse): ProtoConfluentSchema {
26
+ return { type: SchemaType.PROTOBUF, schema: data.schema, references: data.references }
27
+ }
28
+
29
+ updateOptionsFromSchemaReferences(
30
+ referencedSchemas: ProtoConfluentSchema[],
31
+ options: ProtocolOptions = {},
32
+ ): ProtocolOptions {
33
+ return {
34
+ ...options,
35
+ [SchemaType.PROTOBUF]: { ...options[SchemaType.PROTOBUF], referencedSchemas },
36
+ }
37
+ }
38
+ }
@@ -0,0 +1,80 @@
1
+ import { Schema, ProtoOptions, ProtoConfluentSchema } from './@types'
2
+ import protobuf from 'protobufjs'
3
+ import { IParserResult, ReflectionObject, Namespace, Type } from 'protobufjs/light'
4
+ import {
5
+ ConfluentSchemaRegistryArgumentError,
6
+ ConfluentSchemaRegistryValidationError,
7
+ } from './errors'
8
+
9
+ export default class ProtoSchema implements Schema {
10
+ private message: Type
11
+
12
+ constructor(schema: ProtoConfluentSchema, opts?: ProtoOptions) {
13
+ const parsedMessage = protobuf.parse(schema.schema)
14
+ const root = parsedMessage.root
15
+ const referencedSchemas = opts?.referencedSchemas
16
+
17
+ // handle all schema references independent on nested references
18
+ if (referencedSchemas) {
19
+ referencedSchemas.forEach(rawSchema => protobuf.parse(rawSchema.schema as string, root))
20
+ }
21
+
22
+ this.message = root.lookupType(this.getTypeName(parsedMessage, opts))
23
+ }
24
+
25
+ private getNestedTypeName(parent: { [k: string]: ReflectionObject } | undefined): string {
26
+ if (!parent) throw new ConfluentSchemaRegistryArgumentError('no nested fields')
27
+ const keys = Object.keys(parent)
28
+ const reflection = parent[keys[0]]
29
+
30
+ // Traverse down the nested Namespaces until we find a message Type instance (which extends Namespace)
31
+ if (reflection instanceof Namespace && !(reflection instanceof Type) && reflection.nested)
32
+ return this.getNestedTypeName(reflection.nested)
33
+ return keys[0]
34
+ }
35
+
36
+ private getTypeName(parsedMessage: IParserResult, opts?: ProtoOptions): string {
37
+ const root = parsedMessage.root
38
+ const pkg = parsedMessage.package
39
+ const name = opts && opts.messageName ? opts.messageName : this.getNestedTypeName(root.nested)
40
+ return `${pkg ? pkg + '.' : ''}.${name}`
41
+ }
42
+
43
+ private trimStart(buffer: Buffer): Buffer {
44
+ const index = buffer.findIndex((value: number) => value != 0)
45
+ return buffer.slice(index)
46
+ }
47
+
48
+ public toBuffer(payload: object): Buffer {
49
+ const paths: string[][] = []
50
+ if (
51
+ !this.isValid(payload, {
52
+ errorHook: (path: Array<string>) => paths.push(path),
53
+ })
54
+ ) {
55
+ throw new ConfluentSchemaRegistryValidationError('invalid payload', paths)
56
+ }
57
+
58
+ const protoPayload = this.message.create(payload)
59
+ return Buffer.from(this.message.encode(protoPayload).finish())
60
+ }
61
+
62
+ public fromBuffer(buffer: Buffer): any {
63
+ const newBuffer = this.trimStart(buffer)
64
+ return this.message.decode(newBuffer)
65
+ }
66
+
67
+ public isValid(
68
+ payload: object,
69
+ opts?: { errorHook: (path: Array<string>, value: any, type?: any) => void },
70
+ ): boolean {
71
+ const errMsg: null | string = this.message.verify(payload)
72
+ if (errMsg) {
73
+ if (opts?.errorHook) {
74
+ opts.errorHook([errMsg], payload)
75
+ }
76
+ return false
77
+ }
78
+ return true
79
+ }
80
+ }