فهرست منبع

Add metadata-protobuf package + storage v2 metadata standards

Leszek Wiesner 3 سال پیش
والد
کامیت
34a3f88e90

+ 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

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

+ 36 - 15
yarn.lock

@@ -5072,7 +5072,7 @@
   resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.168.tgz#fe24632e79b7ade3f132891afff86caa5e5ce008"
   integrity sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q==
 
-"@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=="
@@ -5203,6 +5203,11 @@
   resolved "https://registry.yarnpkg.com/@types/node/-/node-11.11.6.tgz#df929d1bb2eee5afdda598a41930fe50b43eaa6a"
   integrity sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==
 
+"@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"
@@ -20803,6 +20808,11 @@ nanoid@3.1.20:
   resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.20.tgz#badc263c6b1dcf14b71efaa85f6ab4c1d6cfc788"
   integrity sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==
 
+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"
@@ -23567,6 +23577,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.5.1"
   resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.5.1.tgz#8388e768d383ac8cbea23e1280dfadb79f4122ad"
@@ -28520,7 +28549,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==
@@ -30425,6 +30454,11 @@ yargs-parser@20.x, yargs-parser@^20.2.2, yargs-parser@^20.2.3:
   resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.7.tgz#61df85c113edfb5a7a4e36eb8aa60ef423cbc90a"
   integrity sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==
 
+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"
@@ -30589,19 +30623,6 @@ yargs@^15.0.1, yargs@^15.4.1:
     y18n "^4.0.0"
     yargs-parser "^18.1.2"
 
-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@^2.1.1:
   version "2.3.0"
   resolved "https://registry.yarnpkg.com/yargs/-/yargs-2.3.0.tgz#e900c87250ec5cd080db6009fe3dd63156f1d7fb"