瀏覽代碼

Add metadata-protobuf package + storage v2 metadata standards

Leszek Wiesner 3 年之前
父節點
當前提交
77b81e4b41

+ 4 - 0
metadata-protobuf/.eslintignore

@@ -0,0 +1,4 @@
+lib/
+proto/
+compiled/
+.eslintrc.js

+ 16 - 0
metadata-protobuf/.eslintrc.js

@@ -0,0 +1,16 @@
+module.exports = {
+  env: {
+    mocha: true,
+  },
+  parserOptions: {
+    project: './tsconfig.json'
+  },
+  extends: [
+    '@joystream/eslint-config'
+  ],
+  rules: {
+    'no-unused-vars': 'off', // Required by the typescript rule below
+    '@typescript-eslint/no-unused-vars': ['error'],
+    '@typescript-eslint/no-floating-promises': 'error',
+  },
+}

+ 2 - 0
metadata-protobuf/.gitignore

@@ -0,0 +1,2 @@
+node_modules/
+lib/

+ 4 - 0
metadata-protobuf/.prettierignore

@@ -0,0 +1,4 @@
+lib/
+doc/
+proto/
+compiled/

+ 53 - 0
metadata-protobuf/README.md

@@ -0,0 +1,53 @@
+## Joystream Content Directory Metadata Library
+
+This package contains protobuf message definitions compiled to Javascript/Typescript used for creating and updating various metadata blobs in the joystream content directory.
+
+### Message Specs
+
+Documented in [doc](./doc) folder
+
+### Choice of protobuf protocol v2
+
+For our usecase we wish to re-use same message to create and update  subset of fields.
+For this reason we need the explicit information about wether a field has been set or not and this is only possible with proto v2.
+
+Background: required/optional feilds are deprecated in [proto v3](https://www.ben-morris.com/handling-protocol-buffers-backwards-compatibility-between-versions-2-and-3-using-c/)
+
+
+### Helper methods
+The custom Joystream types such as License have helper methods to construct pre-defined well known values.
+
+### Example code:
+
+Best place to look at are the [tests specs](./test)
+
+### Opaque types
+We use simple [ISO_639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) code representation for Language.
+useful npm package https://www.npmjs.com/package/iso-639-1
+
+### Building the package
+
+Building will compile the protofiles and build the library from source.
+
+- pre-requisists for compiling protofiles:
+    - [protoc](https://github.com/protocolbuffers/protobuf/releases)
+
+- pre-requisists for generating documentation:
+    - [golang](https://golang.org/)
+    - [protoc-gen-doc](https://github.com/pseudomuto/protoc-gen-doc) to generate docs
+
+```
+yarn && yarn build
+```
+
+### Generating docs
+
+```
+yarn generate-docs
+```
+
+### Tests
+
+```
+yarn test
+```

+ 16 - 0
metadata-protobuf/compile.sh

@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+
+# Directory to write generated code to (.js and .d.ts files)
+OUT_DIR="./compiled"
+mkdir -p ${OUT_DIR}
+
+yarn pbjs \
+  -t="static-module" \
+  -w="commonjs" \
+  -o="${OUT_DIR}/index.js" \
+  --force-long \
+  proto/*.proto
+
+yarn pbts \
+  -o="${OUT_DIR}/index.d.ts" \
+  ${OUT_DIR}/*.js

+ 505 - 0
metadata-protobuf/compiled/index.d.ts

@@ -0,0 +1,505 @@
+import { Long } from 'long'
+import * as $protobuf from "protobufjs";
+/** Properties of a GeoCoordiantes. */
+export interface IGeoCoordiantes {
+
+    /** GeoCoordiantes latitude */
+    latitude: number;
+
+    /** GeoCoordiantes longitude */
+    longitude: number;
+}
+
+/** Represents a GeoCoordiantes. */
+export class GeoCoordiantes implements IGeoCoordiantes {
+
+    /**
+     * Constructs a new GeoCoordiantes.
+     * @param [properties] Properties to set
+     */
+    constructor(properties?: IGeoCoordiantes);
+
+    /** GeoCoordiantes latitude. */
+    public latitude: number;
+
+    /** GeoCoordiantes longitude. */
+    public longitude: number;
+
+    /**
+     * Creates a new GeoCoordiantes instance using the specified properties.
+     * @param [properties] Properties to set
+     * @returns GeoCoordiantes instance
+     */
+    public static create(properties?: IGeoCoordiantes): GeoCoordiantes;
+
+    /**
+     * Encodes the specified GeoCoordiantes message. Does not implicitly {@link GeoCoordiantes.verify|verify} messages.
+     * @param message GeoCoordiantes message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encode(message: IGeoCoordiantes, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Encodes the specified GeoCoordiantes message, length delimited. Does not implicitly {@link GeoCoordiantes.verify|verify} messages.
+     * @param message GeoCoordiantes message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encodeDelimited(message: IGeoCoordiantes, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Decodes a GeoCoordiantes message from the specified reader or buffer.
+     * @param reader Reader or buffer to decode from
+     * @param [length] Message length if known beforehand
+     * @returns GeoCoordiantes
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): GeoCoordiantes;
+
+    /**
+     * Decodes a GeoCoordiantes message from the specified reader or buffer, length delimited.
+     * @param reader Reader or buffer to decode from
+     * @returns GeoCoordiantes
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): GeoCoordiantes;
+
+    /**
+     * Verifies a GeoCoordiantes message.
+     * @param message Plain object to verify
+     * @returns `null` if valid, otherwise the reason why it is not
+     */
+    public static verify(message: { [k: string]: any }): (string|null);
+
+    /**
+     * Creates a GeoCoordiantes message from a plain object. Also converts values to their respective internal types.
+     * @param object Plain object
+     * @returns GeoCoordiantes
+     */
+    public static fromObject(object: { [k: string]: any }): GeoCoordiantes;
+
+    /**
+     * Creates a plain object from a GeoCoordiantes message. Also converts values to other types if specified.
+     * @param message GeoCoordiantes
+     * @param [options] Conversion options
+     * @returns Plain object
+     */
+    public static toObject(message: GeoCoordiantes, options?: $protobuf.IConversionOptions): { [k: string]: any };
+
+    /**
+     * Converts this GeoCoordiantes to JSON.
+     * @returns JSON object
+     */
+    public toJSON(): { [k: string]: any };
+}
+
+/** Properties of a NodeLocationMetadata. */
+export interface INodeLocationMetadata {
+
+    /** NodeLocationMetadata countryCode */
+    countryCode?: (string|null);
+
+    /** NodeLocationMetadata city */
+    city?: (string|null);
+
+    /** NodeLocationMetadata coordinates */
+    coordinates?: (IGeoCoordiantes|null);
+}
+
+/** Represents a NodeLocationMetadata. */
+export class NodeLocationMetadata implements INodeLocationMetadata {
+
+    /**
+     * Constructs a new NodeLocationMetadata.
+     * @param [properties] Properties to set
+     */
+    constructor(properties?: INodeLocationMetadata);
+
+    /** NodeLocationMetadata countryCode. */
+    public countryCode: string;
+
+    /** NodeLocationMetadata city. */
+    public city: string;
+
+    /** NodeLocationMetadata coordinates. */
+    public coordinates?: (IGeoCoordiantes|null);
+
+    /**
+     * Creates a new NodeLocationMetadata instance using the specified properties.
+     * @param [properties] Properties to set
+     * @returns NodeLocationMetadata instance
+     */
+    public static create(properties?: INodeLocationMetadata): NodeLocationMetadata;
+
+    /**
+     * Encodes the specified NodeLocationMetadata message. Does not implicitly {@link NodeLocationMetadata.verify|verify} messages.
+     * @param message NodeLocationMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encode(message: INodeLocationMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Encodes the specified NodeLocationMetadata message, length delimited. Does not implicitly {@link NodeLocationMetadata.verify|verify} messages.
+     * @param message NodeLocationMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encodeDelimited(message: INodeLocationMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Decodes a NodeLocationMetadata message from the specified reader or buffer.
+     * @param reader Reader or buffer to decode from
+     * @param [length] Message length if known beforehand
+     * @returns NodeLocationMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): NodeLocationMetadata;
+
+    /**
+     * Decodes a NodeLocationMetadata message from the specified reader or buffer, length delimited.
+     * @param reader Reader or buffer to decode from
+     * @returns NodeLocationMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): NodeLocationMetadata;
+
+    /**
+     * Verifies a NodeLocationMetadata message.
+     * @param message Plain object to verify
+     * @returns `null` if valid, otherwise the reason why it is not
+     */
+    public static verify(message: { [k: string]: any }): (string|null);
+
+    /**
+     * Creates a NodeLocationMetadata message from a plain object. Also converts values to their respective internal types.
+     * @param object Plain object
+     * @returns NodeLocationMetadata
+     */
+    public static fromObject(object: { [k: string]: any }): NodeLocationMetadata;
+
+    /**
+     * Creates a plain object from a NodeLocationMetadata message. Also converts values to other types if specified.
+     * @param message NodeLocationMetadata
+     * @param [options] Conversion options
+     * @returns Plain object
+     */
+    public static toObject(message: NodeLocationMetadata, options?: $protobuf.IConversionOptions): { [k: string]: any };
+
+    /**
+     * Converts this NodeLocationMetadata to JSON.
+     * @returns JSON object
+     */
+    public toJSON(): { [k: string]: any };
+}
+
+/** Properties of a StorageBucketOperatorMetadata. */
+export interface IStorageBucketOperatorMetadata {
+
+    /** StorageBucketOperatorMetadata endpoint */
+    endpoint?: (string|null);
+
+    /** StorageBucketOperatorMetadata location */
+    location?: (INodeLocationMetadata|null);
+
+    /** StorageBucketOperatorMetadata extra */
+    extra?: (string|null);
+}
+
+/** Represents a StorageBucketOperatorMetadata. */
+export class StorageBucketOperatorMetadata implements IStorageBucketOperatorMetadata {
+
+    /**
+     * Constructs a new StorageBucketOperatorMetadata.
+     * @param [properties] Properties to set
+     */
+    constructor(properties?: IStorageBucketOperatorMetadata);
+
+    /** StorageBucketOperatorMetadata endpoint. */
+    public endpoint: string;
+
+    /** StorageBucketOperatorMetadata location. */
+    public location?: (INodeLocationMetadata|null);
+
+    /** StorageBucketOperatorMetadata extra. */
+    public extra: string;
+
+    /**
+     * Creates a new StorageBucketOperatorMetadata instance using the specified properties.
+     * @param [properties] Properties to set
+     * @returns StorageBucketOperatorMetadata instance
+     */
+    public static create(properties?: IStorageBucketOperatorMetadata): StorageBucketOperatorMetadata;
+
+    /**
+     * Encodes the specified StorageBucketOperatorMetadata message. Does not implicitly {@link StorageBucketOperatorMetadata.verify|verify} messages.
+     * @param message StorageBucketOperatorMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encode(message: IStorageBucketOperatorMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Encodes the specified StorageBucketOperatorMetadata message, length delimited. Does not implicitly {@link StorageBucketOperatorMetadata.verify|verify} messages.
+     * @param message StorageBucketOperatorMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encodeDelimited(message: IStorageBucketOperatorMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Decodes a StorageBucketOperatorMetadata message from the specified reader or buffer.
+     * @param reader Reader or buffer to decode from
+     * @param [length] Message length if known beforehand
+     * @returns StorageBucketOperatorMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): StorageBucketOperatorMetadata;
+
+    /**
+     * Decodes a StorageBucketOperatorMetadata message from the specified reader or buffer, length delimited.
+     * @param reader Reader or buffer to decode from
+     * @returns StorageBucketOperatorMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): StorageBucketOperatorMetadata;
+
+    /**
+     * Verifies a StorageBucketOperatorMetadata message.
+     * @param message Plain object to verify
+     * @returns `null` if valid, otherwise the reason why it is not
+     */
+    public static verify(message: { [k: string]: any }): (string|null);
+
+    /**
+     * Creates a StorageBucketOperatorMetadata message from a plain object. Also converts values to their respective internal types.
+     * @param object Plain object
+     * @returns StorageBucketOperatorMetadata
+     */
+    public static fromObject(object: { [k: string]: any }): StorageBucketOperatorMetadata;
+
+    /**
+     * Creates a plain object from a StorageBucketOperatorMetadata message. Also converts values to other types if specified.
+     * @param message StorageBucketOperatorMetadata
+     * @param [options] Conversion options
+     * @returns Plain object
+     */
+    public static toObject(message: StorageBucketOperatorMetadata, options?: $protobuf.IConversionOptions): { [k: string]: any };
+
+    /**
+     * Converts this StorageBucketOperatorMetadata to JSON.
+     * @returns JSON object
+     */
+    public toJSON(): { [k: string]: any };
+}
+
+/** Properties of a DistributionBucketOperatorMetadata. */
+export interface IDistributionBucketOperatorMetadata {
+
+    /** DistributionBucketOperatorMetadata endpoint */
+    endpoint?: (string|null);
+
+    /** DistributionBucketOperatorMetadata location */
+    location?: (INodeLocationMetadata|null);
+
+    /** DistributionBucketOperatorMetadata extra */
+    extra?: (string|null);
+}
+
+/** Represents a DistributionBucketOperatorMetadata. */
+export class DistributionBucketOperatorMetadata implements IDistributionBucketOperatorMetadata {
+
+    /**
+     * Constructs a new DistributionBucketOperatorMetadata.
+     * @param [properties] Properties to set
+     */
+    constructor(properties?: IDistributionBucketOperatorMetadata);
+
+    /** DistributionBucketOperatorMetadata endpoint. */
+    public endpoint: string;
+
+    /** DistributionBucketOperatorMetadata location. */
+    public location?: (INodeLocationMetadata|null);
+
+    /** DistributionBucketOperatorMetadata extra. */
+    public extra: string;
+
+    /**
+     * Creates a new DistributionBucketOperatorMetadata instance using the specified properties.
+     * @param [properties] Properties to set
+     * @returns DistributionBucketOperatorMetadata instance
+     */
+    public static create(properties?: IDistributionBucketOperatorMetadata): DistributionBucketOperatorMetadata;
+
+    /**
+     * Encodes the specified DistributionBucketOperatorMetadata message. Does not implicitly {@link DistributionBucketOperatorMetadata.verify|verify} messages.
+     * @param message DistributionBucketOperatorMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encode(message: IDistributionBucketOperatorMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Encodes the specified DistributionBucketOperatorMetadata message, length delimited. Does not implicitly {@link DistributionBucketOperatorMetadata.verify|verify} messages.
+     * @param message DistributionBucketOperatorMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encodeDelimited(message: IDistributionBucketOperatorMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Decodes a DistributionBucketOperatorMetadata message from the specified reader or buffer.
+     * @param reader Reader or buffer to decode from
+     * @param [length] Message length if known beforehand
+     * @returns DistributionBucketOperatorMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): DistributionBucketOperatorMetadata;
+
+    /**
+     * Decodes a DistributionBucketOperatorMetadata message from the specified reader or buffer, length delimited.
+     * @param reader Reader or buffer to decode from
+     * @returns DistributionBucketOperatorMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): DistributionBucketOperatorMetadata;
+
+    /**
+     * Verifies a DistributionBucketOperatorMetadata message.
+     * @param message Plain object to verify
+     * @returns `null` if valid, otherwise the reason why it is not
+     */
+    public static verify(message: { [k: string]: any }): (string|null);
+
+    /**
+     * Creates a DistributionBucketOperatorMetadata message from a plain object. Also converts values to their respective internal types.
+     * @param object Plain object
+     * @returns DistributionBucketOperatorMetadata
+     */
+    public static fromObject(object: { [k: string]: any }): DistributionBucketOperatorMetadata;
+
+    /**
+     * Creates a plain object from a DistributionBucketOperatorMetadata message. Also converts values to other types if specified.
+     * @param message DistributionBucketOperatorMetadata
+     * @param [options] Conversion options
+     * @returns Plain object
+     */
+    public static toObject(message: DistributionBucketOperatorMetadata, options?: $protobuf.IConversionOptions): { [k: string]: any };
+
+    /**
+     * Converts this DistributionBucketOperatorMetadata to JSON.
+     * @returns JSON object
+     */
+    public toJSON(): { [k: string]: any };
+}
+
+/** Properties of a DistributionBucketFamilyMetadata. */
+export interface IDistributionBucketFamilyMetadata {
+
+    /** DistributionBucketFamilyMetadata region */
+    region?: (string|null);
+
+    /** DistributionBucketFamilyMetadata description */
+    description?: (string|null);
+
+    /** DistributionBucketFamilyMetadata boundary */
+    boundary?: (IGeoCoordiantes[]|null);
+}
+
+/** Represents a DistributionBucketFamilyMetadata. */
+export class DistributionBucketFamilyMetadata implements IDistributionBucketFamilyMetadata {
+
+    /**
+     * Constructs a new DistributionBucketFamilyMetadata.
+     * @param [properties] Properties to set
+     */
+    constructor(properties?: IDistributionBucketFamilyMetadata);
+
+    /** DistributionBucketFamilyMetadata region. */
+    public region: string;
+
+    /** DistributionBucketFamilyMetadata description. */
+    public description: string;
+
+    /** DistributionBucketFamilyMetadata boundary. */
+    public boundary: IGeoCoordiantes[];
+
+    /**
+     * Creates a new DistributionBucketFamilyMetadata instance using the specified properties.
+     * @param [properties] Properties to set
+     * @returns DistributionBucketFamilyMetadata instance
+     */
+    public static create(properties?: IDistributionBucketFamilyMetadata): DistributionBucketFamilyMetadata;
+
+    /**
+     * Encodes the specified DistributionBucketFamilyMetadata message. Does not implicitly {@link DistributionBucketFamilyMetadata.verify|verify} messages.
+     * @param message DistributionBucketFamilyMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encode(message: IDistributionBucketFamilyMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Encodes the specified DistributionBucketFamilyMetadata message, length delimited. Does not implicitly {@link DistributionBucketFamilyMetadata.verify|verify} messages.
+     * @param message DistributionBucketFamilyMetadata message or plain object to encode
+     * @param [writer] Writer to encode to
+     * @returns Writer
+     */
+    public static encodeDelimited(message: IDistributionBucketFamilyMetadata, writer?: $protobuf.Writer): $protobuf.Writer;
+
+    /**
+     * Decodes a DistributionBucketFamilyMetadata message from the specified reader or buffer.
+     * @param reader Reader or buffer to decode from
+     * @param [length] Message length if known beforehand
+     * @returns DistributionBucketFamilyMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): DistributionBucketFamilyMetadata;
+
+    /**
+     * Decodes a DistributionBucketFamilyMetadata message from the specified reader or buffer, length delimited.
+     * @param reader Reader or buffer to decode from
+     * @returns DistributionBucketFamilyMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): DistributionBucketFamilyMetadata;
+
+    /**
+     * Verifies a DistributionBucketFamilyMetadata message.
+     * @param message Plain object to verify
+     * @returns `null` if valid, otherwise the reason why it is not
+     */
+    public static verify(message: { [k: string]: any }): (string|null);
+
+    /**
+     * Creates a DistributionBucketFamilyMetadata message from a plain object. Also converts values to their respective internal types.
+     * @param object Plain object
+     * @returns DistributionBucketFamilyMetadata
+     */
+    public static fromObject(object: { [k: string]: any }): DistributionBucketFamilyMetadata;
+
+    /**
+     * Creates a plain object from a DistributionBucketFamilyMetadata message. Also converts values to other types if specified.
+     * @param message DistributionBucketFamilyMetadata
+     * @param [options] Conversion options
+     * @returns Plain object
+     */
+    public static toObject(message: DistributionBucketFamilyMetadata, options?: $protobuf.IConversionOptions): { [k: string]: any };
+
+    /**
+     * Converts this DistributionBucketFamilyMetadata to JSON.
+     * @returns JSON object
+     */
+    public toJSON(): { [k: string]: any };
+}

+ 1187 - 0
metadata-protobuf/compiled/index.js

@@ -0,0 +1,1187 @@
+/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/
+"use strict";
+
+var $protobuf = require("protobufjs/minimal");
+
+// Common aliases
+var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
+
+// Exported root namespace
+var $root = $protobuf.roots["default"] || ($protobuf.roots["default"] = {});
+
+$root.GeoCoordiantes = (function() {
+
+    /**
+     * Properties of a GeoCoordiantes.
+     * @exports IGeoCoordiantes
+     * @interface IGeoCoordiantes
+     * @property {number} latitude GeoCoordiantes latitude
+     * @property {number} longitude GeoCoordiantes longitude
+     */
+
+    /**
+     * Constructs a new GeoCoordiantes.
+     * @exports GeoCoordiantes
+     * @classdesc Represents a GeoCoordiantes.
+     * @implements IGeoCoordiantes
+     * @constructor
+     * @param {IGeoCoordiantes=} [properties] Properties to set
+     */
+    function GeoCoordiantes(properties) {
+        if (properties)
+            for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                if (properties[keys[i]] != null)
+                    this[keys[i]] = properties[keys[i]];
+    }
+
+    /**
+     * GeoCoordiantes latitude.
+     * @member {number} latitude
+     * @memberof GeoCoordiantes
+     * @instance
+     */
+    GeoCoordiantes.prototype.latitude = 0;
+
+    /**
+     * GeoCoordiantes longitude.
+     * @member {number} longitude
+     * @memberof GeoCoordiantes
+     * @instance
+     */
+    GeoCoordiantes.prototype.longitude = 0;
+
+    /**
+     * Creates a new GeoCoordiantes instance using the specified properties.
+     * @function create
+     * @memberof GeoCoordiantes
+     * @static
+     * @param {IGeoCoordiantes=} [properties] Properties to set
+     * @returns {GeoCoordiantes} GeoCoordiantes instance
+     */
+    GeoCoordiantes.create = function create(properties) {
+        return new GeoCoordiantes(properties);
+    };
+
+    /**
+     * Encodes the specified GeoCoordiantes message. Does not implicitly {@link GeoCoordiantes.verify|verify} messages.
+     * @function encode
+     * @memberof GeoCoordiantes
+     * @static
+     * @param {IGeoCoordiantes} message GeoCoordiantes message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    GeoCoordiantes.encode = function encode(message, writer) {
+        if (!writer)
+            writer = $Writer.create();
+        writer.uint32(/* id 3, wireType 5 =*/29).float(message.latitude);
+        writer.uint32(/* id 4, wireType 5 =*/37).float(message.longitude);
+        return writer;
+    };
+
+    /**
+     * Encodes the specified GeoCoordiantes message, length delimited. Does not implicitly {@link GeoCoordiantes.verify|verify} messages.
+     * @function encodeDelimited
+     * @memberof GeoCoordiantes
+     * @static
+     * @param {IGeoCoordiantes} message GeoCoordiantes message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    GeoCoordiantes.encodeDelimited = function encodeDelimited(message, writer) {
+        return this.encode(message, writer).ldelim();
+    };
+
+    /**
+     * Decodes a GeoCoordiantes message from the specified reader or buffer.
+     * @function decode
+     * @memberof GeoCoordiantes
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @param {number} [length] Message length if known beforehand
+     * @returns {GeoCoordiantes} GeoCoordiantes
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    GeoCoordiantes.decode = function decode(reader, length) {
+        if (!(reader instanceof $Reader))
+            reader = $Reader.create(reader);
+        var end = length === undefined ? reader.len : reader.pos + length, message = new $root.GeoCoordiantes();
+        while (reader.pos < end) {
+            var tag = reader.uint32();
+            switch (tag >>> 3) {
+            case 3:
+                message.latitude = reader.float();
+                break;
+            case 4:
+                message.longitude = reader.float();
+                break;
+            default:
+                reader.skipType(tag & 7);
+                break;
+            }
+        }
+        if (!message.hasOwnProperty("latitude"))
+            throw $util.ProtocolError("missing required 'latitude'", { instance: message });
+        if (!message.hasOwnProperty("longitude"))
+            throw $util.ProtocolError("missing required 'longitude'", { instance: message });
+        return message;
+    };
+
+    /**
+     * Decodes a GeoCoordiantes message from the specified reader or buffer, length delimited.
+     * @function decodeDelimited
+     * @memberof GeoCoordiantes
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @returns {GeoCoordiantes} GeoCoordiantes
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    GeoCoordiantes.decodeDelimited = function decodeDelimited(reader) {
+        if (!(reader instanceof $Reader))
+            reader = new $Reader(reader);
+        return this.decode(reader, reader.uint32());
+    };
+
+    /**
+     * Verifies a GeoCoordiantes message.
+     * @function verify
+     * @memberof GeoCoordiantes
+     * @static
+     * @param {Object.<string,*>} message Plain object to verify
+     * @returns {string|null} `null` if valid, otherwise the reason why it is not
+     */
+    GeoCoordiantes.verify = function verify(message) {
+        if (typeof message !== "object" || message === null)
+            return "object expected";
+        if (typeof message.latitude !== "number")
+            return "latitude: number expected";
+        if (typeof message.longitude !== "number")
+            return "longitude: number expected";
+        return null;
+    };
+
+    /**
+     * Creates a GeoCoordiantes message from a plain object. Also converts values to their respective internal types.
+     * @function fromObject
+     * @memberof GeoCoordiantes
+     * @static
+     * @param {Object.<string,*>} object Plain object
+     * @returns {GeoCoordiantes} GeoCoordiantes
+     */
+    GeoCoordiantes.fromObject = function fromObject(object) {
+        if (object instanceof $root.GeoCoordiantes)
+            return object;
+        var message = new $root.GeoCoordiantes();
+        if (object.latitude != null)
+            message.latitude = Number(object.latitude);
+        if (object.longitude != null)
+            message.longitude = Number(object.longitude);
+        return message;
+    };
+
+    /**
+     * Creates a plain object from a GeoCoordiantes message. Also converts values to other types if specified.
+     * @function toObject
+     * @memberof GeoCoordiantes
+     * @static
+     * @param {GeoCoordiantes} message GeoCoordiantes
+     * @param {$protobuf.IConversionOptions} [options] Conversion options
+     * @returns {Object.<string,*>} Plain object
+     */
+    GeoCoordiantes.toObject = function toObject(message, options) {
+        if (!options)
+            options = {};
+        var object = {};
+        if (options.defaults) {
+            object.latitude = 0;
+            object.longitude = 0;
+        }
+        if (message.latitude != null && message.hasOwnProperty("latitude"))
+            object.latitude = options.json && !isFinite(message.latitude) ? String(message.latitude) : message.latitude;
+        if (message.longitude != null && message.hasOwnProperty("longitude"))
+            object.longitude = options.json && !isFinite(message.longitude) ? String(message.longitude) : message.longitude;
+        return object;
+    };
+
+    /**
+     * Converts this GeoCoordiantes to JSON.
+     * @function toJSON
+     * @memberof GeoCoordiantes
+     * @instance
+     * @returns {Object.<string,*>} JSON object
+     */
+    GeoCoordiantes.prototype.toJSON = function toJSON() {
+        return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+    };
+
+    return GeoCoordiantes;
+})();
+
+$root.NodeLocationMetadata = (function() {
+
+    /**
+     * Properties of a NodeLocationMetadata.
+     * @exports INodeLocationMetadata
+     * @interface INodeLocationMetadata
+     * @property {string|null} [countryCode] NodeLocationMetadata countryCode
+     * @property {string|null} [city] NodeLocationMetadata city
+     * @property {IGeoCoordiantes|null} [coordinates] NodeLocationMetadata coordinates
+     */
+
+    /**
+     * Constructs a new NodeLocationMetadata.
+     * @exports NodeLocationMetadata
+     * @classdesc Represents a NodeLocationMetadata.
+     * @implements INodeLocationMetadata
+     * @constructor
+     * @param {INodeLocationMetadata=} [properties] Properties to set
+     */
+    function NodeLocationMetadata(properties) {
+        if (properties)
+            for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                if (properties[keys[i]] != null)
+                    this[keys[i]] = properties[keys[i]];
+    }
+
+    /**
+     * NodeLocationMetadata countryCode.
+     * @member {string} countryCode
+     * @memberof NodeLocationMetadata
+     * @instance
+     */
+    NodeLocationMetadata.prototype.countryCode = "";
+
+    /**
+     * NodeLocationMetadata city.
+     * @member {string} city
+     * @memberof NodeLocationMetadata
+     * @instance
+     */
+    NodeLocationMetadata.prototype.city = "";
+
+    /**
+     * NodeLocationMetadata coordinates.
+     * @member {IGeoCoordiantes|null|undefined} coordinates
+     * @memberof NodeLocationMetadata
+     * @instance
+     */
+    NodeLocationMetadata.prototype.coordinates = null;
+
+    /**
+     * Creates a new NodeLocationMetadata instance using the specified properties.
+     * @function create
+     * @memberof NodeLocationMetadata
+     * @static
+     * @param {INodeLocationMetadata=} [properties] Properties to set
+     * @returns {NodeLocationMetadata} NodeLocationMetadata instance
+     */
+    NodeLocationMetadata.create = function create(properties) {
+        return new NodeLocationMetadata(properties);
+    };
+
+    /**
+     * Encodes the specified NodeLocationMetadata message. Does not implicitly {@link NodeLocationMetadata.verify|verify} messages.
+     * @function encode
+     * @memberof NodeLocationMetadata
+     * @static
+     * @param {INodeLocationMetadata} message NodeLocationMetadata message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    NodeLocationMetadata.encode = function encode(message, writer) {
+        if (!writer)
+            writer = $Writer.create();
+        if (message.countryCode != null && Object.hasOwnProperty.call(message, "countryCode"))
+            writer.uint32(/* id 1, wireType 2 =*/10).string(message.countryCode);
+        if (message.city != null && Object.hasOwnProperty.call(message, "city"))
+            writer.uint32(/* id 2, wireType 2 =*/18).string(message.city);
+        if (message.coordinates != null && Object.hasOwnProperty.call(message, "coordinates"))
+            $root.GeoCoordiantes.encode(message.coordinates, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim();
+        return writer;
+    };
+
+    /**
+     * Encodes the specified NodeLocationMetadata message, length delimited. Does not implicitly {@link NodeLocationMetadata.verify|verify} messages.
+     * @function encodeDelimited
+     * @memberof NodeLocationMetadata
+     * @static
+     * @param {INodeLocationMetadata} message NodeLocationMetadata message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    NodeLocationMetadata.encodeDelimited = function encodeDelimited(message, writer) {
+        return this.encode(message, writer).ldelim();
+    };
+
+    /**
+     * Decodes a NodeLocationMetadata message from the specified reader or buffer.
+     * @function decode
+     * @memberof NodeLocationMetadata
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @param {number} [length] Message length if known beforehand
+     * @returns {NodeLocationMetadata} NodeLocationMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    NodeLocationMetadata.decode = function decode(reader, length) {
+        if (!(reader instanceof $Reader))
+            reader = $Reader.create(reader);
+        var end = length === undefined ? reader.len : reader.pos + length, message = new $root.NodeLocationMetadata();
+        while (reader.pos < end) {
+            var tag = reader.uint32();
+            switch (tag >>> 3) {
+            case 1:
+                message.countryCode = reader.string();
+                break;
+            case 2:
+                message.city = reader.string();
+                break;
+            case 3:
+                message.coordinates = $root.GeoCoordiantes.decode(reader, reader.uint32());
+                break;
+            default:
+                reader.skipType(tag & 7);
+                break;
+            }
+        }
+        return message;
+    };
+
+    /**
+     * Decodes a NodeLocationMetadata message from the specified reader or buffer, length delimited.
+     * @function decodeDelimited
+     * @memberof NodeLocationMetadata
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @returns {NodeLocationMetadata} NodeLocationMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    NodeLocationMetadata.decodeDelimited = function decodeDelimited(reader) {
+        if (!(reader instanceof $Reader))
+            reader = new $Reader(reader);
+        return this.decode(reader, reader.uint32());
+    };
+
+    /**
+     * Verifies a NodeLocationMetadata message.
+     * @function verify
+     * @memberof NodeLocationMetadata
+     * @static
+     * @param {Object.<string,*>} message Plain object to verify
+     * @returns {string|null} `null` if valid, otherwise the reason why it is not
+     */
+    NodeLocationMetadata.verify = function verify(message) {
+        if (typeof message !== "object" || message === null)
+            return "object expected";
+        if (message.countryCode != null && message.hasOwnProperty("countryCode"))
+            if (!$util.isString(message.countryCode))
+                return "countryCode: string expected";
+        if (message.city != null && message.hasOwnProperty("city"))
+            if (!$util.isString(message.city))
+                return "city: string expected";
+        if (message.coordinates != null && message.hasOwnProperty("coordinates")) {
+            var error = $root.GeoCoordiantes.verify(message.coordinates);
+            if (error)
+                return "coordinates." + error;
+        }
+        return null;
+    };
+
+    /**
+     * Creates a NodeLocationMetadata message from a plain object. Also converts values to their respective internal types.
+     * @function fromObject
+     * @memberof NodeLocationMetadata
+     * @static
+     * @param {Object.<string,*>} object Plain object
+     * @returns {NodeLocationMetadata} NodeLocationMetadata
+     */
+    NodeLocationMetadata.fromObject = function fromObject(object) {
+        if (object instanceof $root.NodeLocationMetadata)
+            return object;
+        var message = new $root.NodeLocationMetadata();
+        if (object.countryCode != null)
+            message.countryCode = String(object.countryCode);
+        if (object.city != null)
+            message.city = String(object.city);
+        if (object.coordinates != null) {
+            if (typeof object.coordinates !== "object")
+                throw TypeError(".NodeLocationMetadata.coordinates: object expected");
+            message.coordinates = $root.GeoCoordiantes.fromObject(object.coordinates);
+        }
+        return message;
+    };
+
+    /**
+     * Creates a plain object from a NodeLocationMetadata message. Also converts values to other types if specified.
+     * @function toObject
+     * @memberof NodeLocationMetadata
+     * @static
+     * @param {NodeLocationMetadata} message NodeLocationMetadata
+     * @param {$protobuf.IConversionOptions} [options] Conversion options
+     * @returns {Object.<string,*>} Plain object
+     */
+    NodeLocationMetadata.toObject = function toObject(message, options) {
+        if (!options)
+            options = {};
+        var object = {};
+        if (options.defaults) {
+            object.countryCode = "";
+            object.city = "";
+            object.coordinates = null;
+        }
+        if (message.countryCode != null && message.hasOwnProperty("countryCode"))
+            object.countryCode = message.countryCode;
+        if (message.city != null && message.hasOwnProperty("city"))
+            object.city = message.city;
+        if (message.coordinates != null && message.hasOwnProperty("coordinates"))
+            object.coordinates = $root.GeoCoordiantes.toObject(message.coordinates, options);
+        return object;
+    };
+
+    /**
+     * Converts this NodeLocationMetadata to JSON.
+     * @function toJSON
+     * @memberof NodeLocationMetadata
+     * @instance
+     * @returns {Object.<string,*>} JSON object
+     */
+    NodeLocationMetadata.prototype.toJSON = function toJSON() {
+        return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+    };
+
+    return NodeLocationMetadata;
+})();
+
+$root.StorageBucketOperatorMetadata = (function() {
+
+    /**
+     * Properties of a StorageBucketOperatorMetadata.
+     * @exports IStorageBucketOperatorMetadata
+     * @interface IStorageBucketOperatorMetadata
+     * @property {string|null} [endpoint] StorageBucketOperatorMetadata endpoint
+     * @property {INodeLocationMetadata|null} [location] StorageBucketOperatorMetadata location
+     * @property {string|null} [extra] StorageBucketOperatorMetadata extra
+     */
+
+    /**
+     * Constructs a new StorageBucketOperatorMetadata.
+     * @exports StorageBucketOperatorMetadata
+     * @classdesc Represents a StorageBucketOperatorMetadata.
+     * @implements IStorageBucketOperatorMetadata
+     * @constructor
+     * @param {IStorageBucketOperatorMetadata=} [properties] Properties to set
+     */
+    function StorageBucketOperatorMetadata(properties) {
+        if (properties)
+            for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                if (properties[keys[i]] != null)
+                    this[keys[i]] = properties[keys[i]];
+    }
+
+    /**
+     * StorageBucketOperatorMetadata endpoint.
+     * @member {string} endpoint
+     * @memberof StorageBucketOperatorMetadata
+     * @instance
+     */
+    StorageBucketOperatorMetadata.prototype.endpoint = "";
+
+    /**
+     * StorageBucketOperatorMetadata location.
+     * @member {INodeLocationMetadata|null|undefined} location
+     * @memberof StorageBucketOperatorMetadata
+     * @instance
+     */
+    StorageBucketOperatorMetadata.prototype.location = null;
+
+    /**
+     * StorageBucketOperatorMetadata extra.
+     * @member {string} extra
+     * @memberof StorageBucketOperatorMetadata
+     * @instance
+     */
+    StorageBucketOperatorMetadata.prototype.extra = "";
+
+    /**
+     * Creates a new StorageBucketOperatorMetadata instance using the specified properties.
+     * @function create
+     * @memberof StorageBucketOperatorMetadata
+     * @static
+     * @param {IStorageBucketOperatorMetadata=} [properties] Properties to set
+     * @returns {StorageBucketOperatorMetadata} StorageBucketOperatorMetadata instance
+     */
+    StorageBucketOperatorMetadata.create = function create(properties) {
+        return new StorageBucketOperatorMetadata(properties);
+    };
+
+    /**
+     * Encodes the specified StorageBucketOperatorMetadata message. Does not implicitly {@link StorageBucketOperatorMetadata.verify|verify} messages.
+     * @function encode
+     * @memberof StorageBucketOperatorMetadata
+     * @static
+     * @param {IStorageBucketOperatorMetadata} message StorageBucketOperatorMetadata message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    StorageBucketOperatorMetadata.encode = function encode(message, writer) {
+        if (!writer)
+            writer = $Writer.create();
+        if (message.endpoint != null && Object.hasOwnProperty.call(message, "endpoint"))
+            writer.uint32(/* id 1, wireType 2 =*/10).string(message.endpoint);
+        if (message.location != null && Object.hasOwnProperty.call(message, "location"))
+            $root.NodeLocationMetadata.encode(message.location, writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim();
+        if (message.extra != null && Object.hasOwnProperty.call(message, "extra"))
+            writer.uint32(/* id 3, wireType 2 =*/26).string(message.extra);
+        return writer;
+    };
+
+    /**
+     * Encodes the specified StorageBucketOperatorMetadata message, length delimited. Does not implicitly {@link StorageBucketOperatorMetadata.verify|verify} messages.
+     * @function encodeDelimited
+     * @memberof StorageBucketOperatorMetadata
+     * @static
+     * @param {IStorageBucketOperatorMetadata} message StorageBucketOperatorMetadata message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    StorageBucketOperatorMetadata.encodeDelimited = function encodeDelimited(message, writer) {
+        return this.encode(message, writer).ldelim();
+    };
+
+    /**
+     * Decodes a StorageBucketOperatorMetadata message from the specified reader or buffer.
+     * @function decode
+     * @memberof StorageBucketOperatorMetadata
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @param {number} [length] Message length if known beforehand
+     * @returns {StorageBucketOperatorMetadata} StorageBucketOperatorMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    StorageBucketOperatorMetadata.decode = function decode(reader, length) {
+        if (!(reader instanceof $Reader))
+            reader = $Reader.create(reader);
+        var end = length === undefined ? reader.len : reader.pos + length, message = new $root.StorageBucketOperatorMetadata();
+        while (reader.pos < end) {
+            var tag = reader.uint32();
+            switch (tag >>> 3) {
+            case 1:
+                message.endpoint = reader.string();
+                break;
+            case 2:
+                message.location = $root.NodeLocationMetadata.decode(reader, reader.uint32());
+                break;
+            case 3:
+                message.extra = reader.string();
+                break;
+            default:
+                reader.skipType(tag & 7);
+                break;
+            }
+        }
+        return message;
+    };
+
+    /**
+     * Decodes a StorageBucketOperatorMetadata message from the specified reader or buffer, length delimited.
+     * @function decodeDelimited
+     * @memberof StorageBucketOperatorMetadata
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @returns {StorageBucketOperatorMetadata} StorageBucketOperatorMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    StorageBucketOperatorMetadata.decodeDelimited = function decodeDelimited(reader) {
+        if (!(reader instanceof $Reader))
+            reader = new $Reader(reader);
+        return this.decode(reader, reader.uint32());
+    };
+
+    /**
+     * Verifies a StorageBucketOperatorMetadata message.
+     * @function verify
+     * @memberof StorageBucketOperatorMetadata
+     * @static
+     * @param {Object.<string,*>} message Plain object to verify
+     * @returns {string|null} `null` if valid, otherwise the reason why it is not
+     */
+    StorageBucketOperatorMetadata.verify = function verify(message) {
+        if (typeof message !== "object" || message === null)
+            return "object expected";
+        if (message.endpoint != null && message.hasOwnProperty("endpoint"))
+            if (!$util.isString(message.endpoint))
+                return "endpoint: string expected";
+        if (message.location != null && message.hasOwnProperty("location")) {
+            var error = $root.NodeLocationMetadata.verify(message.location);
+            if (error)
+                return "location." + error;
+        }
+        if (message.extra != null && message.hasOwnProperty("extra"))
+            if (!$util.isString(message.extra))
+                return "extra: string expected";
+        return null;
+    };
+
+    /**
+     * Creates a StorageBucketOperatorMetadata message from a plain object. Also converts values to their respective internal types.
+     * @function fromObject
+     * @memberof StorageBucketOperatorMetadata
+     * @static
+     * @param {Object.<string,*>} object Plain object
+     * @returns {StorageBucketOperatorMetadata} StorageBucketOperatorMetadata
+     */
+    StorageBucketOperatorMetadata.fromObject = function fromObject(object) {
+        if (object instanceof $root.StorageBucketOperatorMetadata)
+            return object;
+        var message = new $root.StorageBucketOperatorMetadata();
+        if (object.endpoint != null)
+            message.endpoint = String(object.endpoint);
+        if (object.location != null) {
+            if (typeof object.location !== "object")
+                throw TypeError(".StorageBucketOperatorMetadata.location: object expected");
+            message.location = $root.NodeLocationMetadata.fromObject(object.location);
+        }
+        if (object.extra != null)
+            message.extra = String(object.extra);
+        return message;
+    };
+
+    /**
+     * Creates a plain object from a StorageBucketOperatorMetadata message. Also converts values to other types if specified.
+     * @function toObject
+     * @memberof StorageBucketOperatorMetadata
+     * @static
+     * @param {StorageBucketOperatorMetadata} message StorageBucketOperatorMetadata
+     * @param {$protobuf.IConversionOptions} [options] Conversion options
+     * @returns {Object.<string,*>} Plain object
+     */
+    StorageBucketOperatorMetadata.toObject = function toObject(message, options) {
+        if (!options)
+            options = {};
+        var object = {};
+        if (options.defaults) {
+            object.endpoint = "";
+            object.location = null;
+            object.extra = "";
+        }
+        if (message.endpoint != null && message.hasOwnProperty("endpoint"))
+            object.endpoint = message.endpoint;
+        if (message.location != null && message.hasOwnProperty("location"))
+            object.location = $root.NodeLocationMetadata.toObject(message.location, options);
+        if (message.extra != null && message.hasOwnProperty("extra"))
+            object.extra = message.extra;
+        return object;
+    };
+
+    /**
+     * Converts this StorageBucketOperatorMetadata to JSON.
+     * @function toJSON
+     * @memberof StorageBucketOperatorMetadata
+     * @instance
+     * @returns {Object.<string,*>} JSON object
+     */
+    StorageBucketOperatorMetadata.prototype.toJSON = function toJSON() {
+        return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+    };
+
+    return StorageBucketOperatorMetadata;
+})();
+
+$root.DistributionBucketOperatorMetadata = (function() {
+
+    /**
+     * Properties of a DistributionBucketOperatorMetadata.
+     * @exports IDistributionBucketOperatorMetadata
+     * @interface IDistributionBucketOperatorMetadata
+     * @property {string|null} [endpoint] DistributionBucketOperatorMetadata endpoint
+     * @property {INodeLocationMetadata|null} [location] DistributionBucketOperatorMetadata location
+     * @property {string|null} [extra] DistributionBucketOperatorMetadata extra
+     */
+
+    /**
+     * Constructs a new DistributionBucketOperatorMetadata.
+     * @exports DistributionBucketOperatorMetadata
+     * @classdesc Represents a DistributionBucketOperatorMetadata.
+     * @implements IDistributionBucketOperatorMetadata
+     * @constructor
+     * @param {IDistributionBucketOperatorMetadata=} [properties] Properties to set
+     */
+    function DistributionBucketOperatorMetadata(properties) {
+        if (properties)
+            for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                if (properties[keys[i]] != null)
+                    this[keys[i]] = properties[keys[i]];
+    }
+
+    /**
+     * DistributionBucketOperatorMetadata endpoint.
+     * @member {string} endpoint
+     * @memberof DistributionBucketOperatorMetadata
+     * @instance
+     */
+    DistributionBucketOperatorMetadata.prototype.endpoint = "";
+
+    /**
+     * DistributionBucketOperatorMetadata location.
+     * @member {INodeLocationMetadata|null|undefined} location
+     * @memberof DistributionBucketOperatorMetadata
+     * @instance
+     */
+    DistributionBucketOperatorMetadata.prototype.location = null;
+
+    /**
+     * DistributionBucketOperatorMetadata extra.
+     * @member {string} extra
+     * @memberof DistributionBucketOperatorMetadata
+     * @instance
+     */
+    DistributionBucketOperatorMetadata.prototype.extra = "";
+
+    /**
+     * Creates a new DistributionBucketOperatorMetadata instance using the specified properties.
+     * @function create
+     * @memberof DistributionBucketOperatorMetadata
+     * @static
+     * @param {IDistributionBucketOperatorMetadata=} [properties] Properties to set
+     * @returns {DistributionBucketOperatorMetadata} DistributionBucketOperatorMetadata instance
+     */
+    DistributionBucketOperatorMetadata.create = function create(properties) {
+        return new DistributionBucketOperatorMetadata(properties);
+    };
+
+    /**
+     * Encodes the specified DistributionBucketOperatorMetadata message. Does not implicitly {@link DistributionBucketOperatorMetadata.verify|verify} messages.
+     * @function encode
+     * @memberof DistributionBucketOperatorMetadata
+     * @static
+     * @param {IDistributionBucketOperatorMetadata} message DistributionBucketOperatorMetadata message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    DistributionBucketOperatorMetadata.encode = function encode(message, writer) {
+        if (!writer)
+            writer = $Writer.create();
+        if (message.endpoint != null && Object.hasOwnProperty.call(message, "endpoint"))
+            writer.uint32(/* id 1, wireType 2 =*/10).string(message.endpoint);
+        if (message.location != null && Object.hasOwnProperty.call(message, "location"))
+            $root.NodeLocationMetadata.encode(message.location, writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim();
+        if (message.extra != null && Object.hasOwnProperty.call(message, "extra"))
+            writer.uint32(/* id 3, wireType 2 =*/26).string(message.extra);
+        return writer;
+    };
+
+    /**
+     * Encodes the specified DistributionBucketOperatorMetadata message, length delimited. Does not implicitly {@link DistributionBucketOperatorMetadata.verify|verify} messages.
+     * @function encodeDelimited
+     * @memberof DistributionBucketOperatorMetadata
+     * @static
+     * @param {IDistributionBucketOperatorMetadata} message DistributionBucketOperatorMetadata message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    DistributionBucketOperatorMetadata.encodeDelimited = function encodeDelimited(message, writer) {
+        return this.encode(message, writer).ldelim();
+    };
+
+    /**
+     * Decodes a DistributionBucketOperatorMetadata message from the specified reader or buffer.
+     * @function decode
+     * @memberof DistributionBucketOperatorMetadata
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @param {number} [length] Message length if known beforehand
+     * @returns {DistributionBucketOperatorMetadata} DistributionBucketOperatorMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    DistributionBucketOperatorMetadata.decode = function decode(reader, length) {
+        if (!(reader instanceof $Reader))
+            reader = $Reader.create(reader);
+        var end = length === undefined ? reader.len : reader.pos + length, message = new $root.DistributionBucketOperatorMetadata();
+        while (reader.pos < end) {
+            var tag = reader.uint32();
+            switch (tag >>> 3) {
+            case 1:
+                message.endpoint = reader.string();
+                break;
+            case 2:
+                message.location = $root.NodeLocationMetadata.decode(reader, reader.uint32());
+                break;
+            case 3:
+                message.extra = reader.string();
+                break;
+            default:
+                reader.skipType(tag & 7);
+                break;
+            }
+        }
+        return message;
+    };
+
+    /**
+     * Decodes a DistributionBucketOperatorMetadata message from the specified reader or buffer, length delimited.
+     * @function decodeDelimited
+     * @memberof DistributionBucketOperatorMetadata
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @returns {DistributionBucketOperatorMetadata} DistributionBucketOperatorMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    DistributionBucketOperatorMetadata.decodeDelimited = function decodeDelimited(reader) {
+        if (!(reader instanceof $Reader))
+            reader = new $Reader(reader);
+        return this.decode(reader, reader.uint32());
+    };
+
+    /**
+     * Verifies a DistributionBucketOperatorMetadata message.
+     * @function verify
+     * @memberof DistributionBucketOperatorMetadata
+     * @static
+     * @param {Object.<string,*>} message Plain object to verify
+     * @returns {string|null} `null` if valid, otherwise the reason why it is not
+     */
+    DistributionBucketOperatorMetadata.verify = function verify(message) {
+        if (typeof message !== "object" || message === null)
+            return "object expected";
+        if (message.endpoint != null && message.hasOwnProperty("endpoint"))
+            if (!$util.isString(message.endpoint))
+                return "endpoint: string expected";
+        if (message.location != null && message.hasOwnProperty("location")) {
+            var error = $root.NodeLocationMetadata.verify(message.location);
+            if (error)
+                return "location." + error;
+        }
+        if (message.extra != null && message.hasOwnProperty("extra"))
+            if (!$util.isString(message.extra))
+                return "extra: string expected";
+        return null;
+    };
+
+    /**
+     * Creates a DistributionBucketOperatorMetadata message from a plain object. Also converts values to their respective internal types.
+     * @function fromObject
+     * @memberof DistributionBucketOperatorMetadata
+     * @static
+     * @param {Object.<string,*>} object Plain object
+     * @returns {DistributionBucketOperatorMetadata} DistributionBucketOperatorMetadata
+     */
+    DistributionBucketOperatorMetadata.fromObject = function fromObject(object) {
+        if (object instanceof $root.DistributionBucketOperatorMetadata)
+            return object;
+        var message = new $root.DistributionBucketOperatorMetadata();
+        if (object.endpoint != null)
+            message.endpoint = String(object.endpoint);
+        if (object.location != null) {
+            if (typeof object.location !== "object")
+                throw TypeError(".DistributionBucketOperatorMetadata.location: object expected");
+            message.location = $root.NodeLocationMetadata.fromObject(object.location);
+        }
+        if (object.extra != null)
+            message.extra = String(object.extra);
+        return message;
+    };
+
+    /**
+     * Creates a plain object from a DistributionBucketOperatorMetadata message. Also converts values to other types if specified.
+     * @function toObject
+     * @memberof DistributionBucketOperatorMetadata
+     * @static
+     * @param {DistributionBucketOperatorMetadata} message DistributionBucketOperatorMetadata
+     * @param {$protobuf.IConversionOptions} [options] Conversion options
+     * @returns {Object.<string,*>} Plain object
+     */
+    DistributionBucketOperatorMetadata.toObject = function toObject(message, options) {
+        if (!options)
+            options = {};
+        var object = {};
+        if (options.defaults) {
+            object.endpoint = "";
+            object.location = null;
+            object.extra = "";
+        }
+        if (message.endpoint != null && message.hasOwnProperty("endpoint"))
+            object.endpoint = message.endpoint;
+        if (message.location != null && message.hasOwnProperty("location"))
+            object.location = $root.NodeLocationMetadata.toObject(message.location, options);
+        if (message.extra != null && message.hasOwnProperty("extra"))
+            object.extra = message.extra;
+        return object;
+    };
+
+    /**
+     * Converts this DistributionBucketOperatorMetadata to JSON.
+     * @function toJSON
+     * @memberof DistributionBucketOperatorMetadata
+     * @instance
+     * @returns {Object.<string,*>} JSON object
+     */
+    DistributionBucketOperatorMetadata.prototype.toJSON = function toJSON() {
+        return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+    };
+
+    return DistributionBucketOperatorMetadata;
+})();
+
+$root.DistributionBucketFamilyMetadata = (function() {
+
+    /**
+     * Properties of a DistributionBucketFamilyMetadata.
+     * @exports IDistributionBucketFamilyMetadata
+     * @interface IDistributionBucketFamilyMetadata
+     * @property {string|null} [region] DistributionBucketFamilyMetadata region
+     * @property {string|null} [description] DistributionBucketFamilyMetadata description
+     * @property {Array.<IGeoCoordiantes>|null} [boundary] DistributionBucketFamilyMetadata boundary
+     */
+
+    /**
+     * Constructs a new DistributionBucketFamilyMetadata.
+     * @exports DistributionBucketFamilyMetadata
+     * @classdesc Represents a DistributionBucketFamilyMetadata.
+     * @implements IDistributionBucketFamilyMetadata
+     * @constructor
+     * @param {IDistributionBucketFamilyMetadata=} [properties] Properties to set
+     */
+    function DistributionBucketFamilyMetadata(properties) {
+        this.boundary = [];
+        if (properties)
+            for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
+                if (properties[keys[i]] != null)
+                    this[keys[i]] = properties[keys[i]];
+    }
+
+    /**
+     * DistributionBucketFamilyMetadata region.
+     * @member {string} region
+     * @memberof DistributionBucketFamilyMetadata
+     * @instance
+     */
+    DistributionBucketFamilyMetadata.prototype.region = "";
+
+    /**
+     * DistributionBucketFamilyMetadata description.
+     * @member {string} description
+     * @memberof DistributionBucketFamilyMetadata
+     * @instance
+     */
+    DistributionBucketFamilyMetadata.prototype.description = "";
+
+    /**
+     * DistributionBucketFamilyMetadata boundary.
+     * @member {Array.<IGeoCoordiantes>} boundary
+     * @memberof DistributionBucketFamilyMetadata
+     * @instance
+     */
+    DistributionBucketFamilyMetadata.prototype.boundary = $util.emptyArray;
+
+    /**
+     * Creates a new DistributionBucketFamilyMetadata instance using the specified properties.
+     * @function create
+     * @memberof DistributionBucketFamilyMetadata
+     * @static
+     * @param {IDistributionBucketFamilyMetadata=} [properties] Properties to set
+     * @returns {DistributionBucketFamilyMetadata} DistributionBucketFamilyMetadata instance
+     */
+    DistributionBucketFamilyMetadata.create = function create(properties) {
+        return new DistributionBucketFamilyMetadata(properties);
+    };
+
+    /**
+     * Encodes the specified DistributionBucketFamilyMetadata message. Does not implicitly {@link DistributionBucketFamilyMetadata.verify|verify} messages.
+     * @function encode
+     * @memberof DistributionBucketFamilyMetadata
+     * @static
+     * @param {IDistributionBucketFamilyMetadata} message DistributionBucketFamilyMetadata message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    DistributionBucketFamilyMetadata.encode = function encode(message, writer) {
+        if (!writer)
+            writer = $Writer.create();
+        if (message.region != null && Object.hasOwnProperty.call(message, "region"))
+            writer.uint32(/* id 1, wireType 2 =*/10).string(message.region);
+        if (message.description != null && Object.hasOwnProperty.call(message, "description"))
+            writer.uint32(/* id 2, wireType 2 =*/18).string(message.description);
+        if (message.boundary != null && message.boundary.length)
+            for (var i = 0; i < message.boundary.length; ++i)
+                $root.GeoCoordiantes.encode(message.boundary[i], writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim();
+        return writer;
+    };
+
+    /**
+     * Encodes the specified DistributionBucketFamilyMetadata message, length delimited. Does not implicitly {@link DistributionBucketFamilyMetadata.verify|verify} messages.
+     * @function encodeDelimited
+     * @memberof DistributionBucketFamilyMetadata
+     * @static
+     * @param {IDistributionBucketFamilyMetadata} message DistributionBucketFamilyMetadata message or plain object to encode
+     * @param {$protobuf.Writer} [writer] Writer to encode to
+     * @returns {$protobuf.Writer} Writer
+     */
+    DistributionBucketFamilyMetadata.encodeDelimited = function encodeDelimited(message, writer) {
+        return this.encode(message, writer).ldelim();
+    };
+
+    /**
+     * Decodes a DistributionBucketFamilyMetadata message from the specified reader or buffer.
+     * @function decode
+     * @memberof DistributionBucketFamilyMetadata
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @param {number} [length] Message length if known beforehand
+     * @returns {DistributionBucketFamilyMetadata} DistributionBucketFamilyMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    DistributionBucketFamilyMetadata.decode = function decode(reader, length) {
+        if (!(reader instanceof $Reader))
+            reader = $Reader.create(reader);
+        var end = length === undefined ? reader.len : reader.pos + length, message = new $root.DistributionBucketFamilyMetadata();
+        while (reader.pos < end) {
+            var tag = reader.uint32();
+            switch (tag >>> 3) {
+            case 1:
+                message.region = reader.string();
+                break;
+            case 2:
+                message.description = reader.string();
+                break;
+            case 3:
+                if (!(message.boundary && message.boundary.length))
+                    message.boundary = [];
+                message.boundary.push($root.GeoCoordiantes.decode(reader, reader.uint32()));
+                break;
+            default:
+                reader.skipType(tag & 7);
+                break;
+            }
+        }
+        return message;
+    };
+
+    /**
+     * Decodes a DistributionBucketFamilyMetadata message from the specified reader or buffer, length delimited.
+     * @function decodeDelimited
+     * @memberof DistributionBucketFamilyMetadata
+     * @static
+     * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
+     * @returns {DistributionBucketFamilyMetadata} DistributionBucketFamilyMetadata
+     * @throws {Error} If the payload is not a reader or valid buffer
+     * @throws {$protobuf.util.ProtocolError} If required fields are missing
+     */
+    DistributionBucketFamilyMetadata.decodeDelimited = function decodeDelimited(reader) {
+        if (!(reader instanceof $Reader))
+            reader = new $Reader(reader);
+        return this.decode(reader, reader.uint32());
+    };
+
+    /**
+     * Verifies a DistributionBucketFamilyMetadata message.
+     * @function verify
+     * @memberof DistributionBucketFamilyMetadata
+     * @static
+     * @param {Object.<string,*>} message Plain object to verify
+     * @returns {string|null} `null` if valid, otherwise the reason why it is not
+     */
+    DistributionBucketFamilyMetadata.verify = function verify(message) {
+        if (typeof message !== "object" || message === null)
+            return "object expected";
+        if (message.region != null && message.hasOwnProperty("region"))
+            if (!$util.isString(message.region))
+                return "region: string expected";
+        if (message.description != null && message.hasOwnProperty("description"))
+            if (!$util.isString(message.description))
+                return "description: string expected";
+        if (message.boundary != null && message.hasOwnProperty("boundary")) {
+            if (!Array.isArray(message.boundary))
+                return "boundary: array expected";
+            for (var i = 0; i < message.boundary.length; ++i) {
+                var error = $root.GeoCoordiantes.verify(message.boundary[i]);
+                if (error)
+                    return "boundary." + error;
+            }
+        }
+        return null;
+    };
+
+    /**
+     * Creates a DistributionBucketFamilyMetadata message from a plain object. Also converts values to their respective internal types.
+     * @function fromObject
+     * @memberof DistributionBucketFamilyMetadata
+     * @static
+     * @param {Object.<string,*>} object Plain object
+     * @returns {DistributionBucketFamilyMetadata} DistributionBucketFamilyMetadata
+     */
+    DistributionBucketFamilyMetadata.fromObject = function fromObject(object) {
+        if (object instanceof $root.DistributionBucketFamilyMetadata)
+            return object;
+        var message = new $root.DistributionBucketFamilyMetadata();
+        if (object.region != null)
+            message.region = String(object.region);
+        if (object.description != null)
+            message.description = String(object.description);
+        if (object.boundary) {
+            if (!Array.isArray(object.boundary))
+                throw TypeError(".DistributionBucketFamilyMetadata.boundary: array expected");
+            message.boundary = [];
+            for (var i = 0; i < object.boundary.length; ++i) {
+                if (typeof object.boundary[i] !== "object")
+                    throw TypeError(".DistributionBucketFamilyMetadata.boundary: object expected");
+                message.boundary[i] = $root.GeoCoordiantes.fromObject(object.boundary[i]);
+            }
+        }
+        return message;
+    };
+
+    /**
+     * Creates a plain object from a DistributionBucketFamilyMetadata message. Also converts values to other types if specified.
+     * @function toObject
+     * @memberof DistributionBucketFamilyMetadata
+     * @static
+     * @param {DistributionBucketFamilyMetadata} message DistributionBucketFamilyMetadata
+     * @param {$protobuf.IConversionOptions} [options] Conversion options
+     * @returns {Object.<string,*>} Plain object
+     */
+    DistributionBucketFamilyMetadata.toObject = function toObject(message, options) {
+        if (!options)
+            options = {};
+        var object = {};
+        if (options.arrays || options.defaults)
+            object.boundary = [];
+        if (options.defaults) {
+            object.region = "";
+            object.description = "";
+        }
+        if (message.region != null && message.hasOwnProperty("region"))
+            object.region = message.region;
+        if (message.description != null && message.hasOwnProperty("description"))
+            object.description = message.description;
+        if (message.boundary && message.boundary.length) {
+            object.boundary = [];
+            for (var j = 0; j < message.boundary.length; ++j)
+                object.boundary[j] = $root.GeoCoordiantes.toObject(message.boundary[j], options);
+        }
+        return object;
+    };
+
+    /**
+     * Converts this DistributionBucketFamilyMetadata to JSON.
+     * @function toJSON
+     * @memberof DistributionBucketFamilyMetadata
+     * @instance
+     * @returns {Object.<string,*>} JSON object
+     */
+    DistributionBucketFamilyMetadata.prototype.toJSON = function toJSON() {
+        return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
+    };
+
+    return DistributionBucketFamilyMetadata;
+})();
+
+module.exports = $root;

+ 136 - 0
metadata-protobuf/doc/index.md

@@ -0,0 +1,136 @@
+# Protocol Documentation
+<a name="top"></a>
+
+## Table of Contents
+
+- [proto/Storage.proto](#proto/Storage.proto)
+    - [DistributionBucketFamilyMetadata](#.DistributionBucketFamilyMetadata)
+    - [DistributionBucketOperatorMetadata](#.DistributionBucketOperatorMetadata)
+    - [GeoCoordiantes](#.GeoCoordiantes)
+    - [NodeLocationMetadata](#.NodeLocationMetadata)
+    - [StorageBucketOperatorMetadata](#.StorageBucketOperatorMetadata)
+  
+- [Scalar Value Types](#scalar-value-types)
+
+
+
+<a name="proto/Storage.proto"></a>
+<p align="right"><a href="#top">Top</a></p>
+
+## proto/Storage.proto
+
+
+
+<a name=".DistributionBucketFamilyMetadata"></a>
+
+### DistributionBucketFamilyMetadata
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| region | [string](#string) | optional | ID / name of the region covered by the distribution family (ie. us-east-1). Should be unique. |
+| description | [string](#string) | optional | Additional, more specific description of the region |
+| boundary | [GeoCoordiantes](#GeoCoordiantes) | repeated | Geographical boundary of the region, defined as polygon through array of coordinates |
+
+
+
+
+
+
+<a name=".DistributionBucketOperatorMetadata"></a>
+
+### DistributionBucketOperatorMetadata
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| endpoint | [string](#string) | optional | Root distribution node endpoint (ie. https://example.com/distribution) |
+| location | [NodeLocationMetadata](#NodeLocationMetadata) | optional | Information about node&#39;s phisical location |
+| extra | [string](#string) | optional | Additional information about the node / node operator |
+
+
+
+
+
+
+<a name=".GeoCoordiantes"></a>
+
+### GeoCoordiantes
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| latitude | [float](#float) | required |  |
+| longitude | [float](#float) | required |  |
+
+
+
+
+
+
+<a name=".NodeLocationMetadata"></a>
+
+### NodeLocationMetadata
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| country_code | [string](#string) | optional | ISO 3166-1 alpha-2 country code (2 letters) |
+| city | [string](#string) | optional | City name |
+| coordinates | [GeoCoordiantes](#GeoCoordiantes) | optional | Geographic coordinates |
+
+
+
+
+
+
+<a name=".StorageBucketOperatorMetadata"></a>
+
+### StorageBucketOperatorMetadata
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| endpoint | [string](#string) | optional | Root storage node endpoint (ie. https://example.com/storage) |
+| location | [NodeLocationMetadata](#NodeLocationMetadata) | optional | Information about node&#39;s phisical location |
+| extra | [string](#string) | optional | Additional information about the node / node operator |
+
+
+
+
+
+ 
+
+ 
+
+ 
+
+ 
+
+
+
+## Scalar Value Types
+
+| .proto Type | Notes | C++ | Java | Python | Go | C# | PHP | Ruby |
+| ----------- | ----- | --- | ---- | ------ | -- | -- | --- | ---- |
+| <a name="double" /> double |  | double | double | float | float64 | double | float | Float |
+| <a name="float" /> float |  | float | float | float | float32 | float | float | Float |
+| <a name="int32" /> int32 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
+| <a name="int64" /> int64 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. | int64 | long | int/long | int64 | long | integer/string | Bignum |
+| <a name="uint32" /> uint32 | Uses variable-length encoding. | uint32 | int | int/long | uint32 | uint | integer | Bignum or Fixnum (as required) |
+| <a name="uint64" /> uint64 | Uses variable-length encoding. | uint64 | long | int/long | uint64 | ulong | integer/string | Bignum or Fixnum (as required) |
+| <a name="sint32" /> sint32 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
+| <a name="sint64" /> sint64 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. | int64 | long | int/long | int64 | long | integer/string | Bignum |
+| <a name="fixed32" /> fixed32 | Always four bytes. More efficient than uint32 if values are often greater than 2^28. | uint32 | int | int | uint32 | uint | integer | Bignum or Fixnum (as required) |
+| <a name="fixed64" /> fixed64 | Always eight bytes. More efficient than uint64 if values are often greater than 2^56. | uint64 | long | int/long | uint64 | ulong | integer/string | Bignum |
+| <a name="sfixed32" /> sfixed32 | Always four bytes. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
+| <a name="sfixed64" /> sfixed64 | Always eight bytes. | int64 | long | int/long | int64 | long | integer/string | Bignum |
+| <a name="bool" /> bool |  | bool | boolean | boolean | bool | bool | boolean | TrueClass/FalseClass |
+| <a name="string" /> string | A string must always contain UTF-8 encoded or 7-bit ASCII text. | string | String | str/unicode | string | string | string | String (UTF-8) |
+| <a name="bytes" /> bytes | May contain any arbitrary sequence of bytes. | string | ByteString | str | []byte | ByteString | string | String (ASCII-8BIT) |
+

+ 10 - 0
metadata-protobuf/generate-md-doc.sh

@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+
+# Directory to write generated documentation to
+OUT_DIR_DOC="./doc"
+mkdir -p ${OUT_DIR_DOC}
+
+# Gernerate Markdown docs
+protoc \
+    --doc_out="${OUT_DIR_DOC}" --doc_opt=markdown,index.md \
+    proto/*.proto

+ 54 - 0
metadata-protobuf/package.json

@@ -0,0 +1,54 @@
+{
+  "name": "@joystream/metadata-protobuf",
+  "version": "1.0.0",
+  "description": "Joystream Metadata Protobuf Library ",
+  "main": "lib/index.js",
+  "types": "lib/index.d.ts",
+  "exports": {
+    ".": "./lib/index.js",
+    "./utils": "./lib/utils.js",
+    "./licenses": "./lib/licenses.js"
+  },
+  "typesVersions": {
+    "*": {
+      "lib/index.d.ts": ["lib/index.d.ts"],
+      "*": [ "lib/*" ]
+    }
+  },
+  "repository": "https://github.com/joystream/joystream",
+  "author": "Joystream Contributors",
+  "license": "MIT",
+  "private": false,
+  "scripts": {
+    "build": "yarn compile && tsc",
+    "compile": "yarn ts-node ./scripts/compile.ts",
+    "generate-doc": "./generate-md-doc.sh",
+    "test": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' mocha --inline-diffs -r ts-node/register 'test/**/*.ts'",
+    "lint": "eslint ./src --ext .ts",
+    "checks": "tsc --noEmit --pretty && prettier ./ --check && yarn lint",
+    "format": "prettier ./ --write"
+  },
+  "files": [
+    "lib/**/*",
+    "doc/**",
+    "proto/**",
+    "compiled/**/*",
+    "README.md"
+  ],
+  "dependencies": {
+    "google-protobuf": "^3.14.0",
+    "long": "^4.0.0",
+    "@types/long": "^4.0.1"
+  },
+  "devDependencies": {
+    "@types/chai": "^4.2.11",
+    "@types/mocha": "^8.2.0",
+    "chai": "^4.2.0",
+    "eslint": "^7.6.0",
+    "mocha": "^8.2.1",
+    "prettier": "2.0.2",
+    "ts-node": "^8.8.1",
+    "typescript": "^4.1.3",
+    "protobufjs": "^6.11.2"
+  }
+}

+ 30 - 0
metadata-protobuf/proto/Storage.proto

@@ -0,0 +1,30 @@
+syntax = "proto2";
+
+message GeoCoordiantes {
+  required float latitude = 3;
+  required float longitude = 4;
+}
+
+message NodeLocationMetadata {
+  optional string country_code = 1; // ISO 3166-1 alpha-2 country code (2 letters)
+  optional string city = 2; // City name
+  optional GeoCoordiantes coordinates = 3; // Geographic coordinates
+}
+
+message StorageBucketOperatorMetadata {
+  optional string endpoint = 1; // Root storage node endpoint (ie. https://example.com/storage)
+  optional NodeLocationMetadata location = 2; // Information about node's phisical location
+  optional string extra = 3; // Additional information about the node / node operator
+}
+
+message DistributionBucketOperatorMetadata {
+  optional string endpoint = 1; // Root distribution node endpoint (ie. https://example.com/distribution)
+  optional NodeLocationMetadata location = 2; // Information about node's phisical location
+  optional string extra = 3; // Additional information about the node / node operator
+}
+
+message DistributionBucketFamilyMetadata {
+  optional string region = 1; // ID / name of the region covered by the distribution family (ie. us-east-1). Should be unique.
+  optional string description = 2; // Additional, more specific description of the region
+  repeated GeoCoordiantes boundary = 3; // Geographical boundary of the region, defined as polygon through array of coordinates
+}

+ 28 - 0
metadata-protobuf/scripts/compile.ts

@@ -0,0 +1,28 @@
+import { main as pbjs } from 'protobufjs/cli/pbjs'
+import { main as pbts } from 'protobufjs/cli/pbts'
+import path from 'path'
+import fs from 'fs'
+
+const OUT_DIR = path.resolve(__dirname, '../compiled')
+
+pbjs(
+  ['--target', 'static-module', '-w', 'commonjs', '-o', `${OUT_DIR}/index.js`, '--force-long', 'proto/*.proto'],
+  function (err) {
+    if (err) {
+      throw err
+    }
+    console.log(`${OUT_DIR}/index.js updated`)
+  }
+)
+
+pbts([`${OUT_DIR}/*.js`], function (err, output) {
+  if (err) {
+    throw err
+  }
+  // Fix missing Long import
+  output = `import { Long } from 'long'\n${output}`
+
+  fs.writeFileSync(`${OUT_DIR}/index.d.ts`, output)
+
+  console.log(`${OUT_DIR}/index.d.ts updated`)
+})

+ 11 - 0
metadata-protobuf/scripts/tsconfig.json

@@ -0,0 +1,11 @@
+{
+  "compilerOptions": {
+    "noEmit": true,
+    "strict": true,
+    "esModuleInterop": true,
+    "forceConsistentCasingInFileNames": true,
+    "skipLibCheck": true,
+    "resolveJsonModule": true
+  },
+  "include": ["./*.ts"]
+}

+ 2 - 0
metadata-protobuf/src/index.ts

@@ -0,0 +1,2 @@
+// protobuf message constructors
+export * from '../compiled'

+ 25 - 0
metadata-protobuf/src/types.ts

@@ -0,0 +1,25 @@
+import { Long } from 'long'
+import { IConversionOptions } from 'protobufjs'
+
+export type AnyMessage<T> = T & {
+  toJSON(): Record<string, unknown>
+}
+
+export type AnyMetadataClass<T> = {
+  name: string
+  decode(binary: Uint8Array): AnyMessage<T>
+  encode(obj: T): { finish(): Uint8Array }
+  toObject(obj: AnyMessage<T>, options?: IConversionOptions): Record<string, unknown>
+  verify(message: { [k: string]: any }): null | string
+  fromObject(object: { [k: string]: any }): AnyMessage<T>
+}
+
+export type DecodedMetadataObject<T> = {
+  [K in keyof T]: T[K] extends Long | null | undefined
+    ? Exclude<T[K], Long> | string
+    : T[K] extends string | number | boolean | null | undefined
+    ? T[K]
+    : T[K] extends Array<infer S>
+    ? DecodedMetadataObject<S>[]
+    : DecodedMetadataObject<T[K]>
+}

+ 28 - 0
metadata-protobuf/src/utils.ts

@@ -0,0 +1,28 @@
+import { AnyMessage, AnyMetadataClass, DecodedMetadataObject } from './types'
+
+export function isSet<T>(v: T | null | undefined): v is T {
+  return v !== null && v !== undefined
+}
+
+export function integrateMeta<
+  T,
+  Props extends readonly (keyof T & keyof M & string)[],
+  M extends { [K in Props[number]]?: T[K] | null }
+>(object: T, meta: M, props: Props): void {
+  props.forEach((prop) => {
+    const metaPropVal = meta[prop] as T[Props[number]] | null | undefined
+    if (isSet(metaPropVal)) {
+      object[prop] = metaPropVal
+    }
+  })
+}
+
+export function encodeDecode<T>(metaClass: AnyMetadataClass<T>, value: T): DecodedMetadataObject<T> {
+  const encoded = metaClass.encode(value).finish()
+  return metaToObject(metaClass, metaClass.decode(encoded))
+}
+
+export function metaToObject<T>(metaClass: AnyMetadataClass<T>, value: AnyMessage<T>): DecodedMetadataObject<T> {
+  // Default conversion options - use Strings for "Long" values and ignore unset "repeated" fields
+  return metaClass.toObject(value, { arrays: false, longs: String }) as DecodedMetadataObject<T>
+}

+ 14 - 0
metadata-protobuf/test/tsconfig.json

@@ -0,0 +1,14 @@
+{
+  "compilerOptions": {
+    "target": "esnext",
+    "module": "commonjs",
+    "noEmit": true,
+    "strict": true,
+    "declaration": true,
+    "esModuleInterop": true,
+    "forceConsistentCasingInFileNames": true,
+    "skipLibCheck": true,
+    "resolveJsonModule": true
+  },
+  "include": ["./*", "../src/*"]
+}

+ 15 - 0
metadata-protobuf/tsconfig.json

@@ -0,0 +1,15 @@
+{
+  "compilerOptions": {
+    "target": "esnext",
+    "module": "commonjs",
+    "outDir": "lib",
+    "strict": true,
+    "declaration": true,
+    "esModuleInterop": true,
+    "forceConsistentCasingInFileNames": true,
+    "skipLibCheck": true,
+    "resolveJsonModule": true,
+  },
+  "include": ["src"],
+  "exclude": ["node_modules", "test"]
+}

+ 2 - 1
package.json

@@ -28,7 +28,8 @@
     "content-directory-schemas",
     "query-node",
     "query-node/mappings",
-    "query-node/generated/*"
+    "query-node/generated/*",
+    "metadata-protobuf"
   ],
   "resolutions": {
     "@polkadot/api": "4.2.1",

+ 216 - 21
yarn.lock

@@ -6547,7 +6547,7 @@
   resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.171.tgz#f01b3a5fe3499e34b622c362a46a609fdb23573b"
   integrity sha512-7eQ2xYLLI/LsicL2nejW9Wyko3lcpN6O/z0ZLHrEQsg280zIdCv1t/0m6UtBjUHokCGBQ3gYTbHzDkZ1xOBwwg==
 
-"@types/long@^4.0.0":
+"@types/long@^4.0.0", "@types/long@^4.0.1":
   version "4.0.1"
   resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9"
   integrity "sha1-RZxl+hhn2v5qjzIsTFFpVmPMVek= sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w=="
@@ -6606,6 +6606,11 @@
   resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.7.tgz#315d570ccb56c53452ff8638738df60726d5b6ea"
   integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==
 
+"@types/mocha@^8.2.0":
+  version "8.2.3"
+  resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.2.3.tgz#bbeb55fbc73f28ea6de601fbfa4613f58d785323"
+  integrity sha512-ekGvFhFgrc2zYQoX4JeZPmVzZxw6Dtllga7iGHzfbYIYkAMUx/sAFP2GdFpLff+vdHXu5fl7WX9AT+TtqYcsyw==
+
 "@types/multer@^1.4.5":
   version "1.4.5"
   resolved "https://registry.yarnpkg.com/@types/multer/-/multer-1.4.5.tgz#db0557562307e9adb6661a9500c334cd7ddd0cd9"
@@ -6656,6 +6661,11 @@
   resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.14.tgz#1c1d6e3c75dba466e0326948d56e8bd72a1903d2"
   integrity sha512-u/SJDyXwuihpwjXy7hOOghagLEV1KdAST6syfnOk6QZAMzZuWZqXy5aYYZbh8Jdpd4escVFP0MvftHNDb9pruA==
 
+"@types/node@>=13.7.0":
+  version "16.4.3"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-16.4.3.tgz#c01c1a215721f6dec71b47d88b4687463601ba48"
+  integrity sha512-GKM4FLMkWDc0sfx7tXqPWkM6NBow1kge0fgQh0bOnlqo4iT1kvTvMEKE0c1RtUGnbLlGRXiAA8SumE//90uKAg==
+
 "@types/node@^10":
   version "10.17.60"
   resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b"
@@ -7257,6 +7267,11 @@
   dependencies:
     eslint-visitor-keys "^1.1.0"
 
+"@ungap/promise-all-settled@1.1.2":
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44"
+  integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==
+
 "@vue/babel-helper-vue-jsx-merge-props@^1.0.0":
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.0.0.tgz#048fe579958da408fb7a8b2a3ec050b50a661040"
@@ -8071,16 +8086,16 @@ ansi-align@^3.0.0:
   dependencies:
     string-width "^3.0.0"
 
+ansi-colors@4.1.1, ansi-colors@^4.1.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
+  integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
+
 ansi-colors@^3.0.0, ansi-colors@^3.2.1:
   version "3.2.4"
   resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
   integrity "sha1-46PaS/uubIapwoViXeEkojQCb78= sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA=="
 
-ansi-colors@^4.1.1:
-  version "4.1.1"
-  resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
-  integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
-
 ansi-escapes@^3.0.0, ansi-escapes@^3.1.0, ansi-escapes@^3.2.0:
   version "3.2.0"
   resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b"
@@ -10677,6 +10692,21 @@ check-type@^0.4.11:
   dependencies:
     underscore "1.6.0"
 
+chokidar@3.5.1:
+  version "3.5.1"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a"
+  integrity sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==
+  dependencies:
+    anymatch "~3.1.1"
+    braces "~3.0.2"
+    glob-parent "~5.1.0"
+    is-binary-path "~2.1.0"
+    is-glob "~4.0.1"
+    normalize-path "~3.0.0"
+    readdirp "~3.5.0"
+  optionalDependencies:
+    fsevents "~2.3.1"
+
 chokidar@^1.6.0:
   version "1.7.0"
   resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
@@ -12611,6 +12641,11 @@ decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0:
   resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
   integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
 
+decamelize@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837"
+  integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==
+
 decimal.js@^10.2.0:
   version "10.2.0"
   resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.2.0.tgz#39466113a9e036111d02f82489b5fd6b0b5ed231"
@@ -13070,16 +13105,16 @@ diff@3.5.0, diff@^3.1.0, diff@^3.5.0:
   resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
   integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
 
+diff@5.0.0, diff@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b"
+  integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==
+
 diff@^4.0.1:
   version "4.0.2"
   resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
   integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
 
-diff@^5.0.0:
-  version "5.0.0"
-  resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b"
-  integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==
-
 diffie-hellman@^5.0.0:
   version "5.0.3"
   resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
@@ -15377,6 +15412,14 @@ find-up@3.0.0, find-up@^3.0.0:
   dependencies:
     locate-path "^3.0.0"
 
+find-up@5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
+  integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
+  dependencies:
+    locate-path "^6.0.0"
+    path-exists "^4.0.0"
+
 find-up@^1.0.0:
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
@@ -15440,6 +15483,11 @@ flat-cache@^2.0.1:
     rimraf "2.6.3"
     write "1.0.3"
 
+flat@^5.0.2:
+  version "5.0.2"
+  resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241"
+  integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==
+
 flatmap@0.0.3:
   version "0.0.3"
   resolved "https://registry.yarnpkg.com/flatmap/-/flatmap-0.0.3.tgz#1f18a4d938152d495965f9c958d923ab2dd669b4"
@@ -15790,7 +15838,7 @@ fsevents@^2.1.2, fsevents@~2.1.2:
   resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e"
   integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==
 
-fsevents@~2.3.2:
+fsevents@~2.3.1, fsevents@~2.3.2:
   version "2.3.2"
   resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
   integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
@@ -17008,7 +17056,7 @@ he@1.1.1:
   resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
   integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0=
 
-he@1.2.x, he@^1.1.0, he@^1.2.0:
+he@1.2.0, he@1.2.x, he@^1.1.0, he@^1.2.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
   integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
@@ -18957,6 +19005,11 @@ is-plain-obj@^2.0.0:
   resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.0.0.tgz#7fd1a7f1b69e160cde9181d2313f445c68aa2679"
   integrity sha512-EYisGhpgSCwspmIuRHGjROWTon2Xp8Z7U03Wubk/bTL5TTRC5R1rGVgyjzBrk9+ULdH6cRD06KRcw/xfqhVYKQ==
 
+is-plain-obj@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287"
+  integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==
+
 is-plain-object@3.0.0, is-plain-object@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-3.0.0.tgz#47bfc5da1b5d50d64110806c199359482e75a928"
@@ -20666,6 +20719,13 @@ js-tokens@^3.0.2:
   resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
   integrity "sha1-mGbfOVECEw449/mWvOtlRDIJwls= sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg=="
 
+js-yaml@4.0.0, js-yaml@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.0.0.tgz#f426bc0ff4b4051926cd588c71113183409a121f"
+  integrity sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==
+  dependencies:
+    argparse "^2.0.1"
+
 js-yaml@^3.10.0, js-yaml@^3.14.0:
   version "3.14.0"
   resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482"
@@ -21665,6 +21725,13 @@ locate-path@^5.0.0:
   dependencies:
     p-locate "^4.1.0"
 
+locate-path@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"
+  integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
+  dependencies:
+    p-locate "^5.0.0"
+
 lodash-es@^4.17.14:
   version "4.17.15"
   resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.15.tgz#21bd96839354412f23d7a10340e5eac6ee455d78"
@@ -21915,6 +21982,13 @@ log-driver@^1.2.7:
   resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.7.tgz#63b95021f0702fedfa2c9bb0a24e7797d71871d8"
   integrity sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==
 
+log-symbols@4.0.0, log-symbols@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.0.0.tgz#69b3cc46d20f448eccdb75ea1fa733d9e821c920"
+  integrity sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==
+  dependencies:
+    chalk "^4.0.0"
+
 log-symbols@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18"
@@ -22978,6 +23052,37 @@ mocha@^5, mocha@^5.2.0:
     mkdirp "0.5.1"
     supports-color "5.4.0"
 
+mocha@^8.2.1:
+  version "8.4.0"
+  resolved "https://registry.yarnpkg.com/mocha/-/mocha-8.4.0.tgz#677be88bf15980a3cae03a73e10a0fc3997f0cff"
+  integrity sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==
+  dependencies:
+    "@ungap/promise-all-settled" "1.1.2"
+    ansi-colors "4.1.1"
+    browser-stdout "1.3.1"
+    chokidar "3.5.1"
+    debug "4.3.1"
+    diff "5.0.0"
+    escape-string-regexp "4.0.0"
+    find-up "5.0.0"
+    glob "7.1.6"
+    growl "1.10.5"
+    he "1.2.0"
+    js-yaml "4.0.0"
+    log-symbols "4.0.0"
+    minimatch "3.0.4"
+    ms "2.1.3"
+    nanoid "3.1.20"
+    serialize-javascript "5.0.1"
+    strip-json-comments "3.1.1"
+    supports-color "8.1.1"
+    which "2.0.2"
+    wide-align "1.1.3"
+    workerpool "6.1.0"
+    yargs "16.2.0"
+    yargs-parser "20.2.4"
+    yargs-unparser "2.0.0"
+
 mock-stdin@^0.3.1:
   version "0.3.1"
   resolved "https://registry.yarnpkg.com/mock-stdin/-/mock-stdin-0.3.1.tgz#c657d9642d90786435c64ca5e99bbd4d09bd7dd3"
@@ -23045,6 +23150,11 @@ ms@2.1.2, ms@^2.0.0, ms@^2.1.1:
   resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
   integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
 
+ms@2.1.3:
+  version "2.1.3"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
+  integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+
 multer@^1.4.1, multer@^1.4.2:
   version "1.4.2"
   resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.2.tgz#2f1f4d12dbaeeba74cb37e623f234bf4d3d2057a"
@@ -23323,6 +23433,11 @@ nan@^2.13.2:
   resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01"
   integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==
 
+nanoid@3.1.20:
+  version "3.1.20"
+  resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.20.tgz#badc263c6b1dcf14b71efaa85f6ab4c1d6cfc788"
+  integrity sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==
+
 nanoid@^2.1.0:
   version "2.1.11"
   resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280"
@@ -24712,6 +24827,13 @@ p-locate@^4.1.0:
   dependencies:
     p-limit "^2.2.0"
 
+p-locate@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
+  integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
+  dependencies:
+    p-limit "^3.0.2"
+
 p-map-series@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/p-map-series/-/p-map-series-1.0.0.tgz#bf98fe575705658a9e1351befb85ae4c1f07bdca"
@@ -26299,6 +26421,25 @@ proto-list@~1.2.1:
   resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
   integrity "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA=="
 
+protobufjs@^6.11.2:
+  version "6.11.2"
+  resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.2.tgz#de39fabd4ed32beaa08e9bb1e30d08544c1edf8b"
+  integrity sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==
+  dependencies:
+    "@protobufjs/aspromise" "^1.1.2"
+    "@protobufjs/base64" "^1.1.2"
+    "@protobufjs/codegen" "^2.0.4"
+    "@protobufjs/eventemitter" "^1.1.0"
+    "@protobufjs/fetch" "^1.1.0"
+    "@protobufjs/float" "^1.0.2"
+    "@protobufjs/inquire" "^1.1.0"
+    "@protobufjs/path" "^1.1.2"
+    "@protobufjs/pool" "^1.1.0"
+    "@protobufjs/utf8" "^1.1.0"
+    "@types/long" "^4.0.1"
+    "@types/node" ">=13.7.0"
+    long "^4.0.0"
+
 protocol-buffers-schema@^3.3.1:
   version "3.3.2"
   resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.3.2.tgz#00434f608b4e8df54c59e070efeefc37fb4bb859"
@@ -27362,6 +27503,13 @@ readdirp@~3.4.0:
   dependencies:
     picomatch "^2.2.1"
 
+readdirp@~3.5.0:
+  version "3.5.0"
+  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e"
+  integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==
+  dependencies:
+    picomatch "^2.2.1"
+
 readdirp@~3.6.0:
   version "3.6.0"
   resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
@@ -28583,6 +28731,13 @@ serialize-error@^7.0.1:
   dependencies:
     type-fest "^0.13.1"
 
+serialize-javascript@5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4"
+  integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==
+  dependencies:
+    randombytes "^2.1.0"
+
 serialize-javascript@^2.1.0, serialize-javascript@^2.1.2:
   version "2.1.2"
   resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61"
@@ -29749,6 +29904,11 @@ strip-indent@^3.0.0:
   dependencies:
     min-indent "^1.0.0"
 
+strip-json-comments@3.1.1, strip-json-comments@^3.1.0:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
+  integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
+
 strip-json-comments@^2.0.0, strip-json-comments@~2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
@@ -29759,11 +29919,6 @@ strip-json-comments@^3.0.1:
   resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7"
   integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==
 
-strip-json-comments@^3.1.0:
-  version "3.1.1"
-  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
-  integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
-
 strip-markdown@^3.0.3:
   version "3.1.2"
   resolved "https://registry.yarnpkg.com/strip-markdown/-/strip-markdown-3.1.2.tgz#172f6f89f9a98896e65a65422e0507f2bbac1667"
@@ -30011,6 +30166,13 @@ supports-color@5.4.0:
   dependencies:
     has-flag "^3.0.0"
 
+supports-color@8.1.1:
+  version "8.1.1"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
+  integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
+  dependencies:
+    has-flag "^4.0.0"
+
 supports-color@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
@@ -31246,7 +31408,7 @@ typescript-formatter@^7.2.2:
     commandpost "^1.0.0"
     editorconfig "^0.15.0"
 
-typescript@^3.0.3, typescript@^3.3, typescript@^3.7.2, typescript@^3.7.5, typescript@^3.8, typescript@^3.8.3, typescript@^3.9.5, typescript@^3.9.6, typescript@^3.9.7:
+typescript@^3.0.3, typescript@^3.3, typescript@^3.7.2, typescript@^3.7.5, typescript@^3.8, typescript@^3.8.3, typescript@^3.9.5, typescript@^3.9.6, typescript@^3.9.7, typescript@^4.1.3:
   version "3.9.7"
   resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
   integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
@@ -32729,14 +32891,14 @@ which@1, which@^1.1.1, which@^1.2.14, which@^1.2.9, which@^1.3.0, which@^1.3.1:
   dependencies:
     isexe "^2.0.0"
 
-which@^2.0.0, which@^2.0.1, which@^2.0.2:
+which@2.0.2, which@^2.0.0, which@^2.0.1, which@^2.0.2:
   version "2.0.2"
   resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
   integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
   dependencies:
     isexe "^2.0.0"
 
-wide-align@^1.1.0:
+wide-align@1.1.3, wide-align@^1.1.0:
   version "1.1.3"
   resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
   integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==
@@ -32835,6 +32997,11 @@ worker-rpc@^0.1.0:
   dependencies:
     microevent.ts "~0.1.1"
 
+workerpool@6.1.0:
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.1.0.tgz#a8e038b4c94569596852de7a8ea4228eefdeb37b"
+  integrity sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==
+
 wrap-ansi@^2.0.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
@@ -33175,6 +33342,11 @@ yargs-parser@18.x, yargs-parser@^18.1.2, yargs-parser@^18.1.3:
     camelcase "^5.0.0"
     decamelize "^1.2.0"
 
+yargs-parser@20.2.4:
+  version "20.2.4"
+  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54"
+  integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==
+
 yargs-parser@^11.1.1:
   version "11.1.1"
   resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4"
@@ -33240,6 +33412,29 @@ yargs-parser@^8.1.0:
   dependencies:
     camelcase "^4.1.0"
 
+yargs-unparser@2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb"
+  integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==
+  dependencies:
+    camelcase "^6.0.0"
+    decamelize "^4.0.0"
+    flat "^5.0.2"
+    is-plain-obj "^2.1.0"
+
+yargs@16.2.0, yargs@^16.0.0, yargs@^16.1.0, yargs@^16.2.0:
+  version "16.2.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
+  integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==
+  dependencies:
+    cliui "^7.0.2"
+    escalade "^3.1.1"
+    get-caller-file "^2.0.5"
+    require-directory "^2.1.1"
+    string-width "^4.2.0"
+    y18n "^5.0.5"
+    yargs-parser "^20.2.2"
+
 yargs@^10.0.3:
   version "10.1.2"
   resolved "https://registry.yarnpkg.com/yargs/-/yargs-10.1.2.tgz#454d074c2b16a51a43e2fb7807e4f9de69ccb5c5"