GoodMem
ReferenceAPIgRPC API

Extension

Extension service API reference

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 authorization: Bearer <api-key>

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

Permissions model:

  • *_EXTENSION_OWN: operate on caller-owned extensions
  • *_EXTENSION_ANY: operate on any user's extensions (requires elevated role)

Security considerations:

  • Binary JAR content is separated from metadata for security and performance
  • Download operations require separate permissions from metadata access
  • All plugin content is integrity-verified with Murmur3 hashing

CreateExtension

Creates a new Extension by uploading a plugin file.

Type
Requestgoodmem.v1.CreateExtensionRequest
Responsegoodmem.v1.Extension

Auth: gRPC metadata authorization: Bearer <api-key>

Permissions Required: CREATE_EXTENSION_OWN or CREATE_EXTENSION_ANY

Summary:

  • Owner defaults to the authenticated user unless owner_id is provided (requires *_ANY if differs)
  • 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_*
  • 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 'authorization: Bearer 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 authorization: Bearer <api-key>

Permissions Required: READ_EXTENSION_OWN or READ_EXTENSION_ANY

Side Effects: None

Error Codes:

  • UNAUTHENTICATED: missing/invalid auth
  • PERMISSION_DENIED: lacks READ_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 'authorization: Bearer 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 authorization: Bearer <api-key>

Permissions Required: DOWNLOAD_EXTENSION_OWN or DOWNLOAD_EXTENSION_ANY

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_*
  • 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 'authorization: Bearer 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 user.

Type
Requestgoodmem.v1.ListExtensionsRequest
Responsegoodmem.v1.ListExtensionsResponse

Auth: gRPC metadata authorization: Bearer <api-key>

Permissions Required: LIST_EXTENSION_OWN or LIST_EXTENSION_ANY

Request Parameters:

  • owner_id (optional, bytes UUID): filter by owner. If caller has LIST_EXTENSION_ANY and owner_id is omitted, all extensions visible to the role are returned; otherwise only caller-owned extensions are returned
  • name_filter (optional): glob pattern matching on display_name; supports * (any chars), ? (single char), \ (escape); full-string match; case-sensitive
  • Pagination: simple offset-based with opaque pagination tokens
  • Sorting: by created_at descending (newest first)

Note: bytes fields in JSON must be base64.

Side Effects: None

Error Codes:

  • UNAUTHENTICATED: missing/invalid auth
  • PERMISSION_DENIED: lacks 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 'authorization: Bearer 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 authorization: Bearer <api-key>

Permissions Required: DELETE_EXTENSION_OWN or DELETE_EXTENSION_ANY

Side Effects:

  • Removes the extension record and binary JAR content permanently

Error Codes:

  • UNAUTHENTICATED: missing/invalid auth
  • PERMISSION_DENIED: lacks DELETE_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 'authorization: Bearer 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 ID (16 bytes UUID); if omitted → authenticated user; requires CREATE_EXTENSION_ANY if different from caller

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: Reserved message for future pagination token structure.

Current implementation uses simple offset encoding. This message definition is reserved for potential future enhancement to stateful pagination with filter validation. Clients should treat pagination tokens as opaque strings.

FieldTypeDescription
startint32Reserved: cursor offset position
owner_idbytesReserved: owner filter from original request
name_filterstringReserved: name filter pattern from original request
requestor_idbytesReserved: authenticated user ID for token validation
sort_bystringReserved: sort field from original request
sort_ordergoodmem.v1.SortOrderReserved: sort direction from original request

DeleteExtensionRequest

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