Explorar el Código

Introduce protobuffs

Leszek Wiesner hace 4 años
padre
commit
bfdace306f

+ 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
+```

+ 15 - 0
metadata-protobuf/compile.sh

@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+
+# Path to this plugin
+PROTOC_GEN_TS_PATH="./node_modules/.bin/protoc-gen-ts"
+
+# Directory to write generated code to (.js and .d.ts files)
+OUT_DIR="./compiled"
+mkdir -p ${OUT_DIR}
+
+# Compile proto files
+protoc \
+    --plugin="protoc-gen-ts=${PROTOC_GEN_TS_PATH}" \
+    --js_out="import_style=commonjs,binary:${OUT_DIR}" \
+    --ts_out="${OUT_DIR}" \
+    proto/*.proto

+ 45 - 0
metadata-protobuf/compiled/proto/Council_pb.d.ts

@@ -0,0 +1,45 @@
+// package: 
+// file: proto/Council.proto
+
+import * as jspb from "google-protobuf";
+
+export class CouncilCandidacyNoteMetadata extends jspb.Message {
+  hasHeader(): boolean;
+  clearHeader(): void;
+  getHeader(): string | undefined;
+  setHeader(value: string): void;
+
+  clearBulletPointsList(): void;
+  getBulletPointsList(): Array<string>;
+  setBulletPointsList(value: Array<string>): void;
+  addBulletPoints(value: string, index?: number): string;
+
+  hasCoverImage(): boolean;
+  clearCoverImage(): void;
+  getCoverImage(): string | undefined;
+  setCoverImage(value: string): void;
+
+  hasDescription(): boolean;
+  clearDescription(): void;
+  getDescription(): string | undefined;
+  setDescription(value: string): void;
+
+  serializeBinary(): Uint8Array;
+  toObject(includeInstance?: boolean): CouncilCandidacyNoteMetadata.AsObject;
+  static toObject(includeInstance: boolean, msg: CouncilCandidacyNoteMetadata): CouncilCandidacyNoteMetadata.AsObject;
+  static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
+  static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
+  static serializeBinaryToWriter(message: CouncilCandidacyNoteMetadata, writer: jspb.BinaryWriter): void;
+  static deserializeBinary(bytes: Uint8Array): CouncilCandidacyNoteMetadata;
+  static deserializeBinaryFromReader(message: CouncilCandidacyNoteMetadata, reader: jspb.BinaryReader): CouncilCandidacyNoteMetadata;
+}
+
+export namespace CouncilCandidacyNoteMetadata {
+  export type AsObject = {
+    header?: string,
+    bulletPointsList: Array<string>,
+    coverImage?: string,
+    description?: string,
+  }
+}
+

+ 340 - 0
metadata-protobuf/compiled/proto/Council_pb.js

@@ -0,0 +1,340 @@
+// source: proto/Council.proto
+/**
+ * @fileoverview
+ * @enhanceable
+ * @suppress {missingRequire} reports error on implicit type usages.
+ * @suppress {messageConventions} JS Compiler reports an error if a variable or
+ *     field starts with 'MSG_' and isn't a translatable message.
+ * @public
+ */
+// GENERATED CODE -- DO NOT EDIT!
+/* eslint-disable */
+// @ts-nocheck
+
+var jspb = require('google-protobuf');
+var goog = jspb;
+var global = Function('return this')();
+
+goog.exportSymbol('proto.CouncilCandidacyNoteMetadata', null, global);
+/**
+ * Generated by JsPbCodeGenerator.
+ * @param {Array=} opt_data Optional initial data array, typically from a
+ * server response, or constructed directly in Javascript. The array is used
+ * in place and becomes part of the constructed object. It is not cloned.
+ * If no data is provided, the constructed object will be empty, but still
+ * valid.
+ * @extends {jspb.Message}
+ * @constructor
+ */
+proto.CouncilCandidacyNoteMetadata = function(opt_data) {
+  jspb.Message.initialize(this, opt_data, 0, -1, proto.CouncilCandidacyNoteMetadata.repeatedFields_, null);
+};
+goog.inherits(proto.CouncilCandidacyNoteMetadata, jspb.Message);
+if (goog.DEBUG && !COMPILED) {
+  /**
+   * @public
+   * @override
+   */
+  proto.CouncilCandidacyNoteMetadata.displayName = 'proto.CouncilCandidacyNoteMetadata';
+}
+
+/**
+ * List of repeated fields within this message type.
+ * @private {!Array<number>}
+ * @const
+ */
+proto.CouncilCandidacyNoteMetadata.repeatedFields_ = [2];
+
+
+
+if (jspb.Message.GENERATE_TO_OBJECT) {
+/**
+ * Creates an object representation of this proto.
+ * Field names that are reserved in JavaScript and will be renamed to pb_name.
+ * Optional fields that are not set will be set to undefined.
+ * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
+ * For the list of reserved names please see:
+ *     net/proto2/compiler/js/internal/generator.cc#kKeyword.
+ * @param {boolean=} opt_includeInstance Deprecated. whether to include the
+ *     JSPB instance for transitional soy proto support:
+ *     http://goto/soy-param-migration
+ * @return {!Object}
+ */
+proto.CouncilCandidacyNoteMetadata.prototype.toObject = function(opt_includeInstance) {
+  return proto.CouncilCandidacyNoteMetadata.toObject(opt_includeInstance, this);
+};
+
+
+/**
+ * Static version of the {@see toObject} method.
+ * @param {boolean|undefined} includeInstance Deprecated. Whether to include
+ *     the JSPB instance for transitional soy proto support:
+ *     http://goto/soy-param-migration
+ * @param {!proto.CouncilCandidacyNoteMetadata} msg The msg instance to transform.
+ * @return {!Object}
+ * @suppress {unusedLocalVariables} f is only used for nested messages
+ */
+proto.CouncilCandidacyNoteMetadata.toObject = function(includeInstance, msg) {
+  var f, obj = {
+    header: (f = jspb.Message.getField(msg, 1)) == null ? undefined : f,
+    bulletPointsList: (f = jspb.Message.getRepeatedField(msg, 2)) == null ? undefined : f,
+    coverImage: (f = jspb.Message.getField(msg, 3)) == null ? undefined : f,
+    description: (f = jspb.Message.getField(msg, 4)) == null ? undefined : f
+  };
+
+  if (includeInstance) {
+    obj.$jspbMessageInstance = msg;
+  }
+  return obj;
+};
+}
+
+
+/**
+ * Deserializes binary data (in protobuf wire format).
+ * @param {jspb.ByteSource} bytes The bytes to deserialize.
+ * @return {!proto.CouncilCandidacyNoteMetadata}
+ */
+proto.CouncilCandidacyNoteMetadata.deserializeBinary = function(bytes) {
+  var reader = new jspb.BinaryReader(bytes);
+  var msg = new proto.CouncilCandidacyNoteMetadata;
+  return proto.CouncilCandidacyNoteMetadata.deserializeBinaryFromReader(msg, reader);
+};
+
+
+/**
+ * Deserializes binary data (in protobuf wire format) from the
+ * given reader into the given message object.
+ * @param {!proto.CouncilCandidacyNoteMetadata} msg The message object to deserialize into.
+ * @param {!jspb.BinaryReader} reader The BinaryReader to use.
+ * @return {!proto.CouncilCandidacyNoteMetadata}
+ */
+proto.CouncilCandidacyNoteMetadata.deserializeBinaryFromReader = function(msg, reader) {
+  while (reader.nextField()) {
+    if (reader.isEndGroup()) {
+      break;
+    }
+    var field = reader.getFieldNumber();
+    switch (field) {
+    case 1:
+      var value = /** @type {string} */ (reader.readString());
+      msg.setHeader(value);
+      break;
+    case 2:
+      var value = /** @type {string} */ (reader.readString());
+      msg.addBulletPoints(value);
+      break;
+    case 3:
+      var value = /** @type {string} */ (reader.readString());
+      msg.setCoverImage(value);
+      break;
+    case 4:
+      var value = /** @type {string} */ (reader.readString());
+      msg.setDescription(value);
+      break;
+    default:
+      reader.skipField();
+      break;
+    }
+  }
+  return msg;
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format).
+ * @return {!Uint8Array}
+ */
+proto.CouncilCandidacyNoteMetadata.prototype.serializeBinary = function() {
+  var writer = new jspb.BinaryWriter();
+  proto.CouncilCandidacyNoteMetadata.serializeBinaryToWriter(this, writer);
+  return writer.getResultBuffer();
+};
+
+
+/**
+ * Serializes the given message to binary data (in protobuf wire
+ * format), writing to the given BinaryWriter.
+ * @param {!proto.CouncilCandidacyNoteMetadata} message
+ * @param {!jspb.BinaryWriter} writer
+ * @suppress {unusedLocalVariables} f is only used for nested messages
+ */
+proto.CouncilCandidacyNoteMetadata.serializeBinaryToWriter = function(message, writer) {
+  var f = undefined;
+  f = /** @type {string} */ (jspb.Message.getField(message, 1));
+  if (f != null) {
+    writer.writeString(
+      1,
+      f
+    );
+  }
+  f = message.getBulletPointsList();
+  if (f.length > 0) {
+    writer.writeRepeatedString(
+      2,
+      f
+    );
+  }
+  f = /** @type {string} */ (jspb.Message.getField(message, 3));
+  if (f != null) {
+    writer.writeString(
+      3,
+      f
+    );
+  }
+  f = /** @type {string} */ (jspb.Message.getField(message, 4));
+  if (f != null) {
+    writer.writeString(
+      4,
+      f
+    );
+  }
+};
+
+
+/**
+ * optional string header = 1;
+ * @return {string}
+ */
+proto.CouncilCandidacyNoteMetadata.prototype.getHeader = function() {
+  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
+};
+
+
+/**
+ * @param {string} value
+ * @return {!proto.CouncilCandidacyNoteMetadata} returns this
+ */
+proto.CouncilCandidacyNoteMetadata.prototype.setHeader = function(value) {
+  return jspb.Message.setField(this, 1, value);
+};
+
+
+/**
+ * Clears the field making it undefined.
+ * @return {!proto.CouncilCandidacyNoteMetadata} returns this
+ */
+proto.CouncilCandidacyNoteMetadata.prototype.clearHeader = function() {
+  return jspb.Message.setField(this, 1, undefined);
+};
+
+
+/**
+ * Returns whether this field is set.
+ * @return {boolean}
+ */
+proto.CouncilCandidacyNoteMetadata.prototype.hasHeader = function() {
+  return jspb.Message.getField(this, 1) != null;
+};
+
+
+/**
+ * repeated string bullet_points = 2;
+ * @return {!Array<string>}
+ */
+proto.CouncilCandidacyNoteMetadata.prototype.getBulletPointsList = function() {
+  return /** @type {!Array<string>} */ (jspb.Message.getRepeatedField(this, 2));
+};
+
+
+/**
+ * @param {!Array<string>} value
+ * @return {!proto.CouncilCandidacyNoteMetadata} returns this
+ */
+proto.CouncilCandidacyNoteMetadata.prototype.setBulletPointsList = function(value) {
+  return jspb.Message.setField(this, 2, value || []);
+};
+
+
+/**
+ * @param {string} value
+ * @param {number=} opt_index
+ * @return {!proto.CouncilCandidacyNoteMetadata} returns this
+ */
+proto.CouncilCandidacyNoteMetadata.prototype.addBulletPoints = function(value, opt_index) {
+  return jspb.Message.addToRepeatedField(this, 2, value, opt_index);
+};
+
+
+/**
+ * Clears the list making it empty but non-null.
+ * @return {!proto.CouncilCandidacyNoteMetadata} returns this
+ */
+proto.CouncilCandidacyNoteMetadata.prototype.clearBulletPointsList = function() {
+  return this.setBulletPointsList([]);
+};
+
+
+/**
+ * optional string cover_image = 3;
+ * @return {string}
+ */
+proto.CouncilCandidacyNoteMetadata.prototype.getCoverImage = function() {
+  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, ""));
+};
+
+
+/**
+ * @param {string} value
+ * @return {!proto.CouncilCandidacyNoteMetadata} returns this
+ */
+proto.CouncilCandidacyNoteMetadata.prototype.setCoverImage = function(value) {
+  return jspb.Message.setField(this, 3, value);
+};
+
+
+/**
+ * Clears the field making it undefined.
+ * @return {!proto.CouncilCandidacyNoteMetadata} returns this
+ */
+proto.CouncilCandidacyNoteMetadata.prototype.clearCoverImage = function() {
+  return jspb.Message.setField(this, 3, undefined);
+};
+
+
+/**
+ * Returns whether this field is set.
+ * @return {boolean}
+ */
+proto.CouncilCandidacyNoteMetadata.prototype.hasCoverImage = function() {
+  return jspb.Message.getField(this, 3) != null;
+};
+
+
+/**
+ * optional string description = 4;
+ * @return {string}
+ */
+proto.CouncilCandidacyNoteMetadata.prototype.getDescription = function() {
+  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 4, ""));
+};
+
+
+/**
+ * @param {string} value
+ * @return {!proto.CouncilCandidacyNoteMetadata} returns this
+ */
+proto.CouncilCandidacyNoteMetadata.prototype.setDescription = function(value) {
+  return jspb.Message.setField(this, 4, value);
+};
+
+
+/**
+ * Clears the field making it undefined.
+ * @return {!proto.CouncilCandidacyNoteMetadata} returns this
+ */
+proto.CouncilCandidacyNoteMetadata.prototype.clearDescription = function() {
+  return jspb.Message.setField(this, 4, undefined);
+};
+
+
+/**
+ * Returns whether this field is set.
+ * @return {boolean}
+ */
+proto.CouncilCandidacyNoteMetadata.prototype.hasDescription = function() {
+  return jspb.Message.getField(this, 4) != null;
+};
+
+
+goog.object.extend(exports, proto);

+ 39 - 0
metadata-protobuf/compiled/proto/Membership_pb.d.ts

@@ -0,0 +1,39 @@
+// package: 
+// file: proto/Membership.proto
+
+import * as jspb from "google-protobuf";
+
+export class MembershipMetadata extends jspb.Message {
+  hasName(): boolean;
+  clearName(): void;
+  getName(): string | undefined;
+  setName(value: string): void;
+
+  hasAvatarUri(): boolean;
+  clearAvatarUri(): void;
+  getAvatarUri(): string | undefined;
+  setAvatarUri(value: string): void;
+
+  hasAbout(): boolean;
+  clearAbout(): void;
+  getAbout(): string | undefined;
+  setAbout(value: string): void;
+
+  serializeBinary(): Uint8Array;
+  toObject(includeInstance?: boolean): MembershipMetadata.AsObject;
+  static toObject(includeInstance: boolean, msg: MembershipMetadata): MembershipMetadata.AsObject;
+  static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
+  static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
+  static serializeBinaryToWriter(message: MembershipMetadata, writer: jspb.BinaryWriter): void;
+  static deserializeBinary(bytes: Uint8Array): MembershipMetadata;
+  static deserializeBinaryFromReader(message: MembershipMetadata, reader: jspb.BinaryReader): MembershipMetadata;
+}
+
+export namespace MembershipMetadata {
+  export type AsObject = {
+    name?: string,
+    avatarUri?: string,
+    about?: string,
+  }
+}
+

+ 284 - 0
metadata-protobuf/compiled/proto/Membership_pb.js

@@ -0,0 +1,284 @@
+// source: proto/Membership.proto
+/**
+ * @fileoverview
+ * @enhanceable
+ * @suppress {missingRequire} reports error on implicit type usages.
+ * @suppress {messageConventions} JS Compiler reports an error if a variable or
+ *     field starts with 'MSG_' and isn't a translatable message.
+ * @public
+ */
+// GENERATED CODE -- DO NOT EDIT!
+/* eslint-disable */
+// @ts-nocheck
+
+var jspb = require('google-protobuf');
+var goog = jspb;
+var global = Function('return this')();
+
+goog.exportSymbol('proto.MembershipMetadata', null, global);
+/**
+ * Generated by JsPbCodeGenerator.
+ * @param {Array=} opt_data Optional initial data array, typically from a
+ * server response, or constructed directly in Javascript. The array is used
+ * in place and becomes part of the constructed object. It is not cloned.
+ * If no data is provided, the constructed object will be empty, but still
+ * valid.
+ * @extends {jspb.Message}
+ * @constructor
+ */
+proto.MembershipMetadata = function(opt_data) {
+  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
+};
+goog.inherits(proto.MembershipMetadata, jspb.Message);
+if (goog.DEBUG && !COMPILED) {
+  /**
+   * @public
+   * @override
+   */
+  proto.MembershipMetadata.displayName = 'proto.MembershipMetadata';
+}
+
+
+
+if (jspb.Message.GENERATE_TO_OBJECT) {
+/**
+ * Creates an object representation of this proto.
+ * Field names that are reserved in JavaScript and will be renamed to pb_name.
+ * Optional fields that are not set will be set to undefined.
+ * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
+ * For the list of reserved names please see:
+ *     net/proto2/compiler/js/internal/generator.cc#kKeyword.
+ * @param {boolean=} opt_includeInstance Deprecated. whether to include the
+ *     JSPB instance for transitional soy proto support:
+ *     http://goto/soy-param-migration
+ * @return {!Object}
+ */
+proto.MembershipMetadata.prototype.toObject = function(opt_includeInstance) {
+  return proto.MembershipMetadata.toObject(opt_includeInstance, this);
+};
+
+
+/**
+ * Static version of the {@see toObject} method.
+ * @param {boolean|undefined} includeInstance Deprecated. Whether to include
+ *     the JSPB instance for transitional soy proto support:
+ *     http://goto/soy-param-migration
+ * @param {!proto.MembershipMetadata} msg The msg instance to transform.
+ * @return {!Object}
+ * @suppress {unusedLocalVariables} f is only used for nested messages
+ */
+proto.MembershipMetadata.toObject = function(includeInstance, msg) {
+  var f, obj = {
+    name: (f = jspb.Message.getField(msg, 1)) == null ? undefined : f,
+    avatarUri: (f = jspb.Message.getField(msg, 2)) == null ? undefined : f,
+    about: (f = jspb.Message.getField(msg, 3)) == null ? undefined : f
+  };
+
+  if (includeInstance) {
+    obj.$jspbMessageInstance = msg;
+  }
+  return obj;
+};
+}
+
+
+/**
+ * Deserializes binary data (in protobuf wire format).
+ * @param {jspb.ByteSource} bytes The bytes to deserialize.
+ * @return {!proto.MembershipMetadata}
+ */
+proto.MembershipMetadata.deserializeBinary = function(bytes) {
+  var reader = new jspb.BinaryReader(bytes);
+  var msg = new proto.MembershipMetadata;
+  return proto.MembershipMetadata.deserializeBinaryFromReader(msg, reader);
+};
+
+
+/**
+ * Deserializes binary data (in protobuf wire format) from the
+ * given reader into the given message object.
+ * @param {!proto.MembershipMetadata} msg The message object to deserialize into.
+ * @param {!jspb.BinaryReader} reader The BinaryReader to use.
+ * @return {!proto.MembershipMetadata}
+ */
+proto.MembershipMetadata.deserializeBinaryFromReader = function(msg, reader) {
+  while (reader.nextField()) {
+    if (reader.isEndGroup()) {
+      break;
+    }
+    var field = reader.getFieldNumber();
+    switch (field) {
+    case 1:
+      var value = /** @type {string} */ (reader.readString());
+      msg.setName(value);
+      break;
+    case 2:
+      var value = /** @type {string} */ (reader.readString());
+      msg.setAvatarUri(value);
+      break;
+    case 3:
+      var value = /** @type {string} */ (reader.readString());
+      msg.setAbout(value);
+      break;
+    default:
+      reader.skipField();
+      break;
+    }
+  }
+  return msg;
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format).
+ * @return {!Uint8Array}
+ */
+proto.MembershipMetadata.prototype.serializeBinary = function() {
+  var writer = new jspb.BinaryWriter();
+  proto.MembershipMetadata.serializeBinaryToWriter(this, writer);
+  return writer.getResultBuffer();
+};
+
+
+/**
+ * Serializes the given message to binary data (in protobuf wire
+ * format), writing to the given BinaryWriter.
+ * @param {!proto.MembershipMetadata} message
+ * @param {!jspb.BinaryWriter} writer
+ * @suppress {unusedLocalVariables} f is only used for nested messages
+ */
+proto.MembershipMetadata.serializeBinaryToWriter = function(message, writer) {
+  var f = undefined;
+  f = /** @type {string} */ (jspb.Message.getField(message, 1));
+  if (f != null) {
+    writer.writeString(
+      1,
+      f
+    );
+  }
+  f = /** @type {string} */ (jspb.Message.getField(message, 2));
+  if (f != null) {
+    writer.writeString(
+      2,
+      f
+    );
+  }
+  f = /** @type {string} */ (jspb.Message.getField(message, 3));
+  if (f != null) {
+    writer.writeString(
+      3,
+      f
+    );
+  }
+};
+
+
+/**
+ * optional string name = 1;
+ * @return {string}
+ */
+proto.MembershipMetadata.prototype.getName = function() {
+  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
+};
+
+
+/**
+ * @param {string} value
+ * @return {!proto.MembershipMetadata} returns this
+ */
+proto.MembershipMetadata.prototype.setName = function(value) {
+  return jspb.Message.setField(this, 1, value);
+};
+
+
+/**
+ * Clears the field making it undefined.
+ * @return {!proto.MembershipMetadata} returns this
+ */
+proto.MembershipMetadata.prototype.clearName = function() {
+  return jspb.Message.setField(this, 1, undefined);
+};
+
+
+/**
+ * Returns whether this field is set.
+ * @return {boolean}
+ */
+proto.MembershipMetadata.prototype.hasName = function() {
+  return jspb.Message.getField(this, 1) != null;
+};
+
+
+/**
+ * optional string avatar_uri = 2;
+ * @return {string}
+ */
+proto.MembershipMetadata.prototype.getAvatarUri = function() {
+  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
+};
+
+
+/**
+ * @param {string} value
+ * @return {!proto.MembershipMetadata} returns this
+ */
+proto.MembershipMetadata.prototype.setAvatarUri = function(value) {
+  return jspb.Message.setField(this, 2, value);
+};
+
+
+/**
+ * Clears the field making it undefined.
+ * @return {!proto.MembershipMetadata} returns this
+ */
+proto.MembershipMetadata.prototype.clearAvatarUri = function() {
+  return jspb.Message.setField(this, 2, undefined);
+};
+
+
+/**
+ * Returns whether this field is set.
+ * @return {boolean}
+ */
+proto.MembershipMetadata.prototype.hasAvatarUri = function() {
+  return jspb.Message.getField(this, 2) != null;
+};
+
+
+/**
+ * optional string about = 3;
+ * @return {string}
+ */
+proto.MembershipMetadata.prototype.getAbout = function() {
+  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, ""));
+};
+
+
+/**
+ * @param {string} value
+ * @return {!proto.MembershipMetadata} returns this
+ */
+proto.MembershipMetadata.prototype.setAbout = function(value) {
+  return jspb.Message.setField(this, 3, value);
+};
+
+
+/**
+ * Clears the field making it undefined.
+ * @return {!proto.MembershipMetadata} returns this
+ */
+proto.MembershipMetadata.prototype.clearAbout = function() {
+  return jspb.Message.setField(this, 3, undefined);
+};
+
+
+/**
+ * Returns whether this field is set.
+ * @return {boolean}
+ */
+proto.MembershipMetadata.prototype.hasAbout = function() {
+  return jspb.Message.getField(this, 3) != null;
+};
+
+
+goog.object.extend(exports, proto);

+ 154 - 0
metadata-protobuf/compiled/proto/WorkingGroups_pb.d.ts

@@ -0,0 +1,154 @@
+// package: 
+// file: proto/WorkingGroups.proto
+
+import * as jspb from "google-protobuf";
+
+export class OpeningMetadata extends jspb.Message {
+  hasShortDescription(): boolean;
+  clearShortDescription(): void;
+  getShortDescription(): string | undefined;
+  setShortDescription(value: string): void;
+
+  hasDescription(): boolean;
+  clearDescription(): void;
+  getDescription(): string | undefined;
+  setDescription(value: string): void;
+
+  hasHiringLimit(): boolean;
+  clearHiringLimit(): void;
+  getHiringLimit(): number | undefined;
+  setHiringLimit(value: number): void;
+
+  hasExpectedDuration(): boolean;
+  clearExpectedDuration(): void;
+  getExpectedDuration(): number | undefined;
+  setExpectedDuration(value: number): void;
+
+  hasApplicationDetails(): boolean;
+  clearApplicationDetails(): void;
+  getApplicationDetails(): string | undefined;
+  setApplicationDetails(value: string): void;
+
+  clearApplicationFormQuestionsList(): void;
+  getApplicationFormQuestionsList(): Array<OpeningMetadata.ApplicationFormQuestion>;
+  setApplicationFormQuestionsList(value: Array<OpeningMetadata.ApplicationFormQuestion>): void;
+  addApplicationFormQuestions(value?: OpeningMetadata.ApplicationFormQuestion, index?: number): OpeningMetadata.ApplicationFormQuestion;
+
+  serializeBinary(): Uint8Array;
+  toObject(includeInstance?: boolean): OpeningMetadata.AsObject;
+  static toObject(includeInstance: boolean, msg: OpeningMetadata): OpeningMetadata.AsObject;
+  static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
+  static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
+  static serializeBinaryToWriter(message: OpeningMetadata, writer: jspb.BinaryWriter): void;
+  static deserializeBinary(bytes: Uint8Array): OpeningMetadata;
+  static deserializeBinaryFromReader(message: OpeningMetadata, reader: jspb.BinaryReader): OpeningMetadata;
+}
+
+export namespace OpeningMetadata {
+  export type AsObject = {
+    shortDescription?: string,
+    description?: string,
+    hiringLimit?: number,
+    expectedDuration?: number,
+    applicationDetails?: string,
+    applicationFormQuestionsList: Array<OpeningMetadata.ApplicationFormQuestion.AsObject>,
+  }
+
+  export class ApplicationFormQuestion extends jspb.Message {
+    hasQuestion(): boolean;
+    clearQuestion(): void;
+    getQuestion(): string | undefined;
+    setQuestion(value: string): void;
+
+    hasType(): boolean;
+    clearType(): void;
+    getType(): OpeningMetadata.ApplicationFormQuestion.InputTypeMap[keyof OpeningMetadata.ApplicationFormQuestion.InputTypeMap] | undefined;
+    setType(value: OpeningMetadata.ApplicationFormQuestion.InputTypeMap[keyof OpeningMetadata.ApplicationFormQuestion.InputTypeMap]): void;
+
+    serializeBinary(): Uint8Array;
+    toObject(includeInstance?: boolean): ApplicationFormQuestion.AsObject;
+    static toObject(includeInstance: boolean, msg: ApplicationFormQuestion): ApplicationFormQuestion.AsObject;
+    static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
+    static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
+    static serializeBinaryToWriter(message: ApplicationFormQuestion, writer: jspb.BinaryWriter): void;
+    static deserializeBinary(bytes: Uint8Array): ApplicationFormQuestion;
+    static deserializeBinaryFromReader(message: ApplicationFormQuestion, reader: jspb.BinaryReader): ApplicationFormQuestion;
+  }
+
+  export namespace ApplicationFormQuestion {
+    export type AsObject = {
+      question?: string,
+      type?: OpeningMetadata.ApplicationFormQuestion.InputTypeMap[keyof OpeningMetadata.ApplicationFormQuestion.InputTypeMap],
+    }
+
+    export interface InputTypeMap {
+      TEXT: 1;
+      TEXTAREA: 2;
+    }
+
+    export const InputType: InputTypeMap;
+  }
+}
+
+export class ApplicationMetadata extends jspb.Message {
+  clearAnswersList(): void;
+  getAnswersList(): Array<string>;
+  setAnswersList(value: Array<string>): void;
+  addAnswers(value: string, index?: number): string;
+
+  serializeBinary(): Uint8Array;
+  toObject(includeInstance?: boolean): ApplicationMetadata.AsObject;
+  static toObject(includeInstance: boolean, msg: ApplicationMetadata): ApplicationMetadata.AsObject;
+  static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
+  static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
+  static serializeBinaryToWriter(message: ApplicationMetadata, writer: jspb.BinaryWriter): void;
+  static deserializeBinary(bytes: Uint8Array): ApplicationMetadata;
+  static deserializeBinaryFromReader(message: ApplicationMetadata, reader: jspb.BinaryReader): ApplicationMetadata;
+}
+
+export namespace ApplicationMetadata {
+  export type AsObject = {
+    answersList: Array<string>,
+  }
+}
+
+export class WorkingGroupStatusMetadata extends jspb.Message {
+  hasDescription(): boolean;
+  clearDescription(): void;
+  getDescription(): string | undefined;
+  setDescription(value: string): void;
+
+  hasAbout(): boolean;
+  clearAbout(): void;
+  getAbout(): string | undefined;
+  setAbout(value: string): void;
+
+  hasStatus(): boolean;
+  clearStatus(): void;
+  getStatus(): string | undefined;
+  setStatus(value: string): void;
+
+  hasStatusMessage(): boolean;
+  clearStatusMessage(): void;
+  getStatusMessage(): string | undefined;
+  setStatusMessage(value: string): void;
+
+  serializeBinary(): Uint8Array;
+  toObject(includeInstance?: boolean): WorkingGroupStatusMetadata.AsObject;
+  static toObject(includeInstance: boolean, msg: WorkingGroupStatusMetadata): WorkingGroupStatusMetadata.AsObject;
+  static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
+  static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
+  static serializeBinaryToWriter(message: WorkingGroupStatusMetadata, writer: jspb.BinaryWriter): void;
+  static deserializeBinary(bytes: Uint8Array): WorkingGroupStatusMetadata;
+  static deserializeBinaryFromReader(message: WorkingGroupStatusMetadata, reader: jspb.BinaryReader): WorkingGroupStatusMetadata;
+}
+
+export namespace WorkingGroupStatusMetadata {
+  export type AsObject = {
+    description?: string,
+    about?: string,
+    status?: string,
+    statusMessage?: string,
+  }
+}
+

+ 1159 - 0
metadata-protobuf/compiled/proto/WorkingGroups_pb.js

@@ -0,0 +1,1159 @@
+// source: proto/WorkingGroups.proto
+/**
+ * @fileoverview
+ * @enhanceable
+ * @suppress {missingRequire} reports error on implicit type usages.
+ * @suppress {messageConventions} JS Compiler reports an error if a variable or
+ *     field starts with 'MSG_' and isn't a translatable message.
+ * @public
+ */
+// GENERATED CODE -- DO NOT EDIT!
+/* eslint-disable */
+// @ts-nocheck
+
+var jspb = require('google-protobuf');
+var goog = jspb;
+var global = Function('return this')();
+
+goog.exportSymbol('proto.ApplicationMetadata', null, global);
+goog.exportSymbol('proto.OpeningMetadata', null, global);
+goog.exportSymbol('proto.OpeningMetadata.ApplicationFormQuestion', null, global);
+goog.exportSymbol('proto.OpeningMetadata.ApplicationFormQuestion.InputType', null, global);
+goog.exportSymbol('proto.WorkingGroupStatusMetadata', null, global);
+/**
+ * Generated by JsPbCodeGenerator.
+ * @param {Array=} opt_data Optional initial data array, typically from a
+ * server response, or constructed directly in Javascript. The array is used
+ * in place and becomes part of the constructed object. It is not cloned.
+ * If no data is provided, the constructed object will be empty, but still
+ * valid.
+ * @extends {jspb.Message}
+ * @constructor
+ */
+proto.OpeningMetadata = function(opt_data) {
+  jspb.Message.initialize(this, opt_data, 0, -1, proto.OpeningMetadata.repeatedFields_, null);
+};
+goog.inherits(proto.OpeningMetadata, jspb.Message);
+if (goog.DEBUG && !COMPILED) {
+  /**
+   * @public
+   * @override
+   */
+  proto.OpeningMetadata.displayName = 'proto.OpeningMetadata';
+}
+/**
+ * Generated by JsPbCodeGenerator.
+ * @param {Array=} opt_data Optional initial data array, typically from a
+ * server response, or constructed directly in Javascript. The array is used
+ * in place and becomes part of the constructed object. It is not cloned.
+ * If no data is provided, the constructed object will be empty, but still
+ * valid.
+ * @extends {jspb.Message}
+ * @constructor
+ */
+proto.OpeningMetadata.ApplicationFormQuestion = function(opt_data) {
+  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
+};
+goog.inherits(proto.OpeningMetadata.ApplicationFormQuestion, jspb.Message);
+if (goog.DEBUG && !COMPILED) {
+  /**
+   * @public
+   * @override
+   */
+  proto.OpeningMetadata.ApplicationFormQuestion.displayName = 'proto.OpeningMetadata.ApplicationFormQuestion';
+}
+/**
+ * Generated by JsPbCodeGenerator.
+ * @param {Array=} opt_data Optional initial data array, typically from a
+ * server response, or constructed directly in Javascript. The array is used
+ * in place and becomes part of the constructed object. It is not cloned.
+ * If no data is provided, the constructed object will be empty, but still
+ * valid.
+ * @extends {jspb.Message}
+ * @constructor
+ */
+proto.ApplicationMetadata = function(opt_data) {
+  jspb.Message.initialize(this, opt_data, 0, -1, proto.ApplicationMetadata.repeatedFields_, null);
+};
+goog.inherits(proto.ApplicationMetadata, jspb.Message);
+if (goog.DEBUG && !COMPILED) {
+  /**
+   * @public
+   * @override
+   */
+  proto.ApplicationMetadata.displayName = 'proto.ApplicationMetadata';
+}
+/**
+ * Generated by JsPbCodeGenerator.
+ * @param {Array=} opt_data Optional initial data array, typically from a
+ * server response, or constructed directly in Javascript. The array is used
+ * in place and becomes part of the constructed object. It is not cloned.
+ * If no data is provided, the constructed object will be empty, but still
+ * valid.
+ * @extends {jspb.Message}
+ * @constructor
+ */
+proto.WorkingGroupStatusMetadata = function(opt_data) {
+  jspb.Message.initialize(this, opt_data, 0, -1, null, null);
+};
+goog.inherits(proto.WorkingGroupStatusMetadata, jspb.Message);
+if (goog.DEBUG && !COMPILED) {
+  /**
+   * @public
+   * @override
+   */
+  proto.WorkingGroupStatusMetadata.displayName = 'proto.WorkingGroupStatusMetadata';
+}
+
+/**
+ * List of repeated fields within this message type.
+ * @private {!Array<number>}
+ * @const
+ */
+proto.OpeningMetadata.repeatedFields_ = [6];
+
+
+
+if (jspb.Message.GENERATE_TO_OBJECT) {
+/**
+ * Creates an object representation of this proto.
+ * Field names that are reserved in JavaScript and will be renamed to pb_name.
+ * Optional fields that are not set will be set to undefined.
+ * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
+ * For the list of reserved names please see:
+ *     net/proto2/compiler/js/internal/generator.cc#kKeyword.
+ * @param {boolean=} opt_includeInstance Deprecated. whether to include the
+ *     JSPB instance for transitional soy proto support:
+ *     http://goto/soy-param-migration
+ * @return {!Object}
+ */
+proto.OpeningMetadata.prototype.toObject = function(opt_includeInstance) {
+  return proto.OpeningMetadata.toObject(opt_includeInstance, this);
+};
+
+
+/**
+ * Static version of the {@see toObject} method.
+ * @param {boolean|undefined} includeInstance Deprecated. Whether to include
+ *     the JSPB instance for transitional soy proto support:
+ *     http://goto/soy-param-migration
+ * @param {!proto.OpeningMetadata} msg The msg instance to transform.
+ * @return {!Object}
+ * @suppress {unusedLocalVariables} f is only used for nested messages
+ */
+proto.OpeningMetadata.toObject = function(includeInstance, msg) {
+  var f, obj = {
+    shortDescription: (f = jspb.Message.getField(msg, 1)) == null ? undefined : f,
+    description: (f = jspb.Message.getField(msg, 2)) == null ? undefined : f,
+    hiringLimit: (f = jspb.Message.getField(msg, 3)) == null ? undefined : f,
+    expectedDuration: (f = jspb.Message.getField(msg, 4)) == null ? undefined : f,
+    applicationDetails: (f = jspb.Message.getField(msg, 5)) == null ? undefined : f,
+    applicationFormQuestionsList: jspb.Message.toObjectList(msg.getApplicationFormQuestionsList(),
+    proto.OpeningMetadata.ApplicationFormQuestion.toObject, includeInstance)
+  };
+
+  if (includeInstance) {
+    obj.$jspbMessageInstance = msg;
+  }
+  return obj;
+};
+}
+
+
+/**
+ * Deserializes binary data (in protobuf wire format).
+ * @param {jspb.ByteSource} bytes The bytes to deserialize.
+ * @return {!proto.OpeningMetadata}
+ */
+proto.OpeningMetadata.deserializeBinary = function(bytes) {
+  var reader = new jspb.BinaryReader(bytes);
+  var msg = new proto.OpeningMetadata;
+  return proto.OpeningMetadata.deserializeBinaryFromReader(msg, reader);
+};
+
+
+/**
+ * Deserializes binary data (in protobuf wire format) from the
+ * given reader into the given message object.
+ * @param {!proto.OpeningMetadata} msg The message object to deserialize into.
+ * @param {!jspb.BinaryReader} reader The BinaryReader to use.
+ * @return {!proto.OpeningMetadata}
+ */
+proto.OpeningMetadata.deserializeBinaryFromReader = function(msg, reader) {
+  while (reader.nextField()) {
+    if (reader.isEndGroup()) {
+      break;
+    }
+    var field = reader.getFieldNumber();
+    switch (field) {
+    case 1:
+      var value = /** @type {string} */ (reader.readString());
+      msg.setShortDescription(value);
+      break;
+    case 2:
+      var value = /** @type {string} */ (reader.readString());
+      msg.setDescription(value);
+      break;
+    case 3:
+      var value = /** @type {number} */ (reader.readUint32());
+      msg.setHiringLimit(value);
+      break;
+    case 4:
+      var value = /** @type {number} */ (reader.readUint32());
+      msg.setExpectedDuration(value);
+      break;
+    case 5:
+      var value = /** @type {string} */ (reader.readString());
+      msg.setApplicationDetails(value);
+      break;
+    case 6:
+      var value = new proto.OpeningMetadata.ApplicationFormQuestion;
+      reader.readMessage(value,proto.OpeningMetadata.ApplicationFormQuestion.deserializeBinaryFromReader);
+      msg.addApplicationFormQuestions(value);
+      break;
+    default:
+      reader.skipField();
+      break;
+    }
+  }
+  return msg;
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format).
+ * @return {!Uint8Array}
+ */
+proto.OpeningMetadata.prototype.serializeBinary = function() {
+  var writer = new jspb.BinaryWriter();
+  proto.OpeningMetadata.serializeBinaryToWriter(this, writer);
+  return writer.getResultBuffer();
+};
+
+
+/**
+ * Serializes the given message to binary data (in protobuf wire
+ * format), writing to the given BinaryWriter.
+ * @param {!proto.OpeningMetadata} message
+ * @param {!jspb.BinaryWriter} writer
+ * @suppress {unusedLocalVariables} f is only used for nested messages
+ */
+proto.OpeningMetadata.serializeBinaryToWriter = function(message, writer) {
+  var f = undefined;
+  f = /** @type {string} */ (jspb.Message.getField(message, 1));
+  if (f != null) {
+    writer.writeString(
+      1,
+      f
+    );
+  }
+  f = /** @type {string} */ (jspb.Message.getField(message, 2));
+  if (f != null) {
+    writer.writeString(
+      2,
+      f
+    );
+  }
+  f = /** @type {number} */ (jspb.Message.getField(message, 3));
+  if (f != null) {
+    writer.writeUint32(
+      3,
+      f
+    );
+  }
+  f = /** @type {number} */ (jspb.Message.getField(message, 4));
+  if (f != null) {
+    writer.writeUint32(
+      4,
+      f
+    );
+  }
+  f = /** @type {string} */ (jspb.Message.getField(message, 5));
+  if (f != null) {
+    writer.writeString(
+      5,
+      f
+    );
+  }
+  f = message.getApplicationFormQuestionsList();
+  if (f.length > 0) {
+    writer.writeRepeatedMessage(
+      6,
+      f,
+      proto.OpeningMetadata.ApplicationFormQuestion.serializeBinaryToWriter
+    );
+  }
+};
+
+
+
+
+
+if (jspb.Message.GENERATE_TO_OBJECT) {
+/**
+ * Creates an object representation of this proto.
+ * Field names that are reserved in JavaScript and will be renamed to pb_name.
+ * Optional fields that are not set will be set to undefined.
+ * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
+ * For the list of reserved names please see:
+ *     net/proto2/compiler/js/internal/generator.cc#kKeyword.
+ * @param {boolean=} opt_includeInstance Deprecated. whether to include the
+ *     JSPB instance for transitional soy proto support:
+ *     http://goto/soy-param-migration
+ * @return {!Object}
+ */
+proto.OpeningMetadata.ApplicationFormQuestion.prototype.toObject = function(opt_includeInstance) {
+  return proto.OpeningMetadata.ApplicationFormQuestion.toObject(opt_includeInstance, this);
+};
+
+
+/**
+ * Static version of the {@see toObject} method.
+ * @param {boolean|undefined} includeInstance Deprecated. Whether to include
+ *     the JSPB instance for transitional soy proto support:
+ *     http://goto/soy-param-migration
+ * @param {!proto.OpeningMetadata.ApplicationFormQuestion} msg The msg instance to transform.
+ * @return {!Object}
+ * @suppress {unusedLocalVariables} f is only used for nested messages
+ */
+proto.OpeningMetadata.ApplicationFormQuestion.toObject = function(includeInstance, msg) {
+  var f, obj = {
+    question: (f = jspb.Message.getField(msg, 1)) == null ? undefined : f,
+    type: (f = jspb.Message.getField(msg, 2)) == null ? undefined : f
+  };
+
+  if (includeInstance) {
+    obj.$jspbMessageInstance = msg;
+  }
+  return obj;
+};
+}
+
+
+/**
+ * Deserializes binary data (in protobuf wire format).
+ * @param {jspb.ByteSource} bytes The bytes to deserialize.
+ * @return {!proto.OpeningMetadata.ApplicationFormQuestion}
+ */
+proto.OpeningMetadata.ApplicationFormQuestion.deserializeBinary = function(bytes) {
+  var reader = new jspb.BinaryReader(bytes);
+  var msg = new proto.OpeningMetadata.ApplicationFormQuestion;
+  return proto.OpeningMetadata.ApplicationFormQuestion.deserializeBinaryFromReader(msg, reader);
+};
+
+
+/**
+ * Deserializes binary data (in protobuf wire format) from the
+ * given reader into the given message object.
+ * @param {!proto.OpeningMetadata.ApplicationFormQuestion} msg The message object to deserialize into.
+ * @param {!jspb.BinaryReader} reader The BinaryReader to use.
+ * @return {!proto.OpeningMetadata.ApplicationFormQuestion}
+ */
+proto.OpeningMetadata.ApplicationFormQuestion.deserializeBinaryFromReader = function(msg, reader) {
+  while (reader.nextField()) {
+    if (reader.isEndGroup()) {
+      break;
+    }
+    var field = reader.getFieldNumber();
+    switch (field) {
+    case 1:
+      var value = /** @type {string} */ (reader.readString());
+      msg.setQuestion(value);
+      break;
+    case 2:
+      var value = /** @type {!proto.OpeningMetadata.ApplicationFormQuestion.InputType} */ (reader.readEnum());
+      msg.setType(value);
+      break;
+    default:
+      reader.skipField();
+      break;
+    }
+  }
+  return msg;
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format).
+ * @return {!Uint8Array}
+ */
+proto.OpeningMetadata.ApplicationFormQuestion.prototype.serializeBinary = function() {
+  var writer = new jspb.BinaryWriter();
+  proto.OpeningMetadata.ApplicationFormQuestion.serializeBinaryToWriter(this, writer);
+  return writer.getResultBuffer();
+};
+
+
+/**
+ * Serializes the given message to binary data (in protobuf wire
+ * format), writing to the given BinaryWriter.
+ * @param {!proto.OpeningMetadata.ApplicationFormQuestion} message
+ * @param {!jspb.BinaryWriter} writer
+ * @suppress {unusedLocalVariables} f is only used for nested messages
+ */
+proto.OpeningMetadata.ApplicationFormQuestion.serializeBinaryToWriter = function(message, writer) {
+  var f = undefined;
+  f = /** @type {string} */ (jspb.Message.getField(message, 1));
+  if (f != null) {
+    writer.writeString(
+      1,
+      f
+    );
+  }
+  f = /** @type {!proto.OpeningMetadata.ApplicationFormQuestion.InputType} */ (jspb.Message.getField(message, 2));
+  if (f != null) {
+    writer.writeEnum(
+      2,
+      f
+    );
+  }
+};
+
+
+/**
+ * @enum {number}
+ */
+proto.OpeningMetadata.ApplicationFormQuestion.InputType = {
+  TEXT: 1,
+  TEXTAREA: 2
+};
+
+/**
+ * required string question = 1;
+ * @return {string}
+ */
+proto.OpeningMetadata.ApplicationFormQuestion.prototype.getQuestion = function() {
+  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
+};
+
+
+/**
+ * @param {string} value
+ * @return {!proto.OpeningMetadata.ApplicationFormQuestion} returns this
+ */
+proto.OpeningMetadata.ApplicationFormQuestion.prototype.setQuestion = function(value) {
+  return jspb.Message.setField(this, 1, value);
+};
+
+
+/**
+ * Clears the field making it undefined.
+ * @return {!proto.OpeningMetadata.ApplicationFormQuestion} returns this
+ */
+proto.OpeningMetadata.ApplicationFormQuestion.prototype.clearQuestion = function() {
+  return jspb.Message.setField(this, 1, undefined);
+};
+
+
+/**
+ * Returns whether this field is set.
+ * @return {boolean}
+ */
+proto.OpeningMetadata.ApplicationFormQuestion.prototype.hasQuestion = function() {
+  return jspb.Message.getField(this, 1) != null;
+};
+
+
+/**
+ * required InputType type = 2;
+ * @return {!proto.OpeningMetadata.ApplicationFormQuestion.InputType}
+ */
+proto.OpeningMetadata.ApplicationFormQuestion.prototype.getType = function() {
+  return /** @type {!proto.OpeningMetadata.ApplicationFormQuestion.InputType} */ (jspb.Message.getFieldWithDefault(this, 2, 1));
+};
+
+
+/**
+ * @param {!proto.OpeningMetadata.ApplicationFormQuestion.InputType} value
+ * @return {!proto.OpeningMetadata.ApplicationFormQuestion} returns this
+ */
+proto.OpeningMetadata.ApplicationFormQuestion.prototype.setType = function(value) {
+  return jspb.Message.setField(this, 2, value);
+};
+
+
+/**
+ * Clears the field making it undefined.
+ * @return {!proto.OpeningMetadata.ApplicationFormQuestion} returns this
+ */
+proto.OpeningMetadata.ApplicationFormQuestion.prototype.clearType = function() {
+  return jspb.Message.setField(this, 2, undefined);
+};
+
+
+/**
+ * Returns whether this field is set.
+ * @return {boolean}
+ */
+proto.OpeningMetadata.ApplicationFormQuestion.prototype.hasType = function() {
+  return jspb.Message.getField(this, 2) != null;
+};
+
+
+/**
+ * required string short_description = 1;
+ * @return {string}
+ */
+proto.OpeningMetadata.prototype.getShortDescription = function() {
+  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
+};
+
+
+/**
+ * @param {string} value
+ * @return {!proto.OpeningMetadata} returns this
+ */
+proto.OpeningMetadata.prototype.setShortDescription = function(value) {
+  return jspb.Message.setField(this, 1, value);
+};
+
+
+/**
+ * Clears the field making it undefined.
+ * @return {!proto.OpeningMetadata} returns this
+ */
+proto.OpeningMetadata.prototype.clearShortDescription = function() {
+  return jspb.Message.setField(this, 1, undefined);
+};
+
+
+/**
+ * Returns whether this field is set.
+ * @return {boolean}
+ */
+proto.OpeningMetadata.prototype.hasShortDescription = function() {
+  return jspb.Message.getField(this, 1) != null;
+};
+
+
+/**
+ * required string description = 2;
+ * @return {string}
+ */
+proto.OpeningMetadata.prototype.getDescription = function() {
+  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
+};
+
+
+/**
+ * @param {string} value
+ * @return {!proto.OpeningMetadata} returns this
+ */
+proto.OpeningMetadata.prototype.setDescription = function(value) {
+  return jspb.Message.setField(this, 2, value);
+};
+
+
+/**
+ * Clears the field making it undefined.
+ * @return {!proto.OpeningMetadata} returns this
+ */
+proto.OpeningMetadata.prototype.clearDescription = function() {
+  return jspb.Message.setField(this, 2, undefined);
+};
+
+
+/**
+ * Returns whether this field is set.
+ * @return {boolean}
+ */
+proto.OpeningMetadata.prototype.hasDescription = function() {
+  return jspb.Message.getField(this, 2) != null;
+};
+
+
+/**
+ * required uint32 hiring_limit = 3;
+ * @return {number}
+ */
+proto.OpeningMetadata.prototype.getHiringLimit = function() {
+  return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 3, 0));
+};
+
+
+/**
+ * @param {number} value
+ * @return {!proto.OpeningMetadata} returns this
+ */
+proto.OpeningMetadata.prototype.setHiringLimit = function(value) {
+  return jspb.Message.setField(this, 3, value);
+};
+
+
+/**
+ * Clears the field making it undefined.
+ * @return {!proto.OpeningMetadata} returns this
+ */
+proto.OpeningMetadata.prototype.clearHiringLimit = function() {
+  return jspb.Message.setField(this, 3, undefined);
+};
+
+
+/**
+ * Returns whether this field is set.
+ * @return {boolean}
+ */
+proto.OpeningMetadata.prototype.hasHiringLimit = function() {
+  return jspb.Message.getField(this, 3) != null;
+};
+
+
+/**
+ * required uint32 expected_duration = 4;
+ * @return {number}
+ */
+proto.OpeningMetadata.prototype.getExpectedDuration = function() {
+  return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 4, 0));
+};
+
+
+/**
+ * @param {number} value
+ * @return {!proto.OpeningMetadata} returns this
+ */
+proto.OpeningMetadata.prototype.setExpectedDuration = function(value) {
+  return jspb.Message.setField(this, 4, value);
+};
+
+
+/**
+ * Clears the field making it undefined.
+ * @return {!proto.OpeningMetadata} returns this
+ */
+proto.OpeningMetadata.prototype.clearExpectedDuration = function() {
+  return jspb.Message.setField(this, 4, undefined);
+};
+
+
+/**
+ * Returns whether this field is set.
+ * @return {boolean}
+ */
+proto.OpeningMetadata.prototype.hasExpectedDuration = function() {
+  return jspb.Message.getField(this, 4) != null;
+};
+
+
+/**
+ * required string application_details = 5;
+ * @return {string}
+ */
+proto.OpeningMetadata.prototype.getApplicationDetails = function() {
+  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 5, ""));
+};
+
+
+/**
+ * @param {string} value
+ * @return {!proto.OpeningMetadata} returns this
+ */
+proto.OpeningMetadata.prototype.setApplicationDetails = function(value) {
+  return jspb.Message.setField(this, 5, value);
+};
+
+
+/**
+ * Clears the field making it undefined.
+ * @return {!proto.OpeningMetadata} returns this
+ */
+proto.OpeningMetadata.prototype.clearApplicationDetails = function() {
+  return jspb.Message.setField(this, 5, undefined);
+};
+
+
+/**
+ * Returns whether this field is set.
+ * @return {boolean}
+ */
+proto.OpeningMetadata.prototype.hasApplicationDetails = function() {
+  return jspb.Message.getField(this, 5) != null;
+};
+
+
+/**
+ * repeated ApplicationFormQuestion application_form_questions = 6;
+ * @return {!Array<!proto.OpeningMetadata.ApplicationFormQuestion>}
+ */
+proto.OpeningMetadata.prototype.getApplicationFormQuestionsList = function() {
+  return /** @type{!Array<!proto.OpeningMetadata.ApplicationFormQuestion>} */ (
+    jspb.Message.getRepeatedWrapperField(this, proto.OpeningMetadata.ApplicationFormQuestion, 6));
+};
+
+
+/**
+ * @param {!Array<!proto.OpeningMetadata.ApplicationFormQuestion>} value
+ * @return {!proto.OpeningMetadata} returns this
+*/
+proto.OpeningMetadata.prototype.setApplicationFormQuestionsList = function(value) {
+  return jspb.Message.setRepeatedWrapperField(this, 6, value);
+};
+
+
+/**
+ * @param {!proto.OpeningMetadata.ApplicationFormQuestion=} opt_value
+ * @param {number=} opt_index
+ * @return {!proto.OpeningMetadata.ApplicationFormQuestion}
+ */
+proto.OpeningMetadata.prototype.addApplicationFormQuestions = function(opt_value, opt_index) {
+  return jspb.Message.addToRepeatedWrapperField(this, 6, opt_value, proto.OpeningMetadata.ApplicationFormQuestion, opt_index);
+};
+
+
+/**
+ * Clears the list making it empty but non-null.
+ * @return {!proto.OpeningMetadata} returns this
+ */
+proto.OpeningMetadata.prototype.clearApplicationFormQuestionsList = function() {
+  return this.setApplicationFormQuestionsList([]);
+};
+
+
+
+/**
+ * List of repeated fields within this message type.
+ * @private {!Array<number>}
+ * @const
+ */
+proto.ApplicationMetadata.repeatedFields_ = [1];
+
+
+
+if (jspb.Message.GENERATE_TO_OBJECT) {
+/**
+ * Creates an object representation of this proto.
+ * Field names that are reserved in JavaScript and will be renamed to pb_name.
+ * Optional fields that are not set will be set to undefined.
+ * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
+ * For the list of reserved names please see:
+ *     net/proto2/compiler/js/internal/generator.cc#kKeyword.
+ * @param {boolean=} opt_includeInstance Deprecated. whether to include the
+ *     JSPB instance for transitional soy proto support:
+ *     http://goto/soy-param-migration
+ * @return {!Object}
+ */
+proto.ApplicationMetadata.prototype.toObject = function(opt_includeInstance) {
+  return proto.ApplicationMetadata.toObject(opt_includeInstance, this);
+};
+
+
+/**
+ * Static version of the {@see toObject} method.
+ * @param {boolean|undefined} includeInstance Deprecated. Whether to include
+ *     the JSPB instance for transitional soy proto support:
+ *     http://goto/soy-param-migration
+ * @param {!proto.ApplicationMetadata} msg The msg instance to transform.
+ * @return {!Object}
+ * @suppress {unusedLocalVariables} f is only used for nested messages
+ */
+proto.ApplicationMetadata.toObject = function(includeInstance, msg) {
+  var f, obj = {
+    answersList: (f = jspb.Message.getRepeatedField(msg, 1)) == null ? undefined : f
+  };
+
+  if (includeInstance) {
+    obj.$jspbMessageInstance = msg;
+  }
+  return obj;
+};
+}
+
+
+/**
+ * Deserializes binary data (in protobuf wire format).
+ * @param {jspb.ByteSource} bytes The bytes to deserialize.
+ * @return {!proto.ApplicationMetadata}
+ */
+proto.ApplicationMetadata.deserializeBinary = function(bytes) {
+  var reader = new jspb.BinaryReader(bytes);
+  var msg = new proto.ApplicationMetadata;
+  return proto.ApplicationMetadata.deserializeBinaryFromReader(msg, reader);
+};
+
+
+/**
+ * Deserializes binary data (in protobuf wire format) from the
+ * given reader into the given message object.
+ * @param {!proto.ApplicationMetadata} msg The message object to deserialize into.
+ * @param {!jspb.BinaryReader} reader The BinaryReader to use.
+ * @return {!proto.ApplicationMetadata}
+ */
+proto.ApplicationMetadata.deserializeBinaryFromReader = function(msg, reader) {
+  while (reader.nextField()) {
+    if (reader.isEndGroup()) {
+      break;
+    }
+    var field = reader.getFieldNumber();
+    switch (field) {
+    case 1:
+      var value = /** @type {string} */ (reader.readString());
+      msg.addAnswers(value);
+      break;
+    default:
+      reader.skipField();
+      break;
+    }
+  }
+  return msg;
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format).
+ * @return {!Uint8Array}
+ */
+proto.ApplicationMetadata.prototype.serializeBinary = function() {
+  var writer = new jspb.BinaryWriter();
+  proto.ApplicationMetadata.serializeBinaryToWriter(this, writer);
+  return writer.getResultBuffer();
+};
+
+
+/**
+ * Serializes the given message to binary data (in protobuf wire
+ * format), writing to the given BinaryWriter.
+ * @param {!proto.ApplicationMetadata} message
+ * @param {!jspb.BinaryWriter} writer
+ * @suppress {unusedLocalVariables} f is only used for nested messages
+ */
+proto.ApplicationMetadata.serializeBinaryToWriter = function(message, writer) {
+  var f = undefined;
+  f = message.getAnswersList();
+  if (f.length > 0) {
+    writer.writeRepeatedString(
+      1,
+      f
+    );
+  }
+};
+
+
+/**
+ * repeated string answers = 1;
+ * @return {!Array<string>}
+ */
+proto.ApplicationMetadata.prototype.getAnswersList = function() {
+  return /** @type {!Array<string>} */ (jspb.Message.getRepeatedField(this, 1));
+};
+
+
+/**
+ * @param {!Array<string>} value
+ * @return {!proto.ApplicationMetadata} returns this
+ */
+proto.ApplicationMetadata.prototype.setAnswersList = function(value) {
+  return jspb.Message.setField(this, 1, value || []);
+};
+
+
+/**
+ * @param {string} value
+ * @param {number=} opt_index
+ * @return {!proto.ApplicationMetadata} returns this
+ */
+proto.ApplicationMetadata.prototype.addAnswers = function(value, opt_index) {
+  return jspb.Message.addToRepeatedField(this, 1, value, opt_index);
+};
+
+
+/**
+ * Clears the list making it empty but non-null.
+ * @return {!proto.ApplicationMetadata} returns this
+ */
+proto.ApplicationMetadata.prototype.clearAnswersList = function() {
+  return this.setAnswersList([]);
+};
+
+
+
+
+
+if (jspb.Message.GENERATE_TO_OBJECT) {
+/**
+ * Creates an object representation of this proto.
+ * Field names that are reserved in JavaScript and will be renamed to pb_name.
+ * Optional fields that are not set will be set to undefined.
+ * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
+ * For the list of reserved names please see:
+ *     net/proto2/compiler/js/internal/generator.cc#kKeyword.
+ * @param {boolean=} opt_includeInstance Deprecated. whether to include the
+ *     JSPB instance for transitional soy proto support:
+ *     http://goto/soy-param-migration
+ * @return {!Object}
+ */
+proto.WorkingGroupStatusMetadata.prototype.toObject = function(opt_includeInstance) {
+  return proto.WorkingGroupStatusMetadata.toObject(opt_includeInstance, this);
+};
+
+
+/**
+ * Static version of the {@see toObject} method.
+ * @param {boolean|undefined} includeInstance Deprecated. Whether to include
+ *     the JSPB instance for transitional soy proto support:
+ *     http://goto/soy-param-migration
+ * @param {!proto.WorkingGroupStatusMetadata} msg The msg instance to transform.
+ * @return {!Object}
+ * @suppress {unusedLocalVariables} f is only used for nested messages
+ */
+proto.WorkingGroupStatusMetadata.toObject = function(includeInstance, msg) {
+  var f, obj = {
+    description: (f = jspb.Message.getField(msg, 1)) == null ? undefined : f,
+    about: (f = jspb.Message.getField(msg, 2)) == null ? undefined : f,
+    status: (f = jspb.Message.getField(msg, 3)) == null ? undefined : f,
+    statusMessage: (f = jspb.Message.getField(msg, 4)) == null ? undefined : f
+  };
+
+  if (includeInstance) {
+    obj.$jspbMessageInstance = msg;
+  }
+  return obj;
+};
+}
+
+
+/**
+ * Deserializes binary data (in protobuf wire format).
+ * @param {jspb.ByteSource} bytes The bytes to deserialize.
+ * @return {!proto.WorkingGroupStatusMetadata}
+ */
+proto.WorkingGroupStatusMetadata.deserializeBinary = function(bytes) {
+  var reader = new jspb.BinaryReader(bytes);
+  var msg = new proto.WorkingGroupStatusMetadata;
+  return proto.WorkingGroupStatusMetadata.deserializeBinaryFromReader(msg, reader);
+};
+
+
+/**
+ * Deserializes binary data (in protobuf wire format) from the
+ * given reader into the given message object.
+ * @param {!proto.WorkingGroupStatusMetadata} msg The message object to deserialize into.
+ * @param {!jspb.BinaryReader} reader The BinaryReader to use.
+ * @return {!proto.WorkingGroupStatusMetadata}
+ */
+proto.WorkingGroupStatusMetadata.deserializeBinaryFromReader = function(msg, reader) {
+  while (reader.nextField()) {
+    if (reader.isEndGroup()) {
+      break;
+    }
+    var field = reader.getFieldNumber();
+    switch (field) {
+    case 1:
+      var value = /** @type {string} */ (reader.readString());
+      msg.setDescription(value);
+      break;
+    case 2:
+      var value = /** @type {string} */ (reader.readString());
+      msg.setAbout(value);
+      break;
+    case 3:
+      var value = /** @type {string} */ (reader.readString());
+      msg.setStatus(value);
+      break;
+    case 4:
+      var value = /** @type {string} */ (reader.readString());
+      msg.setStatusMessage(value);
+      break;
+    default:
+      reader.skipField();
+      break;
+    }
+  }
+  return msg;
+};
+
+
+/**
+ * Serializes the message to binary data (in protobuf wire format).
+ * @return {!Uint8Array}
+ */
+proto.WorkingGroupStatusMetadata.prototype.serializeBinary = function() {
+  var writer = new jspb.BinaryWriter();
+  proto.WorkingGroupStatusMetadata.serializeBinaryToWriter(this, writer);
+  return writer.getResultBuffer();
+};
+
+
+/**
+ * Serializes the given message to binary data (in protobuf wire
+ * format), writing to the given BinaryWriter.
+ * @param {!proto.WorkingGroupStatusMetadata} message
+ * @param {!jspb.BinaryWriter} writer
+ * @suppress {unusedLocalVariables} f is only used for nested messages
+ */
+proto.WorkingGroupStatusMetadata.serializeBinaryToWriter = function(message, writer) {
+  var f = undefined;
+  f = /** @type {string} */ (jspb.Message.getField(message, 1));
+  if (f != null) {
+    writer.writeString(
+      1,
+      f
+    );
+  }
+  f = /** @type {string} */ (jspb.Message.getField(message, 2));
+  if (f != null) {
+    writer.writeString(
+      2,
+      f
+    );
+  }
+  f = /** @type {string} */ (jspb.Message.getField(message, 3));
+  if (f != null) {
+    writer.writeString(
+      3,
+      f
+    );
+  }
+  f = /** @type {string} */ (jspb.Message.getField(message, 4));
+  if (f != null) {
+    writer.writeString(
+      4,
+      f
+    );
+  }
+};
+
+
+/**
+ * optional string description = 1;
+ * @return {string}
+ */
+proto.WorkingGroupStatusMetadata.prototype.getDescription = function() {
+  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
+};
+
+
+/**
+ * @param {string} value
+ * @return {!proto.WorkingGroupStatusMetadata} returns this
+ */
+proto.WorkingGroupStatusMetadata.prototype.setDescription = function(value) {
+  return jspb.Message.setField(this, 1, value);
+};
+
+
+/**
+ * Clears the field making it undefined.
+ * @return {!proto.WorkingGroupStatusMetadata} returns this
+ */
+proto.WorkingGroupStatusMetadata.prototype.clearDescription = function() {
+  return jspb.Message.setField(this, 1, undefined);
+};
+
+
+/**
+ * Returns whether this field is set.
+ * @return {boolean}
+ */
+proto.WorkingGroupStatusMetadata.prototype.hasDescription = function() {
+  return jspb.Message.getField(this, 1) != null;
+};
+
+
+/**
+ * optional string about = 2;
+ * @return {string}
+ */
+proto.WorkingGroupStatusMetadata.prototype.getAbout = function() {
+  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
+};
+
+
+/**
+ * @param {string} value
+ * @return {!proto.WorkingGroupStatusMetadata} returns this
+ */
+proto.WorkingGroupStatusMetadata.prototype.setAbout = function(value) {
+  return jspb.Message.setField(this, 2, value);
+};
+
+
+/**
+ * Clears the field making it undefined.
+ * @return {!proto.WorkingGroupStatusMetadata} returns this
+ */
+proto.WorkingGroupStatusMetadata.prototype.clearAbout = function() {
+  return jspb.Message.setField(this, 2, undefined);
+};
+
+
+/**
+ * Returns whether this field is set.
+ * @return {boolean}
+ */
+proto.WorkingGroupStatusMetadata.prototype.hasAbout = function() {
+  return jspb.Message.getField(this, 2) != null;
+};
+
+
+/**
+ * optional string status = 3;
+ * @return {string}
+ */
+proto.WorkingGroupStatusMetadata.prototype.getStatus = function() {
+  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, ""));
+};
+
+
+/**
+ * @param {string} value
+ * @return {!proto.WorkingGroupStatusMetadata} returns this
+ */
+proto.WorkingGroupStatusMetadata.prototype.setStatus = function(value) {
+  return jspb.Message.setField(this, 3, value);
+};
+
+
+/**
+ * Clears the field making it undefined.
+ * @return {!proto.WorkingGroupStatusMetadata} returns this
+ */
+proto.WorkingGroupStatusMetadata.prototype.clearStatus = function() {
+  return jspb.Message.setField(this, 3, undefined);
+};
+
+
+/**
+ * Returns whether this field is set.
+ * @return {boolean}
+ */
+proto.WorkingGroupStatusMetadata.prototype.hasStatus = function() {
+  return jspb.Message.getField(this, 3) != null;
+};
+
+
+/**
+ * optional string status_message = 4;
+ * @return {string}
+ */
+proto.WorkingGroupStatusMetadata.prototype.getStatusMessage = function() {
+  return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 4, ""));
+};
+
+
+/**
+ * @param {string} value
+ * @return {!proto.WorkingGroupStatusMetadata} returns this
+ */
+proto.WorkingGroupStatusMetadata.prototype.setStatusMessage = function(value) {
+  return jspb.Message.setField(this, 4, value);
+};
+
+
+/**
+ * Clears the field making it undefined.
+ * @return {!proto.WorkingGroupStatusMetadata} returns this
+ */
+proto.WorkingGroupStatusMetadata.prototype.clearStatusMessage = function() {
+  return jspb.Message.setField(this, 4, undefined);
+};
+
+
+/**
+ * Returns whether this field is set.
+ * @return {boolean}
+ */
+proto.WorkingGroupStatusMetadata.prototype.hasStatusMessage = function() {
+  return jspb.Message.getField(this, 4) != null;
+};
+
+
+goog.object.extend(exports, proto);

+ 41 - 0
metadata-protobuf/doc-appendix.md

@@ -0,0 +1,41 @@
+<!-- 
+    This extra documentation will be appended to the generated docs.
+-->
+
+## Referencing Assets
+<a name=".Assets"></a>
+
+Applications that process messages that contain a `uint32` field that references an asset such as a cover photo or video, should interpret this value as a zero based index into an array/vector that is received external (out of band) to the protobuf message.
+
+Example in context of query-node processing the runtime event `VideoCreated`
+
+```rust
+// Runtime event associated with creating a Video
+VideoCreated(video_id: VideoId, video: Video, assets: Vec<NewAsset>, params: VideoCreationParameters)
+
+struct VideoCreationParameters {
+  in_category: VideoCategoryId,
+  // binary serialized VideoMetadata protobuf message
+  meta: Vec<u8>,
+}
+
+// suppose assets is a vector of two elements. This is the "out of band" array being referenced by the VideoMetadata message
+assets = [
+    NewAsset::Uri("https://mydomain.net/thumbnail.png"),
+    NewAsset::Upload({
+       content_id,
+       ipfs_hash,
+       size,
+       ...
+    }),
+];
+
+meta = VideoMetadata {
+    ...
+    // refers to second element: assets[1] which is being uploaded to the storage system
+    video: 1,
+    // refers to the first element assets[0] which is being referneced by a url string.
+    thumbnail_photo: 0,
+    ...
+};
+```

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

@@ -0,0 +1,248 @@
+# Protocol Documentation
+<a name="top"></a>
+
+## Table of Contents
+
+- [proto/Council.proto](#proto/Council.proto)
+    - [CouncilCandidacyNoteMetadata](#.CouncilCandidacyNoteMetadata)
+  
+- [proto/Membership.proto](#proto/Membership.proto)
+    - [MembershipMetadata](#.MembershipMetadata)
+  
+- [proto/WorkingGroups.proto](#proto/WorkingGroups.proto)
+    - [ApplicationMetadata](#.ApplicationMetadata)
+    - [OpeningMetadata](#.OpeningMetadata)
+    - [OpeningMetadata.ApplicationFormQuestion](#.OpeningMetadata.ApplicationFormQuestion)
+    - [WorkingGroupStatusMetadata](#.WorkingGroupStatusMetadata)
+  
+    - [OpeningMetadata.ApplicationFormQuestion.InputType](#.OpeningMetadata.ApplicationFormQuestion.InputType)
+  
+- [Scalar Value Types](#scalar-value-types)
+
+
+
+<a name="proto/Council.proto"></a>
+<p align="right"><a href="#top">Top</a></p>
+
+## proto/Council.proto
+
+
+
+<a name=".CouncilCandidacyNoteMetadata"></a>
+
+### CouncilCandidacyNoteMetadata
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| header | [string](#string) | optional |  |
+| bullet_points | [string](#string) | repeated |  |
+| cover_image | [string](#string) | optional |  |
+| description | [string](#string) | optional |  |
+
+
+
+
+
+ 
+
+ 
+
+ 
+
+ 
+
+
+
+<a name="proto/Membership.proto"></a>
+<p align="right"><a href="#top">Top</a></p>
+
+## proto/Membership.proto
+
+
+
+<a name=".MembershipMetadata"></a>
+
+### MembershipMetadata
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| name | [string](#string) | optional |  |
+| avatar_uri | [string](#string) | optional |  |
+| about | [string](#string) | optional |  |
+
+
+
+
+
+ 
+
+ 
+
+ 
+
+ 
+
+
+
+<a name="proto/WorkingGroups.proto"></a>
+<p align="right"><a href="#top">Top</a></p>
+
+## proto/WorkingGroups.proto
+
+
+
+<a name=".ApplicationMetadata"></a>
+
+### ApplicationMetadata
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| answers | [string](#string) | repeated |  |
+
+
+
+
+
+
+<a name=".OpeningMetadata"></a>
+
+### OpeningMetadata
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| short_description | [string](#string) | required |  |
+| description | [string](#string) | required |  |
+| hiring_limit | [uint32](#uint32) | required |  |
+| expected_duration | [uint32](#uint32) | required |  |
+| application_details | [string](#string) | required |  |
+| application_form_questions | [OpeningMetadata.ApplicationFormQuestion](#OpeningMetadata.ApplicationFormQuestion) | repeated |  |
+
+
+
+
+
+
+<a name=".OpeningMetadata.ApplicationFormQuestion"></a>
+
+### OpeningMetadata.ApplicationFormQuestion
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| question | [string](#string) | required |  |
+| type | [OpeningMetadata.ApplicationFormQuestion.InputType](#OpeningMetadata.ApplicationFormQuestion.InputType) | required |  |
+
+
+
+
+
+
+<a name=".WorkingGroupStatusMetadata"></a>
+
+### WorkingGroupStatusMetadata
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| description | [string](#string) | optional |  |
+| about | [string](#string) | optional |  |
+| status | [string](#string) | optional | Can also be an enum if we only want a limited set |
+| status_message | [string](#string) | optional |  |
+
+
+
+
+
+ 
+
+
+<a name=".OpeningMetadata.ApplicationFormQuestion.InputType"></a>
+
+### OpeningMetadata.ApplicationFormQuestion.InputType
+
+
+| Name | Number | Description |
+| ---- | ------ | ----------- |
+| TEXT | 1 |  |
+| TEXTAREA | 2 |  |
+
+
+ 
+
+ 
+
+ 
+
+
+
+## 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) |
+
+<!-- 
+    This extra documentation will be appended to the generated docs.
+-->
+
+## Referencing Assets
+<a name=".Assets"></a>
+
+Applications that process messages that contain a `uint32` field that references an asset such as a cover photo or video, should interpret this value as a zero based index into an array/vector that is received external (out of band) to the protobuf message.
+
+Example in context of query-node processing the runtime event `VideoCreated`
+
+```rust
+// Runtime event associated with creating a Video
+VideoCreated(video_id: VideoId, video: Video, assets: Vec<NewAsset>, params: VideoCreationParameters)
+
+struct VideoCreationParameters {
+  in_category: VideoCategoryId,
+  // binary serialized VideoMetadata protobuf message
+  meta: Vec<u8>,
+}
+
+// suppose assets is a vector of two elements. This is the "out of band" array being referenced by the VideoMetadata message
+assets = [
+    NewAsset::Uri("https://mydomain.net/thumbnail.png"),
+    NewAsset::Upload({
+       content_id,
+       ipfs_hash,
+       size,
+       ...
+    }),
+];
+
+meta = VideoMetadata {
+    ...
+    // refers to second element: assets[1] which is being uploaded to the storage system
+    video: 1,
+    // refers to the first element assets[0] which is being referneced by a url string.
+    thumbnail_photo: 0,
+    ...
+};
+```

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

@@ -0,0 +1,13 @@
+#!/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
+
+# Append some custom docs to generated protocol docs
+cat doc-appendix.md >> ${OUT_DIR_DOC}/index.md

+ 41 - 0
metadata-protobuf/package.json

@@ -0,0 +1,41 @@
+{
+  "name": "@joystream/metadata-protobuf",
+  "version": "1.0.0",
+  "description": "Joystream Metadata Protobuf Library ",
+  "main": "lib/index.js",
+  "types": "lib/index.d.ts",
+  "repository": "https://github.com/joystream/joystream",
+  "author": "Joystream Contributors",
+  "license": "MIT",
+  "private": false,
+  "scripts": {
+    "build": "./compile.sh && tsc",
+    "compile": "./compile.sh",
+    "generate-doc": "./generate-md-doc.sh",
+    "test": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' mocha -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"
+  },
+  "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",
+    "ts-protoc-gen": "^0.14.0",
+    "typescript": "^4.1.3"
+  }
+}

+ 8 - 0
metadata-protobuf/proto/Council.proto

@@ -0,0 +1,8 @@
+syntax = "proto2";
+
+message CouncilCandidacyNoteMetadata {
+  optional string header = 1;
+  repeated string bullet_points = 2;
+  optional string cover_image = 3;
+  optional string description = 4;
+}

+ 7 - 0
metadata-protobuf/proto/Membership.proto

@@ -0,0 +1,7 @@
+syntax = "proto2";
+
+message MembershipMetadata {
+  optional string name = 1;
+  optional string avatar_uri = 2;
+  optional string about = 3;
+}

+ 29 - 0
metadata-protobuf/proto/WorkingGroups.proto

@@ -0,0 +1,29 @@
+syntax = "proto2";
+
+message OpeningMetadata {
+  required string short_description = 1;
+  required string description = 2;
+  required uint32 hiring_limit = 3;
+  required uint32 expected_duration = 4;
+  required string application_details = 5;
+  message ApplicationFormQuestion {
+    required string question = 1;
+    enum InputType {
+      TEXT = 1;
+      TEXTAREA = 2;
+    }
+    required InputType type = 2;
+  }
+  repeated ApplicationFormQuestion application_form_questions = 6;
+}
+
+message ApplicationMetadata {
+  repeated string answers = 1;
+}
+
+message WorkingGroupStatusMetadata {
+  optional string description = 1;
+  optional string about = 2;
+  optional string status = 3; // Can also be an enum if we only want a limited set
+  optional string status_message = 4;
+}

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

@@ -0,0 +1,4 @@
+// protobuf message constructors
+export * from '../compiled/proto/Council_pb'
+export * from '../compiled/proto/Membership_pb'
+export * from '../compiled/proto/WorkingGroups_pb'

+ 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"]
+}

+ 1 - 0
package.json

@@ -23,6 +23,7 @@
     "pioneer/packages/*",
     "utils/api-scripts",
     "content-directory-schemas",
+    "metadata-protobuf",
     "query-node",
     "query-node/mappings",
     "query-node/generated/*"