GoodMemGoodMem
ReferenceAPIgRPC API

Extension

gRPC ExtensionService reference for CreateExtension, GetExtension, DownloadExtension, ListExtensions and other RPCs, with request messages, response types, and service documentation.

Services

ExtensionService Service

Service for managing Extensions in the GoodMem system.

Extensions are JAR-based plugins that enhance GoodMem functionality with post-processors and custom logic components. This service provides lifecycle management including upload, download, metadata retrieval, listing, and deletion operations.

Authentication: gRPC metadata x-api-key: <api-key>

Global errors: All RPCs may return DEADLINE_EXCEEDED, CANCELLED, UNAVAILABLE, RESOURCE_EXHAUSTED, INTERNAL.

Authorization model:

  • Every RPC evaluates a typed authorization operation against the GoodMem instance or a particular extension.
  • ROOT and ADMIN receive extension-management authority by default; the standard USER role receives none, because uploaded JARs execute inside the server process. An administrator may delegate individual extension operations through direct authorization grants.
  • Ownership, code-defined role assignments, and direct grants can supply authority; an API-key ceiling may further restrict the authenticated principal's effective authority.
  • Listing requires LIST_EXTENSION on the instance and returns only extensions on which the caller has READ_EXTENSION.

Security considerations:

  • Binary JAR content is separated from metadata for security and performance
  • Download operations require separate permissions from metadata access
  • Murmur3 hashing detects accidental corruption only; it is not a signature and does not establish that plugin code is trusted

CreateExtension

Creates a new Extension by uploading a plugin file.

Type
Requestgoodmem.v1.CreateExtensionRequest
Responsegoodmem.v1.Extension

Auth: gRPC metadata x-api-key: <api-key>

Authorization Required: CREATE_EXTENSION on the proposed extension, evaluated using its proposed owner.

Summary:

  • Owner defaults to the authenticated principal unless owner_id is provided; authorization is evaluated against that proposed owner
  • ALREADY_EXISTS: another extension exists with identical {owner_id, extension_type, display_name} combination
  • Calculates Murmur3 32-bit x86 hash (8-char lowercase hex, seed=0) for corruption detection
  • Sets default status to "ACTIVE" and media_type to "application/java-archive" if not provided

Side Effects:

  • Persists extension with binary content; sets audit fields

Error Codes:

  • UNAUTHENTICATED: missing/invalid auth
  • PERMISSION_DENIED: lacks CREATE_EXTENSION on the proposed extension
  • INVALID_ARGUMENT: empty/invalid fields; unsupported extension_type; empty plugin_content; file size exceeds server limits
  • ALREADY_EXISTS: matching extension as defined above
  • INTERNAL: unexpected server error

Idempotency: Non-idempotent; clients SHOULD NOT blindly retry on unknown failures.

Examples:

grpcurl -plaintext \
-H 'x-api-key: gm_xxx' \
-d '{
"display_name": "Custom Processor",
"extension_type": "JAVA_PROCESSOR",
"filename": "my-processor.jar",
"plugin_content": "BASE64_JAR_CONTENT_HERE"
}' \
localhost:8080 goodmem.v1.ExtensionService/CreateExtension

Note: bytes fields in JSON must be base64.

GetExtension

Retrieves metadata of a specific Extension (without plugin content).

Type
Requestgoodmem.v1.GetExtensionRequest
Responsegoodmem.v1.Extension

Auth: gRPC metadata x-api-key: <api-key>

Authorization Required: READ_EXTENSION on the requested extension.

Side Effects: None

Error Codes:

  • UNAUTHENTICATED: missing/invalid auth
  • PERMISSION_DENIED: lacks READ_EXTENSION on the requested extension
  • INVALID_ARGUMENT: invalid extension ID format
  • NOT_FOUND: extension does not exist
  • INTERNAL: unexpected server error

Idempotency: Read-only; safe to retry; results may change over time.

Examples:

grpcurl -plaintext \
-H 'x-api-key: gm_xxx' \
-d '{ "extension_id": "BASE64_UUID_BYTES_HERE" }' \
localhost:8080 goodmem.v1.ExtensionService/GetExtension

Note: bytes fields in JSON must be base64.

DownloadExtension

Downloads the plugin content of a specific Extension.

Type
Requestgoodmem.v1.DownloadExtensionRequest
Responsegoodmem.v1.DownloadExtensionResponse

Auth: gRPC metadata x-api-key: <api-key>

Authorization Required: DOWNLOAD_EXTENSION on the requested extension.

Security:

  • Returns binary JAR content with integrity hash for verification
  • Separate download permission required from metadata access
  • Download permissions are independent of extension status (ACTIVE/INACTIVE/DISABLED)
  • This allows downloading for debugging/forensic purposes even when extensions are disabled

Side Effects: None

Error Codes:

  • UNAUTHENTICATED: missing/invalid auth
  • PERMISSION_DENIED: lacks DOWNLOAD_EXTENSION on the requested extension
  • INVALID_ARGUMENT: invalid extension ID format
  • NOT_FOUND: extension does not exist
  • INTERNAL: unexpected server error

Idempotency: Read-only; safe to retry; content is immutable.

Examples:

grpcurl -plaintext \
-H 'x-api-key: gm_xxx' \
-d '{ "extension_id": "BASE64_UUID_BYTES_HERE" }' \
localhost:8080 goodmem.v1.ExtensionService/DownloadExtension

Note: bytes fields in JSON must be base64.

ListExtensions

Lists Extensions accessible to the authenticated principal.

Type
Requestgoodmem.v1.ListExtensionsRequest
Responsegoodmem.v1.ListExtensionsResponse

Auth: gRPC metadata x-api-key: <api-key>

Authorization Required: LIST_EXTENSION on the GoodMem instance and READ_EXTENSION on each returned extension; results include only extensions the caller may read.

Request Parameters:

  • owner_id (optional, bytes UUID): filter the already-authorized result set by owner
  • name_filter (optional): glob pattern matching on display_name; supports * (any chars), ? (single char), \ (escape); full-string match; case-sensitive
  • Pagination: opaque tokens bind the offset, authenticated principal, owner/name filters, and the fixed sort contract. A malformed token or one reused with a different principal or explicit filter returns INVALID_ARGUMENT.
  • Sorting: by created_at descending (newest first), then extension_id descending

Note: bytes fields in JSON must be base64.

Side Effects: None

Error Codes:

  • UNAUTHENTICATED: missing/invalid auth
  • PERMISSION_DENIED: lacks instance-level LIST_EXTENSION
  • INVALID_ARGUMENT: invalid filters or parameters
  • INTERNAL: unexpected server error

Idempotency: Read-only; safe to retry; results may change over time.

Examples:

grpcurl -plaintext \
-H 'x-api-key: gm_xxx' \
-d '{ "name_filter": "processor*", "max_results": 10 }' \
localhost:8080 goodmem.v1.ExtensionService/ListExtensions

DeleteExtension

Permanently deletes an Extension and its binary content.

Type
Requestgoodmem.v1.DeleteExtensionRequest
Responsegoogle.protobuf.Empty

Auth: gRPC metadata x-api-key: <api-key>

Authorization Required: DELETE_EXTENSION on the requested extension.

Side Effects:

  • Removes the extension record and binary JAR content permanently

Error Codes:

  • UNAUTHENTICATED: missing/invalid auth
  • PERMISSION_DENIED: lacks DELETE_EXTENSION on the requested extension
  • INVALID_ARGUMENT: invalid extension ID format
  • NOT_FOUND: extension does not exist
  • INTERNAL: unexpected server error

Idempotency: Safe to retry; may return NOT_FOUND if already deleted or never existed.

Examples:

grpcurl -plaintext \
-H 'x-api-key: gm_xxx' \
-d '{ "extension_id": "BASE64_UUID_BYTES_HERE" }' \
localhost:8080 goodmem.v1.ExtensionService/DeleteExtension

Note: bytes fields in JSON must be base64.

Messages

Extension

Represents a plugin (JAR file) that extends GoodMem functionality.

Extensions are JAR files containing post-processors, custom logic, or other plugin implementations that integrate with the GoodMem system. Each extension has metadata, security constraints, and lifecycle management through admin-controlled status transitions.

Security:

  • plugin_content (binary JAR data) is intentionally excluded from this message for security and performance reasons. Use DownloadExtension to retrieve binary content.

Immutability:

  • extension_type is effectively immutable (no update operations supported).
  • owner_id is set at creation and cannot be modified.

Duplicate Prevention:

  • System prevents duplicate extensions with identical {owner_id, extension_type, display_name}.
  • display_name comparison is case-sensitive after leading/trailing whitespace trimming (no Unicode normalization applied).

Notes:

  • All timestamps are UTC (google.protobuf.Timestamp).
  • Murmur3 32-bit hash provides corruption detection for JAR content (not cryptographically secure).

See also: ExtensionService for management operations

FieldTypeDescription
extension_idbytesOUTPUT_ONLY UUID (16 bytes); immutable primary identifier
display_namestringREQUIRED on create; ≤255 chars; leading/trailing whitespace trimmed; cannot be empty
descriptionstringOPTIONAL description of extension functionality
extension_typestringREQUIRED extension type string; current valid values: "JAVA_PROCESSOR"
filenamestringREQUIRED original filename of uploaded JAR; ≤255 UTF-8 bytes; cannot be empty after trimming; no path separators or control characters
media_typestringOUTPUT_ONLY MIME type; always non-empty; defaults to "application/java-archive" if not provided at create
file_sizeint64OUTPUT_ONLY size in bytes of JAR content; set during creation
file_hashstringOUTPUT_ONLY Murmur3 32-bit x86 hash (8-char lowercase hex, seed=0) for corruption detection only (not cryptographically secure); calculated during creation
statusstringOUTPUT_ONLY lifecycle status; valid values: "ACTIVE", "INACTIVE", "DISABLED"; defaults to "ACTIVE"; admin-controlled via tooling only (no RPC for status changes); typical transitions: ACTIVE↔INACTIVE, →DISABLED
owner_idbytesOUTPUT_ONLY owner UUID (16 bytes); set at create; not updatable
created_atgoogle.protobuf.TimestampStandard audit fields
OUTPUT_ONLY
updated_atgoogle.protobuf.TimestampOUTPUT_ONLY
created_by_idbytesOUTPUT_ONLY creator UUID (16 bytes)
updated_by_idbytesOUTPUT_ONLY last updater UUID (16 bytes)

CreateExtensionRequest

FieldTypeDescription
extension_idbytesOptional client-provided UUID (16 bytes); server generates if omitted; returns ALREADY_EXISTS if ID exists
display_namestringRequired: User-facing name (≤255 chars; leading/trailing whitespace trimmed; cannot be empty)
descriptionstringOptional description of extension functionality
extension_typestringRequired: Extension type string; current valid values: "JAVA_PROCESSOR"
filenamestringRequired: Original filename (≤255 UTF-8 bytes; cannot be empty after trimming; no path separators or control characters)
media_typestringOptional: MIME type (lowercased); empty defaults to "application/java-archive"; must be valid IANA type if provided
plugin_contentbytesRequired: Binary JAR file content (cannot be empty; subject to server configuration, default limit 100MB)
owner_idbytesOptional owner principal UUID (16 bytes); if omitted → authenticated principal; CREATE_EXTENSION is evaluated using this proposed owner

GetExtensionRequest

FieldTypeDescription
extension_idbytesRequired: Extension ID (16 bytes UUID)

DownloadExtensionRequest

FieldTypeDescription
extension_idbytesRequired: Extension ID (16 bytes UUID)

DownloadExtensionResponse

FieldTypeDescription
filenamestringOriginal filename of the JAR file
media_typestringMIME type (e.g., "application/java-archive")
file_sizeint64Size in bytes of `plugin_content`
file_hashstringMurmur3 32-bit x86 hash (8-char lowercase hex, seed=0) for corruption detection only (not cryptographically secure)
plugin_contentbytesBinary JAR file content

ListExtensionsRequest

FieldTypeDescription
owner_idbytesOptional filters
Optional: Filter by owner (16 bytes UUID)
name_filterstringOptional: Glob pattern for display_name matching; supports * (any chars), ? (single char), \ (escape); full-string match; case-sensitive
max_resultsint32Pagination
Optional: Max results per page; defaults to 50 if not provided or ≤0
next_tokenstringOptional: Opaque pagination token; do not parse
sort_bystringSorting (parameters currently ignored by implementation)
Optional: Sort field name; IGNORED - implementation always sorts by "created_at"
sort_ordergoodmem.v1.SortOrderOptional: Sort direction; IGNORED - implementation always uses DESCENDING

ListExtensionsResponse

FieldTypeDescription
extensionsgoodmem.v1.ExtensionPage of extension results (metadata only, no binary content)
next_tokenstringOpaque token for next page; omitted on final page

ListExtensionsNextPageToken

INTERNAL: State carried by an opaque ListExtensions pagination token.

The server validates the requestor, filters, and fixed sort contract before using start. Clients must not construct or inspect this message; they should return the encoded token exactly as received. max_results is intentionally excluded so callers may change page size between pages.

FieldTypeDescription
startint32Required positive offset for the next page
owner_idbytesEffective owner filter from the first page
name_filterstringEffective name glob from the first page
requestor_idbytesAuthenticated principal UUID (16 bytes)
sort_bystringFixed server sort field (`created_at`)
sort_ordergoodmem.v1.SortOrderFixed server sort direction (`DESCENDING`)
secondary_sort_bystringStable tie-breaker field (`extension_id`)
secondary_sort_ordergoodmem.v1.SortOrderTie-breaker direction (`DESCENDING`)

DeleteExtensionRequest

FieldTypeDescription
extension_idbytesRequired: Extension ID to delete (16 bytes UUID)