@azure/schema-registry-json 1.0.0-alpha.20230809.1

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023 Microsoft
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,167 @@
1
+ # Azure Schema Registry Json Serializer client library for JavaScript
2
+
3
+ Azure Schema Registry is a schema repository service hosted by Azure Event Hubs,
4
+ providing schema storage, versioning, and management. This package provides an
5
+ Json serializer capable of serializing and deserializing payloads containing
6
+ Json-serialized data.
7
+
8
+ Key links:
9
+
10
+ - [Source code](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/schemaregistry/schema-registry-json)
11
+ - [Package (npm)](https://www.npmjs.com/package/@azure/schema-registry-json)
12
+ - [API Reference Documentation](https://aka.ms/schemaregistryjson-js-api)
13
+ - [Samples](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/schemaregistry/schema-registry-json/samples)
14
+
15
+ ## Getting started
16
+
17
+ - [LTS versions of Node.js](https://github.com/nodejs/release#release-schedule)
18
+
19
+ ### Prerequisites
20
+
21
+ - An [Azure subscription][azure_sub]
22
+ - An existing [Schema Registry resource](https://aka.ms/schemaregistry)
23
+
24
+ ### Install the `@azure/schema-registry-json` package
25
+
26
+ Install the Azure Text Analytics client library for JavaScript with `npm`:
27
+
28
+ ```bash
29
+ npm install @azure/schema-registry-json
30
+ ```
31
+
32
+ ## Key concepts
33
+
34
+ ### JsonSerializer
35
+
36
+ Provides API to serialize to and deserialize from JSON wrapped in a message
37
+ with a content type field containing the schema ID. Uses
38
+ `SchemaRegistryClient` from the [@azure/schema-registry](https://www.npmjs.com/package/@azure/schema-registry) package
39
+ to get schema IDs from schema definition or vice versa. The provided API has internal cache to avoid calling the schema registry service when possible.
40
+
41
+ ### Messages
42
+
43
+ By default, the serializer will create messages structured as follows:
44
+
45
+ - `data`: a byte array containing JSON data.
46
+
47
+ - `contentType`: a string of the following format `application/json+<Schema ID>` where
48
+ the `application/json` part signals that this message has a Json-serialized payload
49
+ and the `<Schema Id>` part is the Schema ID the Schema Registry service assigned
50
+ to the schema used to serialize this payload.
51
+
52
+ Not all messaging services are supporting the same message structure. To enable
53
+ integration with such services, the serializer can act on custom message structures
54
+ by setting the `messageAdapter` option in the constructor with a corresponding
55
+ message producer and consumer. Azure messaging client libraries export default
56
+ adapters for their message types.
57
+
58
+ ## Examples
59
+
60
+ ### Serialize and deserialize an `@azure/event-hubs`'s `EventData`
61
+
62
+ ```javascript
63
+ const { DefaultAzureCredential } = require("@azure/identity");
64
+ const { createEventDataAdapter } = require("@azure/event-hubs");
65
+ const { SchemaRegistryClient } = require("@azure/schema-registry");
66
+ const { JsonSerializer } = require("@azure/schema-registry-json");
67
+
68
+ const client = new SchemaRegistryClient(
69
+ "<fully qualified namespace>",
70
+ new DefaultAzureCredential()
71
+ );
72
+ const serializer = new JsonSerializer(client, {
73
+ groupName: "<group>",
74
+ messageAdapter: createEventDataAdapter(),
75
+ });
76
+
77
+ // Example Json schema
78
+ const schema = JSON.stringify({
79
+ $schema: "http://json-schema.org/draft-04/schema#",
80
+ $id: "person",
81
+ title: "Student",
82
+ description: "A student in the class",
83
+ type: "object",
84
+ properties: {
85
+ name: {
86
+ type: "string",
87
+ description: "The name of the student",
88
+ },
89
+ },
90
+ required: ["name"]
91
+ });
92
+
93
+ // Example value that matches the Json schema above
94
+ const value = { name: "Bob" };
95
+
96
+ // Serialize value to a message
97
+ const message = await serializer.serialize(value, schema);
98
+
99
+ // Deserialize a message to value
100
+ const deserializedValue = await serializer.deserialize(message);
101
+ ```
102
+
103
+ The serializer doesn't check whether the deserialized value matches the schema
104
+ but provides an option to implement such validation. The application can pass a
105
+ validation callback function as one of the options to the deserialize method where schema validation can be implemented.
106
+ To see how the validation might be implemented, please checkout the [`schemaRegistryJsonWithValidation`](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/schemaregistry/schema-registry-json/samples-dev/schemaRegistryJsonWithValidation.ts)
107
+ sample.
108
+
109
+ ## Troubleshooting
110
+
111
+ The Json serializer communicates with the [Schema Registry][schema_registry] service as needed to register or query schemas and those service calls could throw a [RestError][resterror]. Furthermore, errors of type `Error` will be thrown when serialization or deserialization fails. The `cause` property will contain the underlying error that was thrown from the JSON parser.
112
+
113
+ ### Logging
114
+
115
+ Enabling logging may help uncover useful information about failures. In order to
116
+ see a log of HTTP requests and responses, set the `AZURE_LOG_LEVEL` environment
117
+ variable to `info`. Alternatively, logging can be enabled at runtime by calling
118
+ `setLogLevel` in the `@azure/logger`:
119
+
120
+ ```javascript
121
+ const { setLogLevel } = require("@azure/logger");
122
+
123
+ setLogLevel("info");
124
+ ```
125
+
126
+ ## Next steps
127
+
128
+ Please take a look at the
129
+ [samples](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/schemaregistry/schema-registry-json/samples)
130
+ directory for detailed examples on how to use this library.
131
+
132
+ ## Contributing
133
+
134
+ This project welcomes contributions and suggestions. Most contributions require
135
+ you to agree to a Contributor License Agreement (CLA) declaring that you have
136
+ the right to, and actually do, grant us the rights to use your contribution. For
137
+ details, visit https://cla.microsoft.com.
138
+
139
+ When you submit a pull request, a CLA-bot will automatically determine whether
140
+ you need to provide a CLA and decorate the PR appropriately (e.g., label,
141
+ comment). Simply follow the instructions provided by the bot. You will only need
142
+ to do this once across all repos using our CLA.
143
+
144
+ This project has adopted the [Microsoft Open Source Code of
145
+ Conduct](https://opensource.microsoft.com/codeofconduct/). For more information
146
+ see the [Code of Conduct
147
+ FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact
148
+ [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional
149
+ questions or comments.
150
+
151
+ If you'd like to contribute to this library, please read the [contributing
152
+ guide](https://github.com/Azure/azure-sdk-for-js/blob/main/CONTRIBUTING.md) to
153
+ learn more about how to build and test the code.
154
+
155
+ ## Related projects
156
+
157
+ - [Microsoft Azure SDK for Javascript](https://github.com/Azure/azure-sdk-for-js)
158
+
159
+ ![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-js%2Fsdk%2Fschemaregistry%2Fschema-registry-json%2FREADME.png)
160
+
161
+ [azure_cli]: https://docs.microsoft.com/cli/azure
162
+ [azure_sub]: https://azure.microsoft.com/free/
163
+ [azure_portal]: https://portal.azure.com
164
+ [azure_identity]: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/identity/identity
165
+ [defaultazurecredential]: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/identity/identity#defaultazurecredential
166
+ [resterror]: https://docs.microsoft.com/javascript/api/@azure/core-rest-pipeline/resterror?view=azure-node-latest
167
+ [schema_registry]: https://docs.microsoft.com/javascript/api/overview/azure/schema-registry-readme?view=azure-node-latest
package/dist/index.js ADDED
@@ -0,0 +1,217 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var schemaRegistry = require('@azure/schema-registry');
6
+ var LRUCache = require('lru-cache');
7
+ var logger$1 = require('@azure/logger');
8
+
9
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
10
+
11
+ var LRUCache__default = /*#__PURE__*/_interopDefaultLegacy(LRUCache);
12
+
13
+ // Copyright (c) Microsoft Corporation.
14
+ // Licensed under the MIT license.
15
+ function isMessageContent(message) {
16
+ const castMessage = message;
17
+ return castMessage.data !== undefined && castMessage.contentType !== undefined;
18
+ }
19
+
20
+ // Copyright (c) Microsoft Corporation.
21
+ // Licensed under the MIT license.
22
+ /** @internal */
23
+ function wrapError(f, message) {
24
+ let result;
25
+ try {
26
+ result = f();
27
+ }
28
+ catch (cause) {
29
+ throw errorWithCause(message, cause);
30
+ }
31
+ return result;
32
+ }
33
+ /** @internal */
34
+ function errorWithCause(message, cause) {
35
+ return new Error(message,
36
+ // TS v4.6 and below do not yet recognize the cause option in the Error constructor
37
+ // see https://medium.com/ovrsea/power-up-your-node-js-debugging-and-error-handling-with-the-new-error-cause-feature-4136c563126a
38
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
39
+ // @ts-ignore
40
+ { cause });
41
+ }
42
+
43
+ // Copyright (c) Microsoft Corporation.
44
+ /**
45
+ * The \@azure/logger configuration for the schema-registry-json package.
46
+ */
47
+ const logger = logger$1.createClientLogger("schema-registry-json");
48
+
49
+ // Copyright (c) Microsoft Corporation.
50
+ const jsonMimeType = "application/json";
51
+ const encoder = new TextEncoder();
52
+ const decoder = new TextDecoder();
53
+ function getSchemaObject(schema) {
54
+ return wrapError(() => JSON.parse(schema), `Parsing Json schema failed:\n\n\t${schema}\n\nSee 'cause' for more details.`);
55
+ }
56
+ const cacheOptions = {
57
+ max: 128,
58
+ /**
59
+ * This is needed in order to specify `sizeCalculation` but we do not intend
60
+ * to limit the size just yet.
61
+ */
62
+ maxSize: Number.MAX_VALUE,
63
+ sizeCalculation: (_value, key) => {
64
+ return key.length;
65
+ },
66
+ };
67
+ /**
68
+ * Json serializer that obtains schemas from a schema registry and does not
69
+ * pack schemas into its payloads.
70
+ */
71
+ class JsonSerializer {
72
+ /**
73
+ * Creates a new serializer.
74
+ *
75
+ * @param client - Schema Registry where schemas are registered and obtained.
76
+ * Usually this is a SchemaRegistryClient instance.
77
+ */
78
+ constructor(client, options) {
79
+ this.cacheIdByDefinition = new LRUCache__default["default"](cacheOptions);
80
+ this.cacheById = new LRUCache__default["default"](cacheOptions);
81
+ this.registry = client;
82
+ this.schemaGroup = options === null || options === void 0 ? void 0 : options.groupName;
83
+ this.messageAdapter = options === null || options === void 0 ? void 0 : options.messageAdapter;
84
+ }
85
+ /**
86
+ * serializes the value parameter according to the input schema and creates a message
87
+ * with the serialized data.
88
+ *
89
+ * @param value - The value to serialize.
90
+ * @param schema - The Json schema to use.
91
+ * @returns A new message with the serialized value. The structure of message is
92
+ * constrolled by the message factory option.
93
+ * @throws {@link Error}
94
+ * Thrown if the schema can not be parsed or the value does not match the schema.
95
+ */
96
+ async serialize(value, schema) {
97
+ const entry = await this.getSchemaByDefinition(schema);
98
+ const data = wrapError(() => encoder.encode(JSON.stringify(value)), `Json serialization failed. See 'cause' for more details. Schema ID: ${entry.id}`);
99
+ const contentType = `${jsonMimeType}+${entry.id}`;
100
+ return this.messageAdapter
101
+ ? this.messageAdapter.produce({
102
+ contentType,
103
+ data,
104
+ })
105
+ : /**
106
+ * If no message consumer was provided, then a MessageContent will be
107
+ * returned. This should work because the MessageT type parameter defaults
108
+ * to MessageContent.
109
+ */
110
+ {
111
+ data,
112
+ contentType,
113
+ };
114
+ }
115
+ /**
116
+ * Deserializes the payload of the message using the schema ID in the content type
117
+ * field if no schema was provided.
118
+ *
119
+ * @param message - The message with the payload to be deserialized.
120
+ * @returns The deserialized value.
121
+ * @throws {@link Error}
122
+ * Thrown if the deserialization failed, e.g. because reader and writer schemas are incompatible.
123
+ */
124
+ async deserialize(message, options) {
125
+ const { data, contentType } = convertMessage(message, this.messageAdapter);
126
+ const schemaId = getSchemaId(contentType);
127
+ const schema = await this.getSchemaById(schemaId);
128
+ const returnedMessage = wrapError(() => JSON.parse(decoder.decode(data)), `Json deserialization failed with schema ID (${schemaId}). See 'cause' for more details.`);
129
+ const validate = options === null || options === void 0 ? void 0 : options.validateCallback;
130
+ if (validate) {
131
+ wrapError(() => validate(returnedMessage, schema), `Json validation failed. See 'cause' for more details. Schema ID: ${schemaId}`);
132
+ }
133
+ return returnedMessage;
134
+ }
135
+ async getSchemaById(schemaId) {
136
+ const cached = this.cacheById.get(schemaId);
137
+ if (cached) {
138
+ return cached;
139
+ }
140
+ const schemaResponse = await this.registry.getSchema(schemaId);
141
+ if (!schemaResponse) {
142
+ throw new Error(`Schema with ID '${schemaId}' not found.`);
143
+ }
144
+ if (!schemaResponse.properties.format.match(/^json$/i)) {
145
+ throw new Error(`Schema with ID '${schemaResponse.properties.id}' has format '${schemaResponse.properties.format}', not 'json'.`);
146
+ }
147
+ return this.cache(schemaResponse.definition, schemaId).schema;
148
+ }
149
+ async getSchemaByDefinition(definition) {
150
+ const schemaId = this.cacheIdByDefinition.get(definition);
151
+ if (schemaId) {
152
+ return { id: schemaId, schema: definition };
153
+ }
154
+ if (!this.schemaGroup) {
155
+ throw new Error("Schema group must have been specified in the constructor options when the client was created in order to serialize.");
156
+ }
157
+ const schemaObj = getSchemaObject(definition);
158
+ const description = {
159
+ groupName: this.schemaGroup,
160
+ name: getSchemaName(schemaObj),
161
+ format: schemaRegistry.KnownSchemaFormats.Json,
162
+ definition,
163
+ };
164
+ let id;
165
+ try {
166
+ id = (await this.registry.getSchemaProperties(description)).id;
167
+ }
168
+ catch (e) {
169
+ if (e.statusCode === 404) {
170
+ throw errorWithCause(`Schema '${description.name}' not found in registry group '${description.groupName}', or not found to have matching definition.`, e);
171
+ }
172
+ else {
173
+ throw e;
174
+ }
175
+ }
176
+ return this.cache(definition, id);
177
+ }
178
+ cache(schema, id) {
179
+ const entry = { schema, id };
180
+ this.cacheIdByDefinition.set(schema, id);
181
+ this.cacheById.set(id, schema);
182
+ logger.verbose(`Cache entry added or updated. Total number of entries: ${this.cacheIdByDefinition.size}; Total schema length ${this.cacheIdByDefinition.calculatedSize}`);
183
+ return entry;
184
+ }
185
+ }
186
+ function getSchemaId(contentType) {
187
+ const contentTypeParts = contentType.split("+");
188
+ if (contentTypeParts.length !== 2) {
189
+ throw new Error("Content type was not in the expected format of MIME type + schema ID");
190
+ }
191
+ if (contentTypeParts[0] !== jsonMimeType) {
192
+ throw new Error(`Received content of type ${contentTypeParts[0]} but an json serializer may only be used on content that is of '${jsonMimeType}' type`);
193
+ }
194
+ return contentTypeParts[1];
195
+ }
196
+ function convertMessage(message, adapter) {
197
+ const messageConsumer = adapter === null || adapter === void 0 ? void 0 : adapter.consume;
198
+ if (messageConsumer) {
199
+ return messageConsumer(message);
200
+ }
201
+ else if (isMessageContent(message)) {
202
+ return message;
203
+ }
204
+ else {
205
+ throw new Error(`Expected either a message adapter to be provided to the serializer or the input message to have data and contentType fields`);
206
+ }
207
+ }
208
+ function getSchemaName(schema) {
209
+ const id = schema.$id || schema.id;
210
+ if (!id) {
211
+ throw new Error("Schema must have an ID.");
212
+ }
213
+ return id;
214
+ }
215
+
216
+ exports.JsonSerializer = JsonSerializer;
217
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/utility.ts","../src/errors.ts","../src/logger.ts","../src/jsonSerializer.ts"],"sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { MessageContent } from \"./models\";\n\nexport function isMessageContent(message: unknown): message is MessageContent {\n const castMessage = message as MessageContent;\n return castMessage.data !== undefined && castMessage.contentType !== undefined;\n}\n","// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\n/** @internal */\nexport function wrapError<T>(f: () => T, message: string): T {\n let result: T;\n try {\n result = f();\n } catch (cause) {\n throw errorWithCause(message, cause as Error);\n }\n return result;\n}\n\n/** @internal */\nexport function errorWithCause(message: string, cause: Error): Error {\n return new Error(\n message,\n // TS v4.6 and below do not yet recognize the cause option in the Error constructor\n // see https://medium.com/ovrsea/power-up-your-node-js-debugging-and-error-handling-with-the-new-error-cause-feature-4136c563126a\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n { cause }\n );\n}\n","// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { createClientLogger } from \"@azure/logger\";\n\n/**\n * The \\@azure/logger configuration for the schema-registry-json package.\n */\nexport const logger = createClientLogger(\"schema-registry-json\");\n","// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport {\n DeserializeOptions,\n JsonSerializerOptions,\n MessageAdapter,\n MessageContent,\n} from \"./models\";\nimport { KnownSchemaFormats, SchemaDescription, SchemaRegistry } from \"@azure/schema-registry\";\nimport { isMessageContent } from \"./utility\";\nimport { errorWithCause, wrapError } from \"./errors\";\nimport LRUCache from \"lru-cache\";\nimport LRUCacheOptions = LRUCache.Options;\nimport { logger } from \"./logger\";\n\nconst jsonMimeType = \"application/json\";\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\ninterface CacheEntry {\n /** Schema ID */\n id: string;\n /** Schema string */\n schema: string;\n}\ninterface SchemaObject {\n id?: string;\n $id?: string;\n $schema?: string;\n}\nfunction getSchemaObject(schema: string): SchemaObject {\n return wrapError(\n () => JSON.parse(schema),\n `Parsing Json schema failed:\\n\\n\\t${schema}\\n\\nSee 'cause' for more details.`\n );\n}\n\nconst cacheOptions: LRUCacheOptions<string, any> = {\n max: 128,\n /**\n * This is needed in order to specify `sizeCalculation` but we do not intend\n * to limit the size just yet.\n */\n maxSize: Number.MAX_VALUE,\n sizeCalculation: (_value: any, key: string) => {\n return key.length;\n },\n};\n\n/**\n * Json serializer that obtains schemas from a schema registry and does not\n * pack schemas into its payloads.\n */\nexport class JsonSerializer<MessageT = MessageContent> {\n /**\n * Creates a new serializer.\n *\n * @param client - Schema Registry where schemas are registered and obtained.\n * Usually this is a SchemaRegistryClient instance.\n */\n constructor(client: SchemaRegistry, options?: JsonSerializerOptions<MessageT>) {\n this.registry = client;\n this.schemaGroup = options?.groupName;\n this.messageAdapter = options?.messageAdapter;\n }\n\n private readonly schemaGroup?: string;\n private readonly registry: SchemaRegistry;\n private readonly messageAdapter?: MessageAdapter<MessageT>;\n private readonly cacheIdByDefinition = new LRUCache<string, string>(cacheOptions);\n private readonly cacheById = new LRUCache<string, string>(cacheOptions);\n\n /**\n * serializes the value parameter according to the input schema and creates a message\n * with the serialized data.\n *\n * @param value - The value to serialize.\n * @param schema - The Json schema to use.\n * @returns A new message with the serialized value. The structure of message is\n * constrolled by the message factory option.\n * @throws {@link Error}\n * Thrown if the schema can not be parsed or the value does not match the schema.\n */\n async serialize(value: unknown, schema: string): Promise<MessageT> {\n const entry = await this.getSchemaByDefinition(schema);\n const data = wrapError(\n () => encoder.encode(JSON.stringify(value)),\n `Json serialization failed. See 'cause' for more details. Schema ID: ${entry.id}`\n );\n const contentType = `${jsonMimeType}+${entry.id}`;\n return this.messageAdapter\n ? this.messageAdapter.produce({\n contentType,\n data,\n })\n : /**\n * If no message consumer was provided, then a MessageContent will be\n * returned. This should work because the MessageT type parameter defaults\n * to MessageContent.\n */\n ({\n data,\n contentType,\n } as MessageContent as unknown as MessageT);\n }\n\n /**\n * Deserializes the payload of the message using the schema ID in the content type\n * field if no schema was provided.\n *\n * @param message - The message with the payload to be deserialized.\n * @returns The deserialized value.\n * @throws {@link Error}\n * Thrown if the deserialization failed, e.g. because reader and writer schemas are incompatible.\n */\n async deserialize(message: MessageT, options?: DeserializeOptions): Promise<unknown> {\n const { data, contentType } = convertMessage(message, this.messageAdapter);\n const schemaId = getSchemaId(contentType);\n const schema = await this.getSchemaById(schemaId);\n const returnedMessage = wrapError(\n () => JSON.parse(decoder.decode(data)),\n `Json deserialization failed with schema ID (${schemaId}). See 'cause' for more details.`\n );\n const validate = options?.validateCallback;\n if (validate) {\n wrapError(\n () => validate(returnedMessage, schema),\n `Json validation failed. See 'cause' for more details. Schema ID: ${schemaId}`\n );\n }\n return returnedMessage;\n }\n\n private async getSchemaById(schemaId: string): Promise<string> {\n const cached = this.cacheById.get(schemaId);\n if (cached) {\n return cached;\n }\n const schemaResponse = await this.registry.getSchema(schemaId);\n if (!schemaResponse) {\n throw new Error(`Schema with ID '${schemaId}' not found.`);\n }\n\n if (!schemaResponse.properties.format.match(/^json$/i)) {\n throw new Error(\n `Schema with ID '${schemaResponse.properties.id}' has format '${schemaResponse.properties.format}', not 'json'.`\n );\n }\n return this.cache(schemaResponse.definition, schemaId).schema;\n }\n\n private async getSchemaByDefinition(definition: string): Promise<CacheEntry> {\n const schemaId = this.cacheIdByDefinition.get(definition);\n if (schemaId) {\n return { id: schemaId, schema: definition };\n }\n if (!this.schemaGroup) {\n throw new Error(\n \"Schema group must have been specified in the constructor options when the client was created in order to serialize.\"\n );\n }\n const schemaObj = getSchemaObject(definition);\n const description: SchemaDescription = {\n groupName: this.schemaGroup,\n name: getSchemaName(schemaObj),\n format: KnownSchemaFormats.Json,\n definition,\n };\n let id: string;\n\n try {\n id = (await this.registry.getSchemaProperties(description)).id;\n } catch (e) {\n if ((e as any).statusCode === 404) {\n throw errorWithCause(\n `Schema '${description.name}' not found in registry group '${description.groupName}', or not found to have matching definition.`,\n e as Error\n );\n } else {\n throw e;\n }\n }\n\n return this.cache(definition, id);\n }\n\n private cache(schema: string, id: string): CacheEntry {\n const entry = { schema, id };\n this.cacheIdByDefinition.set(schema, id);\n this.cacheById.set(id, schema);\n logger.verbose(\n `Cache entry added or updated. Total number of entries: ${this.cacheIdByDefinition.size}; Total schema length ${this.cacheIdByDefinition.calculatedSize}`\n );\n return entry;\n }\n}\n\nfunction getSchemaId(contentType: string): string {\n const contentTypeParts = contentType.split(\"+\");\n if (contentTypeParts.length !== 2) {\n throw new Error(\"Content type was not in the expected format of MIME type + schema ID\");\n }\n if (contentTypeParts[0] !== jsonMimeType) {\n throw new Error(\n `Received content of type ${contentTypeParts[0]} but an json serializer may only be used on content that is of '${jsonMimeType}' type`\n );\n }\n return contentTypeParts[1];\n}\n\nfunction convertMessage<MessageT>(\n message: MessageT,\n adapter?: MessageAdapter<MessageT>\n): MessageContent {\n const messageConsumer = adapter?.consume;\n if (messageConsumer) {\n return messageConsumer(message);\n } else if (isMessageContent(message)) {\n return message;\n } else {\n throw new Error(\n `Expected either a message adapter to be provided to the serializer or the input message to have data and contentType fields`\n );\n }\n}\n\nfunction getSchemaName(schema: SchemaObject): string {\n const id = schema.$id || schema.id;\n if (!id) {\n throw new Error(\"Schema must have an ID.\");\n }\n return id;\n}\n"],"names":["createClientLogger","LRUCache","KnownSchemaFormats"],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT license.
3
+ /** @internal */
4
+ export function wrapError(f, message) {
5
+ let result;
6
+ try {
7
+ result = f();
8
+ }
9
+ catch (cause) {
10
+ throw errorWithCause(message, cause);
11
+ }
12
+ return result;
13
+ }
14
+ /** @internal */
15
+ export function errorWithCause(message, cause) {
16
+ return new Error(message,
17
+ // TS v4.6 and below do not yet recognize the cause option in the Error constructor
18
+ // see https://medium.com/ovrsea/power-up-your-node-js-debugging-and-error-handling-with-the-new-error-cause-feature-4136c563126a
19
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
20
+ // @ts-ignore
21
+ { cause });
22
+ }
23
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC,gBAAgB;AAChB,MAAM,UAAU,SAAS,CAAI,CAAU,EAAE,OAAe;IACtD,IAAI,MAAS,CAAC;IACd,IAAI;QACF,MAAM,GAAG,CAAC,EAAE,CAAC;KACd;IAAC,OAAO,KAAK,EAAE;QACd,MAAM,cAAc,CAAC,OAAO,EAAE,KAAc,CAAC,CAAC;KAC/C;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,gBAAgB;AAChB,MAAM,UAAU,cAAc,CAAC,OAAe,EAAE,KAAY;IAC1D,OAAO,IAAI,KAAK,CACd,OAAO;IACP,mFAAmF;IACnF,iIAAiI;IACjI,6DAA6D;IAC7D,aAAa;IACb,EAAE,KAAK,EAAE,CACV,CAAC;AACJ,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\n/** @internal */\nexport function wrapError<T>(f: () => T, message: string): T {\n let result: T;\n try {\n result = f();\n } catch (cause) {\n throw errorWithCause(message, cause as Error);\n }\n return result;\n}\n\n/** @internal */\nexport function errorWithCause(message: string, cause: Error): Error {\n return new Error(\n message,\n // TS v4.6 and below do not yet recognize the cause option in the Error constructor\n // see https://medium.com/ovrsea/power-up-your-node-js-debugging-and-error-handling-with-the-new-error-cause-feature-4136c563126a\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n { cause }\n );\n}\n"]}
@@ -0,0 +1,5 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT license.
3
+ export { JsonSerializer } from "./jsonSerializer";
4
+ export * from "./models";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,cAAc,UAAU,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nexport { JsonSerializer } from \"./jsonSerializer\";\n\nexport * from \"./models\";\n"]}
@@ -0,0 +1,173 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT license.
3
+ import { KnownSchemaFormats } from "@azure/schema-registry";
4
+ import { isMessageContent } from "./utility";
5
+ import { errorWithCause, wrapError } from "./errors";
6
+ import LRUCache from "lru-cache";
7
+ import { logger } from "./logger";
8
+ const jsonMimeType = "application/json";
9
+ const encoder = new TextEncoder();
10
+ const decoder = new TextDecoder();
11
+ function getSchemaObject(schema) {
12
+ return wrapError(() => JSON.parse(schema), `Parsing Json schema failed:\n\n\t${schema}\n\nSee 'cause' for more details.`);
13
+ }
14
+ const cacheOptions = {
15
+ max: 128,
16
+ /**
17
+ * This is needed in order to specify `sizeCalculation` but we do not intend
18
+ * to limit the size just yet.
19
+ */
20
+ maxSize: Number.MAX_VALUE,
21
+ sizeCalculation: (_value, key) => {
22
+ return key.length;
23
+ },
24
+ };
25
+ /**
26
+ * Json serializer that obtains schemas from a schema registry and does not
27
+ * pack schemas into its payloads.
28
+ */
29
+ export class JsonSerializer {
30
+ /**
31
+ * Creates a new serializer.
32
+ *
33
+ * @param client - Schema Registry where schemas are registered and obtained.
34
+ * Usually this is a SchemaRegistryClient instance.
35
+ */
36
+ constructor(client, options) {
37
+ this.cacheIdByDefinition = new LRUCache(cacheOptions);
38
+ this.cacheById = new LRUCache(cacheOptions);
39
+ this.registry = client;
40
+ this.schemaGroup = options === null || options === void 0 ? void 0 : options.groupName;
41
+ this.messageAdapter = options === null || options === void 0 ? void 0 : options.messageAdapter;
42
+ }
43
+ /**
44
+ * serializes the value parameter according to the input schema and creates a message
45
+ * with the serialized data.
46
+ *
47
+ * @param value - The value to serialize.
48
+ * @param schema - The Json schema to use.
49
+ * @returns A new message with the serialized value. The structure of message is
50
+ * constrolled by the message factory option.
51
+ * @throws {@link Error}
52
+ * Thrown if the schema can not be parsed or the value does not match the schema.
53
+ */
54
+ async serialize(value, schema) {
55
+ const entry = await this.getSchemaByDefinition(schema);
56
+ const data = wrapError(() => encoder.encode(JSON.stringify(value)), `Json serialization failed. See 'cause' for more details. Schema ID: ${entry.id}`);
57
+ const contentType = `${jsonMimeType}+${entry.id}`;
58
+ return this.messageAdapter
59
+ ? this.messageAdapter.produce({
60
+ contentType,
61
+ data,
62
+ })
63
+ : /**
64
+ * If no message consumer was provided, then a MessageContent will be
65
+ * returned. This should work because the MessageT type parameter defaults
66
+ * to MessageContent.
67
+ */
68
+ {
69
+ data,
70
+ contentType,
71
+ };
72
+ }
73
+ /**
74
+ * Deserializes the payload of the message using the schema ID in the content type
75
+ * field if no schema was provided.
76
+ *
77
+ * @param message - The message with the payload to be deserialized.
78
+ * @returns The deserialized value.
79
+ * @throws {@link Error}
80
+ * Thrown if the deserialization failed, e.g. because reader and writer schemas are incompatible.
81
+ */
82
+ async deserialize(message, options) {
83
+ const { data, contentType } = convertMessage(message, this.messageAdapter);
84
+ const schemaId = getSchemaId(contentType);
85
+ const schema = await this.getSchemaById(schemaId);
86
+ const returnedMessage = wrapError(() => JSON.parse(decoder.decode(data)), `Json deserialization failed with schema ID (${schemaId}). See 'cause' for more details.`);
87
+ const validate = options === null || options === void 0 ? void 0 : options.validateCallback;
88
+ if (validate) {
89
+ wrapError(() => validate(returnedMessage, schema), `Json validation failed. See 'cause' for more details. Schema ID: ${schemaId}`);
90
+ }
91
+ return returnedMessage;
92
+ }
93
+ async getSchemaById(schemaId) {
94
+ const cached = this.cacheById.get(schemaId);
95
+ if (cached) {
96
+ return cached;
97
+ }
98
+ const schemaResponse = await this.registry.getSchema(schemaId);
99
+ if (!schemaResponse) {
100
+ throw new Error(`Schema with ID '${schemaId}' not found.`);
101
+ }
102
+ if (!schemaResponse.properties.format.match(/^json$/i)) {
103
+ throw new Error(`Schema with ID '${schemaResponse.properties.id}' has format '${schemaResponse.properties.format}', not 'json'.`);
104
+ }
105
+ return this.cache(schemaResponse.definition, schemaId).schema;
106
+ }
107
+ async getSchemaByDefinition(definition) {
108
+ const schemaId = this.cacheIdByDefinition.get(definition);
109
+ if (schemaId) {
110
+ return { id: schemaId, schema: definition };
111
+ }
112
+ if (!this.schemaGroup) {
113
+ throw new Error("Schema group must have been specified in the constructor options when the client was created in order to serialize.");
114
+ }
115
+ const schemaObj = getSchemaObject(definition);
116
+ const description = {
117
+ groupName: this.schemaGroup,
118
+ name: getSchemaName(schemaObj),
119
+ format: KnownSchemaFormats.Json,
120
+ definition,
121
+ };
122
+ let id;
123
+ try {
124
+ id = (await this.registry.getSchemaProperties(description)).id;
125
+ }
126
+ catch (e) {
127
+ if (e.statusCode === 404) {
128
+ throw errorWithCause(`Schema '${description.name}' not found in registry group '${description.groupName}', or not found to have matching definition.`, e);
129
+ }
130
+ else {
131
+ throw e;
132
+ }
133
+ }
134
+ return this.cache(definition, id);
135
+ }
136
+ cache(schema, id) {
137
+ const entry = { schema, id };
138
+ this.cacheIdByDefinition.set(schema, id);
139
+ this.cacheById.set(id, schema);
140
+ logger.verbose(`Cache entry added or updated. Total number of entries: ${this.cacheIdByDefinition.size}; Total schema length ${this.cacheIdByDefinition.calculatedSize}`);
141
+ return entry;
142
+ }
143
+ }
144
+ function getSchemaId(contentType) {
145
+ const contentTypeParts = contentType.split("+");
146
+ if (contentTypeParts.length !== 2) {
147
+ throw new Error("Content type was not in the expected format of MIME type + schema ID");
148
+ }
149
+ if (contentTypeParts[0] !== jsonMimeType) {
150
+ throw new Error(`Received content of type ${contentTypeParts[0]} but an json serializer may only be used on content that is of '${jsonMimeType}' type`);
151
+ }
152
+ return contentTypeParts[1];
153
+ }
154
+ function convertMessage(message, adapter) {
155
+ const messageConsumer = adapter === null || adapter === void 0 ? void 0 : adapter.consume;
156
+ if (messageConsumer) {
157
+ return messageConsumer(message);
158
+ }
159
+ else if (isMessageContent(message)) {
160
+ return message;
161
+ }
162
+ else {
163
+ throw new Error(`Expected either a message adapter to be provided to the serializer or the input message to have data and contentType fields`);
164
+ }
165
+ }
166
+ function getSchemaName(schema) {
167
+ const id = schema.$id || schema.id;
168
+ if (!id) {
169
+ throw new Error("Schema must have an ID.");
170
+ }
171
+ return id;
172
+ }
173
+ //# sourceMappingURL=jsonSerializer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonSerializer.js","sourceRoot":"","sources":["../../src/jsonSerializer.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport {\n DeserializeOptions,\n JsonSerializerOptions,\n MessageAdapter,\n MessageContent,\n} from \"./models\";\nimport { KnownSchemaFormats, SchemaDescription, SchemaRegistry } from \"@azure/schema-registry\";\nimport { isMessageContent } from \"./utility\";\nimport { errorWithCause, wrapError } from \"./errors\";\nimport LRUCache from \"lru-cache\";\nimport LRUCacheOptions = LRUCache.Options;\nimport { logger } from \"./logger\";\n\nconst jsonMimeType = \"application/json\";\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\ninterface CacheEntry {\n /** Schema ID */\n id: string;\n /** Schema string */\n schema: string;\n}\ninterface SchemaObject {\n id?: string;\n $id?: string;\n $schema?: string;\n}\nfunction getSchemaObject(schema: string): SchemaObject {\n return wrapError(\n () => JSON.parse(schema),\n `Parsing Json schema failed:\\n\\n\\t${schema}\\n\\nSee 'cause' for more details.`\n );\n}\n\nconst cacheOptions: LRUCacheOptions<string, any> = {\n max: 128,\n /**\n * This is needed in order to specify `sizeCalculation` but we do not intend\n * to limit the size just yet.\n */\n maxSize: Number.MAX_VALUE,\n sizeCalculation: (_value: any, key: string) => {\n return key.length;\n },\n};\n\n/**\n * Json serializer that obtains schemas from a schema registry and does not\n * pack schemas into its payloads.\n */\nexport class JsonSerializer<MessageT = MessageContent> {\n /**\n * Creates a new serializer.\n *\n * @param client - Schema Registry where schemas are registered and obtained.\n * Usually this is a SchemaRegistryClient instance.\n */\n constructor(client: SchemaRegistry, options?: JsonSerializerOptions<MessageT>) {\n this.registry = client;\n this.schemaGroup = options?.groupName;\n this.messageAdapter = options?.messageAdapter;\n }\n\n private readonly schemaGroup?: string;\n private readonly registry: SchemaRegistry;\n private readonly messageAdapter?: MessageAdapter<MessageT>;\n private readonly cacheIdByDefinition = new LRUCache<string, string>(cacheOptions);\n private readonly cacheById = new LRUCache<string, string>(cacheOptions);\n\n /**\n * serializes the value parameter according to the input schema and creates a message\n * with the serialized data.\n *\n * @param value - The value to serialize.\n * @param schema - The Json schema to use.\n * @returns A new message with the serialized value. The structure of message is\n * constrolled by the message factory option.\n * @throws {@link Error}\n * Thrown if the schema can not be parsed or the value does not match the schema.\n */\n async serialize(value: unknown, schema: string): Promise<MessageT> {\n const entry = await this.getSchemaByDefinition(schema);\n const data = wrapError(\n () => encoder.encode(JSON.stringify(value)),\n `Json serialization failed. See 'cause' for more details. Schema ID: ${entry.id}`\n );\n const contentType = `${jsonMimeType}+${entry.id}`;\n return this.messageAdapter\n ? this.messageAdapter.produce({\n contentType,\n data,\n })\n : /**\n * If no message consumer was provided, then a MessageContent will be\n * returned. This should work because the MessageT type parameter defaults\n * to MessageContent.\n */\n ({\n data,\n contentType,\n } as MessageContent as unknown as MessageT);\n }\n\n /**\n * Deserializes the payload of the message using the schema ID in the content type\n * field if no schema was provided.\n *\n * @param message - The message with the payload to be deserialized.\n * @returns The deserialized value.\n * @throws {@link Error}\n * Thrown if the deserialization failed, e.g. because reader and writer schemas are incompatible.\n */\n async deserialize(message: MessageT, options?: DeserializeOptions): Promise<unknown> {\n const { data, contentType } = convertMessage(message, this.messageAdapter);\n const schemaId = getSchemaId(contentType);\n const schema = await this.getSchemaById(schemaId);\n const returnedMessage = wrapError(\n () => JSON.parse(decoder.decode(data)),\n `Json deserialization failed with schema ID (${schemaId}). See 'cause' for more details.`\n );\n const validate = options?.validateCallback;\n if (validate) {\n wrapError(\n () => validate(returnedMessage, schema),\n `Json validation failed. See 'cause' for more details. Schema ID: ${schemaId}`\n );\n }\n return returnedMessage;\n }\n\n private async getSchemaById(schemaId: string): Promise<string> {\n const cached = this.cacheById.get(schemaId);\n if (cached) {\n return cached;\n }\n const schemaResponse = await this.registry.getSchema(schemaId);\n if (!schemaResponse) {\n throw new Error(`Schema with ID '${schemaId}' not found.`);\n }\n\n if (!schemaResponse.properties.format.match(/^json$/i)) {\n throw new Error(\n `Schema with ID '${schemaResponse.properties.id}' has format '${schemaResponse.properties.format}', not 'json'.`\n );\n }\n return this.cache(schemaResponse.definition, schemaId).schema;\n }\n\n private async getSchemaByDefinition(definition: string): Promise<CacheEntry> {\n const schemaId = this.cacheIdByDefinition.get(definition);\n if (schemaId) {\n return { id: schemaId, schema: definition };\n }\n if (!this.schemaGroup) {\n throw new Error(\n \"Schema group must have been specified in the constructor options when the client was created in order to serialize.\"\n );\n }\n const schemaObj = getSchemaObject(definition);\n const description: SchemaDescription = {\n groupName: this.schemaGroup,\n name: getSchemaName(schemaObj),\n format: KnownSchemaFormats.Json,\n definition,\n };\n let id: string;\n\n try {\n id = (await this.registry.getSchemaProperties(description)).id;\n } catch (e) {\n if ((e as any).statusCode === 404) {\n throw errorWithCause(\n `Schema '${description.name}' not found in registry group '${description.groupName}', or not found to have matching definition.`,\n e as Error\n );\n } else {\n throw e;\n }\n }\n\n return this.cache(definition, id);\n }\n\n private cache(schema: string, id: string): CacheEntry {\n const entry = { schema, id };\n this.cacheIdByDefinition.set(schema, id);\n this.cacheById.set(id, schema);\n logger.verbose(\n `Cache entry added or updated. Total number of entries: ${this.cacheIdByDefinition.size}; Total schema length ${this.cacheIdByDefinition.calculatedSize}`\n );\n return entry;\n }\n}\n\nfunction getSchemaId(contentType: string): string {\n const contentTypeParts = contentType.split(\"+\");\n if (contentTypeParts.length !== 2) {\n throw new Error(\"Content type was not in the expected format of MIME type + schema ID\");\n }\n if (contentTypeParts[0] !== jsonMimeType) {\n throw new Error(\n `Received content of type ${contentTypeParts[0]} but an json serializer may only be used on content that is of '${jsonMimeType}' type`\n );\n }\n return contentTypeParts[1];\n}\n\nfunction convertMessage<MessageT>(\n message: MessageT,\n adapter?: MessageAdapter<MessageT>\n): MessageContent {\n const messageConsumer = adapter?.consume;\n if (messageConsumer) {\n return messageConsumer(message);\n } else if (isMessageContent(message)) {\n return message;\n } else {\n throw new Error(\n `Expected either a message adapter to be provided to the serializer or the input message to have data and contentType fields`\n );\n }\n}\n\nfunction getSchemaName(schema: SchemaObject): string {\n const id = schema.$id || schema.id;\n if (!id) {\n throw new Error(\"Schema must have an ID.\");\n }\n return id;\n}\n"]}
@@ -0,0 +1,8 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT license.
3
+ import { createClientLogger } from "@azure/logger";
4
+ /**
5
+ * The \@azure/logger configuration for the schema-registry-json package.
6
+ */
7
+ export const logger = createClientLogger("schema-registry-json");
8
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/logger.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAElC,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEnD;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,kBAAkB,CAAC,sBAAsB,CAAC,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { createClientLogger } from \"@azure/logger\";\n\n/**\n * The \\@azure/logger configuration for the schema-registry-json package.\n */\nexport const logger = createClientLogger(\"schema-registry-json\");\n"]}
@@ -0,0 +1,4 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT license.
3
+ export {};
4
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/models.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\n/**\n * A message that contains binary data and a content type.\n */\nexport interface MessageContent {\n /**\n * The message's binary data\n */\n data: Uint8Array;\n /**\n * The message's content type\n */\n contentType: string;\n}\n\n/**\n * MessageAdapter is an interface that converts to/from a concrete message type\n * to a MessageContent\n */\nexport interface MessageAdapter<MessageT> {\n /**\n * defines how to create a message from a payload and a content type\n */\n produce: (messageContent: MessageContent) => MessageT;\n /**\n * defines how to access the payload and the content type of a message\n */\n consume: (message: MessageT) => MessageContent;\n}\n\n/**\n * Options for Schema\n */\nexport interface JsonSerializerOptions<MessageT> {\n /**\n * The group name to be used when registering/looking up a schema. Must be specified\n * if `serialize` will be called.\n */\n groupName?: string;\n /**\n * Message Adapter enables the serializer to produce and consume custom messages.\n */\n messageAdapter?: MessageAdapter<MessageT>;\n}\n\n/**\n * The options to the deserialize method.\n */\nexport interface DeserializeOptions {\n /**\n * Validate the value against the schema. Raise an error if the validation is not successful.\n */\n validateCallback?: (value: unknown, schema: string) => void;\n}\n"]}
@@ -0,0 +1,7 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT license.
3
+ export function isMessageContent(message) {
4
+ const castMessage = message;
5
+ return castMessage.data !== undefined && castMessage.contentType !== undefined;
6
+ }
7
+ //# sourceMappingURL=utility.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utility.js","sourceRoot":"","sources":["../../src/utility.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,kCAAkC;AAIlC,MAAM,UAAU,gBAAgB,CAAC,OAAgB;IAC/C,MAAM,WAAW,GAAG,OAAyB,CAAC;IAC9C,OAAO,WAAW,CAAC,IAAI,KAAK,SAAS,IAAI,WAAW,CAAC,WAAW,KAAK,SAAS,CAAC;AACjF,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport { MessageContent } from \"./models\";\n\nexport function isMessageContent(message: unknown): message is MessageContent {\n const castMessage = message as MessageContent;\n return castMessage.data !== undefined && castMessage.contentType !== undefined;\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,115 @@
1
+ {
2
+ "name": "@azure/schema-registry-json",
3
+ "version": "1.0.0-alpha.20230809.1",
4
+ "description": "Schema Registry JSON Serializer Library with typescript type definitions for node.js and browser.",
5
+ "sdk-type": "client",
6
+ "main": "dist/index.js",
7
+ "module": "dist-esm/src/index.js",
8
+ "types": "types/schema-registry-json.d.ts",
9
+ "scripts": {
10
+ "audit": "node ../../../common/scripts/rush-audit.js && rimraf node_modules package-lock.json && npm i --package-lock-only 2>&1 && npm audit",
11
+ "build:browser": "tsc -p . && rollup -c rollup.test.config.js 2>&1",
12
+ "build:node": "tsc -p . && dev-tool run bundle --browser-test=false",
13
+ "build:samples": "echo Obsolete.",
14
+ "build:test": "tsc -p . && rollup -c rollup.test.config.js 2>&1",
15
+ "build": "npm run clean && tsc -p . && dev-tool run bundle && api-extractor run --local",
16
+ "check-format": "prettier --list-different --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"samples-dev/**/*.ts\" \"*.{js,json}\"",
17
+ "clean": "rimraf dist dist-* temp types *.tgz *.log",
18
+ "execute:samples": "dev-tool samples run samples-dev",
19
+ "extract-api": "tsc -p . && api-extractor run --local",
20
+ "format": "prettier --write --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"samples-dev/**/*.ts\" \"*.{js,json}\"",
21
+ "integration-test:browser": "dev-tool run test:browser",
22
+ "integration-test:node": "dev-tool run test:node-js-input -- --timeout 5000000 'dist-esm/test/**/*.spec.js'",
23
+ "integration-test": "npm run integration-test:node && npm run integration-test:browser",
24
+ "lint:fix": "eslint package.json api-extractor.json README.md src test --ext .ts,.javascript,.js --fix --fix-type [problem,suggestion]",
25
+ "lint": "eslint package.json api-extractor.json README.md src test --ext .ts,.javascript,.js",
26
+ "pack": "npm pack 2>&1",
27
+ "test:browser": "npm run build:test && npm run unit-test:browser && npm run integration-test:browser",
28
+ "test:node": "npm run build:test && npm run unit-test:node && npm run integration-test:node",
29
+ "test": "npm run build:test && npm run unit-test && npm run integration-test",
30
+ "unit-test:browser": "dev-tool run test:browser",
31
+ "unit-test:node": "dev-tool run test:node-ts-input -- --timeout 1200000 \"test/{,!(browser)/**/}*.spec.ts\"",
32
+ "unit-test": "npm run unit-test:node && npm run unit-test:browser"
33
+ },
34
+ "files": [
35
+ "dist/",
36
+ "dist-esm/src/",
37
+ "types/schema-registry-json.d.ts",
38
+ "README.md",
39
+ "LICENSE"
40
+ ],
41
+ "repository": "github:Azure/azure-sdk-for-js",
42
+ "engines": {
43
+ "node": ">=14.0.0"
44
+ },
45
+ "keywords": [
46
+ "azure",
47
+ "cloud",
48
+ "typescript"
49
+ ],
50
+ "author": "Microsoft Corporation",
51
+ "license": "MIT",
52
+ "bugs": {
53
+ "url": "https://github.com/Azure/azure-sdk-for-js/issues"
54
+ },
55
+ "homepage": "https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/schemaregistry/schema-registry-json/",
56
+ "sideEffects": false,
57
+ "prettier": "@azure/eslint-plugin-azure-sdk/prettier.json",
58
+ "//sampleConfiguration": {
59
+ "disableDocsMs": true,
60
+ "productName": "Azure Schema Registry",
61
+ "productSlugs": [
62
+ "azure",
63
+ "azure-schema-registry-json"
64
+ ],
65
+ "requiredResources": {
66
+ "Azure Schema Registry resource": "https://aka.ms/schemaregistry"
67
+ }
68
+ },
69
+ "dependencies": {
70
+ "@azure/logger": "^1.0.0",
71
+ "@azure/schema-registry": "1.3.0-beta.1",
72
+ "lru-cache": "^7.4.1",
73
+ "tslib": "^2.2.0"
74
+ },
75
+ "devDependencies": {
76
+ "@azure/core-util": "^1.3.0",
77
+ "@azure/dev-tool": ">=1.0.0-alpha <1.0.0-alphb",
78
+ "@azure/eslint-plugin-azure-sdk": ">=3.0.0-alpha <3.0.0-alphb",
79
+ "@azure/event-hubs": "^5.8.0",
80
+ "@azure/identity": "^2.0.1",
81
+ "@azure/test-utils": ">=1.0.0-alpha <1.0.0-alphb",
82
+ "@azure-tools/test-credential": "^1.0.0",
83
+ "@azure-tools/test-recorder": "^3.0.0",
84
+ "@microsoft/api-extractor": "^7.31.1",
85
+ "@rollup/plugin-commonjs": "^24.0.0",
86
+ "@rollup/plugin-inject": "^5.0.0",
87
+ "@types/ajv": "^1.0.0",
88
+ "@types/mocha": "^7.0.2",
89
+ "@types/node": "^16.0.0",
90
+ "ajv": "^8.12.0",
91
+ "cross-env": "^7.0.2",
92
+ "dotenv": "^16.0.0",
93
+ "eslint": "^8.0.0",
94
+ "karma": "^6.2.0",
95
+ "karma-chrome-launcher": "^3.0.0",
96
+ "karma-coverage": "^2.0.0",
97
+ "karma-env-preprocessor": "^0.1.1",
98
+ "karma-firefox-launcher": "^1.1.0",
99
+ "karma-json-preprocessor": "^0.3.3",
100
+ "karma-json-to-file-reporter": "^1.0.1",
101
+ "karma-junit-reporter": "^2.0.1",
102
+ "karma-mocha": "^2.0.1",
103
+ "karma-mocha-reporter": "^2.2.5",
104
+ "karma-sourcemap-loader": "^0.3.8",
105
+ "karma-source-map-support": "~1.4.0",
106
+ "mocha": "^7.1.1",
107
+ "mocha-junit-reporter": "^2.0.0",
108
+ "nyc": "^15.0.0",
109
+ "prettier": "^2.5.1",
110
+ "rimraf": "^3.0.0",
111
+ "rollup": "^2.0.0",
112
+ "source-map-support": "^0.5.9",
113
+ "typescript": "~5.0.0"
114
+ }
115
+ }
@@ -0,0 +1,101 @@
1
+ import { SchemaRegistry } from '@azure/schema-registry';
2
+
3
+ /**
4
+ * The options to the deserialize method.
5
+ */
6
+ export declare interface DeserializeOptions {
7
+ /**
8
+ * Validate the value against the schema. Raise an error if the validation is not successful.
9
+ */
10
+ validateCallback?: (value: unknown, schema: string) => void;
11
+ }
12
+
13
+ /**
14
+ * Json serializer that obtains schemas from a schema registry and does not
15
+ * pack schemas into its payloads.
16
+ */
17
+ export declare class JsonSerializer<MessageT = MessageContent> {
18
+ /**
19
+ * Creates a new serializer.
20
+ *
21
+ * @param client - Schema Registry where schemas are registered and obtained.
22
+ * Usually this is a SchemaRegistryClient instance.
23
+ */
24
+ constructor(client: SchemaRegistry, options?: JsonSerializerOptions<MessageT>);
25
+ private readonly schemaGroup?;
26
+ private readonly registry;
27
+ private readonly messageAdapter?;
28
+ private readonly cacheIdByDefinition;
29
+ private readonly cacheById;
30
+ /**
31
+ * serializes the value parameter according to the input schema and creates a message
32
+ * with the serialized data.
33
+ *
34
+ * @param value - The value to serialize.
35
+ * @param schema - The Json schema to use.
36
+ * @returns A new message with the serialized value. The structure of message is
37
+ * constrolled by the message factory option.
38
+ * @throws {@link Error}
39
+ * Thrown if the schema can not be parsed or the value does not match the schema.
40
+ */
41
+ serialize(value: unknown, schema: string): Promise<MessageT>;
42
+ /**
43
+ * Deserializes the payload of the message using the schema ID in the content type
44
+ * field if no schema was provided.
45
+ *
46
+ * @param message - The message with the payload to be deserialized.
47
+ * @returns The deserialized value.
48
+ * @throws {@link Error}
49
+ * Thrown if the deserialization failed, e.g. because reader and writer schemas are incompatible.
50
+ */
51
+ deserialize(message: MessageT, options?: DeserializeOptions): Promise<unknown>;
52
+ private getSchemaById;
53
+ private getSchemaByDefinition;
54
+ private cache;
55
+ }
56
+
57
+ /**
58
+ * Options for Schema
59
+ */
60
+ export declare interface JsonSerializerOptions<MessageT> {
61
+ /**
62
+ * The group name to be used when registering/looking up a schema. Must be specified
63
+ * if `serialize` will be called.
64
+ */
65
+ groupName?: string;
66
+ /**
67
+ * Message Adapter enables the serializer to produce and consume custom messages.
68
+ */
69
+ messageAdapter?: MessageAdapter<MessageT>;
70
+ }
71
+
72
+ /**
73
+ * MessageAdapter is an interface that converts to/from a concrete message type
74
+ * to a MessageContent
75
+ */
76
+ export declare interface MessageAdapter<MessageT> {
77
+ /**
78
+ * defines how to create a message from a payload and a content type
79
+ */
80
+ produce: (messageContent: MessageContent) => MessageT;
81
+ /**
82
+ * defines how to access the payload and the content type of a message
83
+ */
84
+ consume: (message: MessageT) => MessageContent;
85
+ }
86
+
87
+ /**
88
+ * A message that contains binary data and a content type.
89
+ */
90
+ export declare interface MessageContent {
91
+ /**
92
+ * The message's binary data
93
+ */
94
+ data: Uint8Array;
95
+ /**
96
+ * The message's content type
97
+ */
98
+ contentType: string;
99
+ }
100
+
101
+ export { }