confluent-schema-registry 3.3.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 (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
+ }