Add Phase 2 artifact repository: types, blob store, gRPC service
Build the complete artifact pillar with five packages: - artifacts: Artifact, Snapshot, Citation, Publisher types with Get/Store DB methods, tag/category management, metadata ops, YAML import - blob: content-addressable store (SHA256, hierarchical dir layout) - proto: protobuf definitions (common.proto, artifacts.proto) with buf linting and code generation - server: gRPC ArtifactService implementation (create/get artifacts, store/retrieve blobs, manage tags/categories, search by tag) All FK insertion ordering is correct (parent rows before children). Full test coverage across artifacts, blob, and server packages. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
15
proto/buf.gen.yaml
Normal file
15
proto/buf.gen.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
version: v2
|
||||
|
||||
managed:
|
||||
enabled: true
|
||||
override:
|
||||
- file_option: go_package_prefix
|
||||
value: git.wntrmute.dev/kyle/exo/proto
|
||||
|
||||
plugins:
|
||||
- local: protoc-gen-go
|
||||
out: ../proto
|
||||
opt: paths=source_relative
|
||||
- local: protoc-gen-go-grpc
|
||||
out: ../proto
|
||||
opt: paths=source_relative
|
||||
12
proto/buf.yaml
Normal file
12
proto/buf.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
version: v2
|
||||
|
||||
modules:
|
||||
- path: .
|
||||
|
||||
lint:
|
||||
use:
|
||||
- STANDARD
|
||||
|
||||
breaking:
|
||||
use:
|
||||
- FILE
|
||||
1533
proto/exo/v1/artifacts.pb.go
Normal file
1533
proto/exo/v1/artifacts.pb.go
Normal file
File diff suppressed because it is too large
Load Diff
157
proto/exo/v1/artifacts.proto
Normal file
157
proto/exo/v1/artifacts.proto
Normal file
@@ -0,0 +1,157 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package exo.v1;
|
||||
|
||||
option go_package = "git.wntrmute.dev/kyle/exo/proto/exo/v1;exov1";
|
||||
|
||||
import "exo/v1/common.proto";
|
||||
|
||||
// Publisher represents a publishing entity.
|
||||
message Publisher {
|
||||
string id = 1;
|
||||
string name = 2;
|
||||
string address = 3;
|
||||
}
|
||||
|
||||
// Citation holds bibliographic information.
|
||||
message Citation {
|
||||
string id = 1;
|
||||
string doi = 2;
|
||||
string title = 3;
|
||||
int32 year = 4;
|
||||
string published = 5; // ISO 8601 UTC
|
||||
repeated string authors = 6;
|
||||
Publisher publisher = 7;
|
||||
string source = 8;
|
||||
string abstract = 9;
|
||||
repeated MetadataEntry metadata = 10;
|
||||
}
|
||||
|
||||
// BlobRef is a reference to content in the blob store.
|
||||
message BlobRef {
|
||||
string snapshot_id = 1;
|
||||
string id = 2; // SHA256 hash
|
||||
string format = 3; // MIME type
|
||||
}
|
||||
|
||||
// Snapshot represents content at a specific point in time.
|
||||
message Snapshot {
|
||||
string artifact_id = 1;
|
||||
string id = 2;
|
||||
int64 stored_at = 3;
|
||||
string datetime = 4; // ISO 8601 UTC
|
||||
Citation citation = 5;
|
||||
string source = 6;
|
||||
repeated BlobRef blobs = 7;
|
||||
repeated MetadataEntry metadata = 8;
|
||||
}
|
||||
|
||||
// Artifact is the top-level container for a knowledge source.
|
||||
message Artifact {
|
||||
string id = 1;
|
||||
string type = 2;
|
||||
Citation citation = 3;
|
||||
string latest = 4; // ISO 8601 UTC
|
||||
repeated Snapshot snapshots = 5;
|
||||
repeated string tags = 6;
|
||||
repeated string categories = 7;
|
||||
repeated MetadataEntry metadata = 8;
|
||||
}
|
||||
|
||||
// --- Service messages ---
|
||||
|
||||
message CreateArtifactRequest {
|
||||
Artifact artifact = 1;
|
||||
}
|
||||
|
||||
message CreateArtifactResponse {
|
||||
string id = 1;
|
||||
}
|
||||
|
||||
message GetArtifactRequest {
|
||||
string id = 1;
|
||||
}
|
||||
|
||||
message GetArtifactResponse {
|
||||
Artifact artifact = 1;
|
||||
}
|
||||
|
||||
message DeleteArtifactRequest {
|
||||
string id = 1;
|
||||
}
|
||||
|
||||
message DeleteArtifactResponse {}
|
||||
|
||||
message StoreBlobRequest {
|
||||
string snapshot_id = 1;
|
||||
string format = 2; // MIME type
|
||||
bytes data = 3;
|
||||
}
|
||||
|
||||
message StoreBlobResponse {
|
||||
string id = 1; // SHA256 hash
|
||||
}
|
||||
|
||||
message GetBlobRequest {
|
||||
string id = 1; // SHA256 hash
|
||||
}
|
||||
|
||||
message GetBlobResponse {
|
||||
bytes data = 1;
|
||||
string format = 2;
|
||||
}
|
||||
|
||||
message ListTagsRequest {}
|
||||
|
||||
message ListTagsResponse {
|
||||
repeated string tags = 1;
|
||||
}
|
||||
|
||||
message CreateTagRequest {
|
||||
string tag = 1;
|
||||
}
|
||||
|
||||
message CreateTagResponse {}
|
||||
|
||||
message ListCategoriesRequest {}
|
||||
|
||||
message ListCategoriesResponse {
|
||||
repeated string categories = 1;
|
||||
}
|
||||
|
||||
message CreateCategoryRequest {
|
||||
string category = 1;
|
||||
}
|
||||
|
||||
message CreateCategoryResponse {}
|
||||
|
||||
message SearchByTagRequest {
|
||||
string tag = 1;
|
||||
}
|
||||
|
||||
message SearchByTagResponse {
|
||||
repeated string artifact_ids = 1;
|
||||
}
|
||||
|
||||
// ArtifactService provides CRUD operations for the artifact repository.
|
||||
service ArtifactService {
|
||||
// Artifacts
|
||||
rpc CreateArtifact(CreateArtifactRequest) returns (CreateArtifactResponse);
|
||||
rpc GetArtifact(GetArtifactRequest) returns (GetArtifactResponse);
|
||||
rpc DeleteArtifact(DeleteArtifactRequest) returns (DeleteArtifactResponse);
|
||||
|
||||
// Blobs
|
||||
rpc StoreBlob(StoreBlobRequest) returns (StoreBlobResponse);
|
||||
rpc GetBlob(GetBlobRequest) returns (GetBlobResponse);
|
||||
|
||||
// Tags
|
||||
rpc ListTags(ListTagsRequest) returns (ListTagsResponse);
|
||||
rpc CreateTag(CreateTagRequest) returns (CreateTagResponse);
|
||||
|
||||
// Categories
|
||||
rpc ListCategories(ListCategoriesRequest) returns (ListCategoriesResponse);
|
||||
rpc CreateCategory(CreateCategoryRequest) returns (CreateCategoryResponse);
|
||||
|
||||
// Search
|
||||
rpc SearchByTag(SearchByTagRequest) returns (SearchByTagResponse);
|
||||
}
|
||||
477
proto/exo/v1/artifacts_grpc.pb.go
Normal file
477
proto/exo/v1/artifacts_grpc.pb.go
Normal file
@@ -0,0 +1,477 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.1
|
||||
// - protoc (unknown)
|
||||
// source: exo/v1/artifacts.proto
|
||||
|
||||
package exov1
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.64.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion9
|
||||
|
||||
const (
|
||||
ArtifactService_CreateArtifact_FullMethodName = "/exo.v1.ArtifactService/CreateArtifact"
|
||||
ArtifactService_GetArtifact_FullMethodName = "/exo.v1.ArtifactService/GetArtifact"
|
||||
ArtifactService_DeleteArtifact_FullMethodName = "/exo.v1.ArtifactService/DeleteArtifact"
|
||||
ArtifactService_StoreBlob_FullMethodName = "/exo.v1.ArtifactService/StoreBlob"
|
||||
ArtifactService_GetBlob_FullMethodName = "/exo.v1.ArtifactService/GetBlob"
|
||||
ArtifactService_ListTags_FullMethodName = "/exo.v1.ArtifactService/ListTags"
|
||||
ArtifactService_CreateTag_FullMethodName = "/exo.v1.ArtifactService/CreateTag"
|
||||
ArtifactService_ListCategories_FullMethodName = "/exo.v1.ArtifactService/ListCategories"
|
||||
ArtifactService_CreateCategory_FullMethodName = "/exo.v1.ArtifactService/CreateCategory"
|
||||
ArtifactService_SearchByTag_FullMethodName = "/exo.v1.ArtifactService/SearchByTag"
|
||||
)
|
||||
|
||||
// ArtifactServiceClient is the client API for ArtifactService service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
//
|
||||
// ArtifactService provides CRUD operations for the artifact repository.
|
||||
type ArtifactServiceClient interface {
|
||||
// Artifacts
|
||||
CreateArtifact(ctx context.Context, in *CreateArtifactRequest, opts ...grpc.CallOption) (*CreateArtifactResponse, error)
|
||||
GetArtifact(ctx context.Context, in *GetArtifactRequest, opts ...grpc.CallOption) (*GetArtifactResponse, error)
|
||||
DeleteArtifact(ctx context.Context, in *DeleteArtifactRequest, opts ...grpc.CallOption) (*DeleteArtifactResponse, error)
|
||||
// Blobs
|
||||
StoreBlob(ctx context.Context, in *StoreBlobRequest, opts ...grpc.CallOption) (*StoreBlobResponse, error)
|
||||
GetBlob(ctx context.Context, in *GetBlobRequest, opts ...grpc.CallOption) (*GetBlobResponse, error)
|
||||
// Tags
|
||||
ListTags(ctx context.Context, in *ListTagsRequest, opts ...grpc.CallOption) (*ListTagsResponse, error)
|
||||
CreateTag(ctx context.Context, in *CreateTagRequest, opts ...grpc.CallOption) (*CreateTagResponse, error)
|
||||
// Categories
|
||||
ListCategories(ctx context.Context, in *ListCategoriesRequest, opts ...grpc.CallOption) (*ListCategoriesResponse, error)
|
||||
CreateCategory(ctx context.Context, in *CreateCategoryRequest, opts ...grpc.CallOption) (*CreateCategoryResponse, error)
|
||||
// Search
|
||||
SearchByTag(ctx context.Context, in *SearchByTagRequest, opts ...grpc.CallOption) (*SearchByTagResponse, error)
|
||||
}
|
||||
|
||||
type artifactServiceClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewArtifactServiceClient(cc grpc.ClientConnInterface) ArtifactServiceClient {
|
||||
return &artifactServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *artifactServiceClient) CreateArtifact(ctx context.Context, in *CreateArtifactRequest, opts ...grpc.CallOption) (*CreateArtifactResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(CreateArtifactResponse)
|
||||
err := c.cc.Invoke(ctx, ArtifactService_CreateArtifact_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *artifactServiceClient) GetArtifact(ctx context.Context, in *GetArtifactRequest, opts ...grpc.CallOption) (*GetArtifactResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(GetArtifactResponse)
|
||||
err := c.cc.Invoke(ctx, ArtifactService_GetArtifact_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *artifactServiceClient) DeleteArtifact(ctx context.Context, in *DeleteArtifactRequest, opts ...grpc.CallOption) (*DeleteArtifactResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(DeleteArtifactResponse)
|
||||
err := c.cc.Invoke(ctx, ArtifactService_DeleteArtifact_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *artifactServiceClient) StoreBlob(ctx context.Context, in *StoreBlobRequest, opts ...grpc.CallOption) (*StoreBlobResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(StoreBlobResponse)
|
||||
err := c.cc.Invoke(ctx, ArtifactService_StoreBlob_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *artifactServiceClient) GetBlob(ctx context.Context, in *GetBlobRequest, opts ...grpc.CallOption) (*GetBlobResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(GetBlobResponse)
|
||||
err := c.cc.Invoke(ctx, ArtifactService_GetBlob_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *artifactServiceClient) ListTags(ctx context.Context, in *ListTagsRequest, opts ...grpc.CallOption) (*ListTagsResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListTagsResponse)
|
||||
err := c.cc.Invoke(ctx, ArtifactService_ListTags_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *artifactServiceClient) CreateTag(ctx context.Context, in *CreateTagRequest, opts ...grpc.CallOption) (*CreateTagResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(CreateTagResponse)
|
||||
err := c.cc.Invoke(ctx, ArtifactService_CreateTag_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *artifactServiceClient) ListCategories(ctx context.Context, in *ListCategoriesRequest, opts ...grpc.CallOption) (*ListCategoriesResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListCategoriesResponse)
|
||||
err := c.cc.Invoke(ctx, ArtifactService_ListCategories_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *artifactServiceClient) CreateCategory(ctx context.Context, in *CreateCategoryRequest, opts ...grpc.CallOption) (*CreateCategoryResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(CreateCategoryResponse)
|
||||
err := c.cc.Invoke(ctx, ArtifactService_CreateCategory_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *artifactServiceClient) SearchByTag(ctx context.Context, in *SearchByTagRequest, opts ...grpc.CallOption) (*SearchByTagResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(SearchByTagResponse)
|
||||
err := c.cc.Invoke(ctx, ArtifactService_SearchByTag_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ArtifactServiceServer is the server API for ArtifactService service.
|
||||
// All implementations must embed UnimplementedArtifactServiceServer
|
||||
// for forward compatibility.
|
||||
//
|
||||
// ArtifactService provides CRUD operations for the artifact repository.
|
||||
type ArtifactServiceServer interface {
|
||||
// Artifacts
|
||||
CreateArtifact(context.Context, *CreateArtifactRequest) (*CreateArtifactResponse, error)
|
||||
GetArtifact(context.Context, *GetArtifactRequest) (*GetArtifactResponse, error)
|
||||
DeleteArtifact(context.Context, *DeleteArtifactRequest) (*DeleteArtifactResponse, error)
|
||||
// Blobs
|
||||
StoreBlob(context.Context, *StoreBlobRequest) (*StoreBlobResponse, error)
|
||||
GetBlob(context.Context, *GetBlobRequest) (*GetBlobResponse, error)
|
||||
// Tags
|
||||
ListTags(context.Context, *ListTagsRequest) (*ListTagsResponse, error)
|
||||
CreateTag(context.Context, *CreateTagRequest) (*CreateTagResponse, error)
|
||||
// Categories
|
||||
ListCategories(context.Context, *ListCategoriesRequest) (*ListCategoriesResponse, error)
|
||||
CreateCategory(context.Context, *CreateCategoryRequest) (*CreateCategoryResponse, error)
|
||||
// Search
|
||||
SearchByTag(context.Context, *SearchByTagRequest) (*SearchByTagResponse, error)
|
||||
mustEmbedUnimplementedArtifactServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedArtifactServiceServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedArtifactServiceServer struct{}
|
||||
|
||||
func (UnimplementedArtifactServiceServer) CreateArtifact(context.Context, *CreateArtifactRequest) (*CreateArtifactResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method CreateArtifact not implemented")
|
||||
}
|
||||
func (UnimplementedArtifactServiceServer) GetArtifact(context.Context, *GetArtifactRequest) (*GetArtifactResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method GetArtifact not implemented")
|
||||
}
|
||||
func (UnimplementedArtifactServiceServer) DeleteArtifact(context.Context, *DeleteArtifactRequest) (*DeleteArtifactResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method DeleteArtifact not implemented")
|
||||
}
|
||||
func (UnimplementedArtifactServiceServer) StoreBlob(context.Context, *StoreBlobRequest) (*StoreBlobResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method StoreBlob not implemented")
|
||||
}
|
||||
func (UnimplementedArtifactServiceServer) GetBlob(context.Context, *GetBlobRequest) (*GetBlobResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method GetBlob not implemented")
|
||||
}
|
||||
func (UnimplementedArtifactServiceServer) ListTags(context.Context, *ListTagsRequest) (*ListTagsResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method ListTags not implemented")
|
||||
}
|
||||
func (UnimplementedArtifactServiceServer) CreateTag(context.Context, *CreateTagRequest) (*CreateTagResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method CreateTag not implemented")
|
||||
}
|
||||
func (UnimplementedArtifactServiceServer) ListCategories(context.Context, *ListCategoriesRequest) (*ListCategoriesResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method ListCategories not implemented")
|
||||
}
|
||||
func (UnimplementedArtifactServiceServer) CreateCategory(context.Context, *CreateCategoryRequest) (*CreateCategoryResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method CreateCategory not implemented")
|
||||
}
|
||||
func (UnimplementedArtifactServiceServer) SearchByTag(context.Context, *SearchByTagRequest) (*SearchByTagResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method SearchByTag not implemented")
|
||||
}
|
||||
func (UnimplementedArtifactServiceServer) mustEmbedUnimplementedArtifactServiceServer() {}
|
||||
func (UnimplementedArtifactServiceServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeArtifactServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to ArtifactServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeArtifactServiceServer interface {
|
||||
mustEmbedUnimplementedArtifactServiceServer()
|
||||
}
|
||||
|
||||
func RegisterArtifactServiceServer(s grpc.ServiceRegistrar, srv ArtifactServiceServer) {
|
||||
// If the following call panics, it indicates UnimplementedArtifactServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&ArtifactService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _ArtifactService_CreateArtifact_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CreateArtifactRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ArtifactServiceServer).CreateArtifact(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ArtifactService_CreateArtifact_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ArtifactServiceServer).CreateArtifact(ctx, req.(*CreateArtifactRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ArtifactService_GetArtifact_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetArtifactRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ArtifactServiceServer).GetArtifact(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ArtifactService_GetArtifact_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ArtifactServiceServer).GetArtifact(ctx, req.(*GetArtifactRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ArtifactService_DeleteArtifact_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(DeleteArtifactRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ArtifactServiceServer).DeleteArtifact(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ArtifactService_DeleteArtifact_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ArtifactServiceServer).DeleteArtifact(ctx, req.(*DeleteArtifactRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ArtifactService_StoreBlob_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(StoreBlobRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ArtifactServiceServer).StoreBlob(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ArtifactService_StoreBlob_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ArtifactServiceServer).StoreBlob(ctx, req.(*StoreBlobRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ArtifactService_GetBlob_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetBlobRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ArtifactServiceServer).GetBlob(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ArtifactService_GetBlob_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ArtifactServiceServer).GetBlob(ctx, req.(*GetBlobRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ArtifactService_ListTags_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListTagsRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ArtifactServiceServer).ListTags(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ArtifactService_ListTags_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ArtifactServiceServer).ListTags(ctx, req.(*ListTagsRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ArtifactService_CreateTag_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CreateTagRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ArtifactServiceServer).CreateTag(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ArtifactService_CreateTag_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ArtifactServiceServer).CreateTag(ctx, req.(*CreateTagRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ArtifactService_ListCategories_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListCategoriesRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ArtifactServiceServer).ListCategories(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ArtifactService_ListCategories_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ArtifactServiceServer).ListCategories(ctx, req.(*ListCategoriesRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ArtifactService_CreateCategory_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CreateCategoryRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ArtifactServiceServer).CreateCategory(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ArtifactService_CreateCategory_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ArtifactServiceServer).CreateCategory(ctx, req.(*CreateCategoryRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ArtifactService_SearchByTag_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SearchByTagRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ArtifactServiceServer).SearchByTag(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ArtifactService_SearchByTag_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ArtifactServiceServer).SearchByTag(ctx, req.(*SearchByTagRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// ArtifactService_ServiceDesc is the grpc.ServiceDesc for ArtifactService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var ArtifactService_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "exo.v1.ArtifactService",
|
||||
HandlerType: (*ArtifactServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "CreateArtifact",
|
||||
Handler: _ArtifactService_CreateArtifact_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetArtifact",
|
||||
Handler: _ArtifactService_GetArtifact_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "DeleteArtifact",
|
||||
Handler: _ArtifactService_DeleteArtifact_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "StoreBlob",
|
||||
Handler: _ArtifactService_StoreBlob_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetBlob",
|
||||
Handler: _ArtifactService_GetBlob_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListTags",
|
||||
Handler: _ArtifactService_ListTags_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "CreateTag",
|
||||
Handler: _ArtifactService_CreateTag_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListCategories",
|
||||
Handler: _ArtifactService_ListCategories_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "CreateCategory",
|
||||
Handler: _ArtifactService_CreateCategory_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "SearchByTag",
|
||||
Handler: _ArtifactService_SearchByTag_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "exo/v1/artifacts.proto",
|
||||
}
|
||||
297
proto/exo/v1/common.pb.go
Normal file
297
proto/exo/v1/common.pb.go
Normal file
@@ -0,0 +1,297 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc (unknown)
|
||||
// source: exo/v1/common.proto
|
||||
|
||||
package exov1
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// Value is a typed key-value entry.
|
||||
type Value struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Contents string `protobuf:"bytes,1,opt,name=contents,proto3" json:"contents,omitempty"`
|
||||
Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *Value) Reset() {
|
||||
*x = Value{}
|
||||
mi := &file_exo_v1_common_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Value) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Value) ProtoMessage() {}
|
||||
|
||||
func (x *Value) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_exo_v1_common_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Value.ProtoReflect.Descriptor instead.
|
||||
func (*Value) Descriptor() ([]byte, []int) {
|
||||
return file_exo_v1_common_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *Value) GetContents() string {
|
||||
if x != nil {
|
||||
return x.Contents
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Value) GetType() string {
|
||||
if x != nil {
|
||||
return x.Type
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// MetadataEntry is a single key-value metadata pair.
|
||||
type MetadataEntry struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
||||
Value *Value `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *MetadataEntry) Reset() {
|
||||
*x = MetadataEntry{}
|
||||
mi := &file_exo_v1_common_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *MetadataEntry) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*MetadataEntry) ProtoMessage() {}
|
||||
|
||||
func (x *MetadataEntry) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_exo_v1_common_proto_msgTypes[1]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use MetadataEntry.ProtoReflect.Descriptor instead.
|
||||
func (*MetadataEntry) Descriptor() ([]byte, []int) {
|
||||
return file_exo_v1_common_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *MetadataEntry) GetKey() string {
|
||||
if x != nil {
|
||||
return x.Key
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *MetadataEntry) GetValue() *Value {
|
||||
if x != nil {
|
||||
return x.Value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Header is attached to every persistent object.
|
||||
type Header struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
|
||||
Created int64 `protobuf:"varint,3,opt,name=created,proto3" json:"created,omitempty"`
|
||||
Modified int64 `protobuf:"varint,4,opt,name=modified,proto3" json:"modified,omitempty"`
|
||||
Categories []string `protobuf:"bytes,5,rep,name=categories,proto3" json:"categories,omitempty"`
|
||||
Tags []string `protobuf:"bytes,6,rep,name=tags,proto3" json:"tags,omitempty"`
|
||||
Metadata []*MetadataEntry `protobuf:"bytes,7,rep,name=metadata,proto3" json:"metadata,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *Header) Reset() {
|
||||
*x = Header{}
|
||||
mi := &file_exo_v1_common_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Header) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Header) ProtoMessage() {}
|
||||
|
||||
func (x *Header) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_exo_v1_common_proto_msgTypes[2]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Header.ProtoReflect.Descriptor instead.
|
||||
func (*Header) Descriptor() ([]byte, []int) {
|
||||
return file_exo_v1_common_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *Header) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Header) GetType() string {
|
||||
if x != nil {
|
||||
return x.Type
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Header) GetCreated() int64 {
|
||||
if x != nil {
|
||||
return x.Created
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Header) GetModified() int64 {
|
||||
if x != nil {
|
||||
return x.Modified
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Header) GetCategories() []string {
|
||||
if x != nil {
|
||||
return x.Categories
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Header) GetTags() []string {
|
||||
if x != nil {
|
||||
return x.Tags
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Header) GetMetadata() []*MetadataEntry {
|
||||
if x != nil {
|
||||
return x.Metadata
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_exo_v1_common_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_exo_v1_common_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\x13exo/v1/common.proto\x12\x06exo.v1\"7\n" +
|
||||
"\x05Value\x12\x1a\n" +
|
||||
"\bcontents\x18\x01 \x01(\tR\bcontents\x12\x12\n" +
|
||||
"\x04type\x18\x02 \x01(\tR\x04type\"F\n" +
|
||||
"\rMetadataEntry\x12\x10\n" +
|
||||
"\x03key\x18\x01 \x01(\tR\x03key\x12#\n" +
|
||||
"\x05value\x18\x02 \x01(\v2\r.exo.v1.ValueR\x05value\"\xc9\x01\n" +
|
||||
"\x06Header\x12\x0e\n" +
|
||||
"\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" +
|
||||
"\x04type\x18\x02 \x01(\tR\x04type\x12\x18\n" +
|
||||
"\acreated\x18\x03 \x01(\x03R\acreated\x12\x1a\n" +
|
||||
"\bmodified\x18\x04 \x01(\x03R\bmodified\x12\x1e\n" +
|
||||
"\n" +
|
||||
"categories\x18\x05 \x03(\tR\n" +
|
||||
"categories\x12\x12\n" +
|
||||
"\x04tags\x18\x06 \x03(\tR\x04tags\x121\n" +
|
||||
"\bmetadata\x18\a \x03(\v2\x15.exo.v1.MetadataEntryR\bmetadataB\x80\x01\n" +
|
||||
"\n" +
|
||||
"com.exo.v1B\vCommonProtoP\x01Z,git.wntrmute.dev/kyle/exo/proto/exo/v1;exov1\xa2\x02\x03EXX\xaa\x02\x06Exo.V1\xca\x02\x06Exo\\V1\xe2\x02\x12Exo\\V1\\GPBMetadata\xea\x02\aExo::V1b\x06proto3"
|
||||
|
||||
var (
|
||||
file_exo_v1_common_proto_rawDescOnce sync.Once
|
||||
file_exo_v1_common_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_exo_v1_common_proto_rawDescGZIP() []byte {
|
||||
file_exo_v1_common_proto_rawDescOnce.Do(func() {
|
||||
file_exo_v1_common_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_exo_v1_common_proto_rawDesc), len(file_exo_v1_common_proto_rawDesc)))
|
||||
})
|
||||
return file_exo_v1_common_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_exo_v1_common_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
||||
var file_exo_v1_common_proto_goTypes = []any{
|
||||
(*Value)(nil), // 0: exo.v1.Value
|
||||
(*MetadataEntry)(nil), // 1: exo.v1.MetadataEntry
|
||||
(*Header)(nil), // 2: exo.v1.Header
|
||||
}
|
||||
var file_exo_v1_common_proto_depIdxs = []int32{
|
||||
0, // 0: exo.v1.MetadataEntry.value:type_name -> exo.v1.Value
|
||||
1, // 1: exo.v1.Header.metadata:type_name -> exo.v1.MetadataEntry
|
||||
2, // [2:2] is the sub-list for method output_type
|
||||
2, // [2:2] is the sub-list for method input_type
|
||||
2, // [2:2] is the sub-list for extension type_name
|
||||
2, // [2:2] is the sub-list for extension extendee
|
||||
0, // [0:2] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_exo_v1_common_proto_init() }
|
||||
func file_exo_v1_common_proto_init() {
|
||||
if File_exo_v1_common_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_exo_v1_common_proto_rawDesc), len(file_exo_v1_common_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 3,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_exo_v1_common_proto_goTypes,
|
||||
DependencyIndexes: file_exo_v1_common_proto_depIdxs,
|
||||
MessageInfos: file_exo_v1_common_proto_msgTypes,
|
||||
}.Build()
|
||||
File_exo_v1_common_proto = out.File
|
||||
file_exo_v1_common_proto_goTypes = nil
|
||||
file_exo_v1_common_proto_depIdxs = nil
|
||||
}
|
||||
28
proto/exo/v1/common.proto
Normal file
28
proto/exo/v1/common.proto
Normal file
@@ -0,0 +1,28 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package exo.v1;
|
||||
|
||||
option go_package = "git.wntrmute.dev/kyle/exo/proto/exo/v1;exov1";
|
||||
|
||||
// Value is a typed key-value entry.
|
||||
message Value {
|
||||
string contents = 1;
|
||||
string type = 2;
|
||||
}
|
||||
|
||||
// MetadataEntry is a single key-value metadata pair.
|
||||
message MetadataEntry {
|
||||
string key = 1;
|
||||
Value value = 2;
|
||||
}
|
||||
|
||||
// Header is attached to every persistent object.
|
||||
message Header {
|
||||
string id = 1;
|
||||
string type = 2;
|
||||
int64 created = 3;
|
||||
int64 modified = 4;
|
||||
repeated string categories = 5;
|
||||
repeated string tags = 6;
|
||||
repeated MetadataEntry metadata = 7;
|
||||
}
|
||||
Reference in New Issue
Block a user