From 1f8af08b0fc8b75e05db6dc9b86205b9300351cb Mon Sep 17 00:00:00 2001 From: lwargin-circle Date: Thu, 16 Apr 2026 15:39:02 +0200 Subject: [PATCH 01/11] fix: preserve include_stream_metadata when QuickNode API omits it on read-after-update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When updating a quicknode_stream resource, the provider calls readStreamFromAPI (a GET) after the PATCH to refresh computed fields. For certain stream types the QuickNode API does not include include_stream_metadata in the GET response. Because readStreamFromAPI initialised a blank StreamResourceModel{} and only populated fields that were present in the response, the field was left as null. The Update function then assigned that null back to the plan, causing Terraform to report "Provider produced inconsistent result after apply" for every affected stream — even when the field itself was not part of the change. Fix: add an optional fallback parameter to readStreamFromAPI. When the API response omits include_stream_metadata, the fallback (plan) value is preserved instead of letting the field become null. All existing callers are unaffected (no fallback passed). The Update caller now passes &plan so any API-omitted field retains its planned value. Co-Authored-By: Claude Sonnet 4.6 --- internal/provider/stream_resource.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/internal/provider/stream_resource.go b/internal/provider/stream_resource.go index c7ac885..063b130 100644 --- a/internal/provider/stream_resource.go +++ b/internal/provider/stream_resource.go @@ -563,7 +563,10 @@ func getPostgresAttributes(destAttrs map[string]interface{}) (*streams.PostgresA } // readStreamFromAPI reads stream data from the API and updates the provided StreamResourceModel. -func (r *StreamResource) readStreamFromAPI(ctx context.Context, streamID string) (*StreamResourceModel, error) { +// An optional fallback model can be provided; fields absent from the API response will retain +// their values from the fallback instead of becoming null. This guards against providers returning +// inconsistent results when the QuickNode API omits a field that was set before the update. +func (r *StreamResource) readStreamFromAPI(ctx context.Context, streamID string, fallback ...*StreamResourceModel) (*StreamResourceModel, error) { readResp, err := r.client.FindOneWithResponse(ctx, streamID) if err != nil { return nil, fmt.Errorf("error reading stream: %w", err) @@ -616,6 +619,10 @@ func (r *StreamResource) readStreamFromAPI(ctx context.Context, streamID string) } if includeStreamMetadata, ok := result["include_stream_metadata"].(string); ok { data.IncludeStreamMetadata = types.StringValue(includeStreamMetadata) + } else if len(fallback) > 0 && fallback[0] != nil && !fallback[0].IncludeStreamMetadata.IsNull() { + // QuickNode API did not return include_stream_metadata in this response. + // Preserve the fallback (plan/state) value to avoid a provider inconsistency error. + data.IncludeStreamMetadata = fallback[0].IncludeStreamMetadata } if destination, ok := result["destination"].(string); ok { data.Destination = types.StringValue(destination) @@ -1154,8 +1161,11 @@ func (r *StreamResource) Update(ctx context.Context, req resource.UpdateRequest, }) } - // Read full stream data from API to get computed fields - fullStreamData, err := r.readStreamFromAPI(ctx, streamId) + // Read full stream data from API to get computed fields. + // Pass the current plan as fallback so that fields the QuickNode API may omit from the + // GET response (e.g. include_stream_metadata) are preserved rather than set to null, + // which would otherwise trigger a "provider produced inconsistent result" Terraform error. + fullStreamData, err := r.readStreamFromAPI(ctx, streamId, &plan) if err != nil { resp.Diagnostics.AddError("Error reading stream after update", err.Error()) return From 88dbea6b3769eb42ebac8b93e5fb131f5f73947f Mon Sep 17 00:00:00 2001 From: lwargin-circle Date: Thu, 16 Apr 2026 15:41:00 +0200 Subject: [PATCH 02/11] fix: preserve include_stream_metadata in Read() when API omits it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The QuickNode GET /streams/:id endpoint no longer returns include_stream_metadata in its response (confirmed via curl; field also removed from official API docs). This caused two separate issues: 1. Read() — on every terraform plan/apply the field was read back as null from the API, overwriting the known state value and triggering a phantom diff that would attempt a no-op update on every cycle. 2. Update() — after a successful PATCH the provider refreshed state via the same GET call; the null field was then assigned to the plan, causing Terraform to fail with "Provider produced inconsistent result after apply". Fix: pass the current state (Read) or current plan (Update) as a fallback to readStreamFromAPI so that any field absent from the API response is preserved from the known-good value rather than silently becoming null. All other callers (Create, pre-update status check) remain unchanged. Co-Authored-By: Claude Sonnet 4.6 --- internal/provider/stream_resource.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/internal/provider/stream_resource.go b/internal/provider/stream_resource.go index 063b130..2d23d08 100644 --- a/internal/provider/stream_resource.go +++ b/internal/provider/stream_resource.go @@ -884,8 +884,11 @@ func (r *StreamResource) Read(ctx context.Context, req resource.ReadRequest, res return } - // Read stream data from API - streamData, err := r.readStreamFromAPI(ctx, data.Id.ValueString()) + // Read stream data from API. + // Pass the current state as fallback so that fields the QuickNode API no longer returns + // in GET responses (e.g. include_stream_metadata) are preserved from state rather than + // becoming null, which would otherwise cause phantom diffs on every plan/apply cycle. + streamData, err := r.readStreamFromAPI(ctx, data.Id.ValueString(), &data) if err != nil { if strings.Contains(err.Error(), "stream not found") { resp.State.RemoveResource(ctx) From abe17dab1f86ead8f62a436031d30dc407265630 Mon Sep 17 00:00:00 2001 From: lwargin-circle Date: Thu, 16 Apr 2026 15:51:44 +0200 Subject: [PATCH 03/11] fix: remove include_stream_metadata after QuickNode API breaking change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QuickNode silently removed include_stream_metadata from their Streams API: - No longer returned in GET /streams/:id responses (confirmed via curl) - No longer accepted in POST/PATCH request bodies (removed from live OpenAPI spec) - No longer documented in the official API docs This caused two Terraform failures for any stream that was updated: 1. "Provider produced inconsistent result after apply" — after a PATCH the provider called GET to refresh state; the absent field left a null in the freshly initialised model, overwriting the planned value of "header". 2. Phantom diffs — every terraform plan overwrote the state value with null, queuing a spurious update on every cycle. Changes in this commit: - Update vendored streams-openapi.json from the live QuickNode API endpoint (make vendor: curl https://api.quicknode.com/streams/rest/openapi.json) - Regenerate streams.gen.go — IncludeStreamMetadata removed from CreateStreamDto and UpdateStreamDto generated types - Remove IncludeStreamMetadata from Create and Update API request bodies in stream_resource.go (field no longer in API contract) - Mark schema field include_stream_metadata as Optional + deprecated so that existing configurations continue to parse without error while users migrate away from the field - Preserve fallback in readStreamFromAPI (Read + Update) so that existing state values are not silently nullified by the absent GET response field Co-Authored-By: Claude Sonnet 4.6 --- api/streams/streams-openapi.json | 1068 +------------------------- api/streams/streams.gen.go | 361 ++++++++- internal/provider/stream_resource.go | 17 +- 3 files changed, 338 insertions(+), 1108 deletions(-) diff --git a/api/streams/streams-openapi.json b/api/streams/streams-openapi.json index 438b422..aa221ce 100644 --- a/api/streams/streams-openapi.json +++ b/api/streams/streams-openapi.json @@ -1,1067 +1 @@ -{ - "openapi": "3.0.0", - "paths": { - "/streams/rest/v1/streams": { - "post": { - "operationId": "create", - "summary": "Create a new stream", - "parameters": [], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateStreamDto" - } - } - } - }, - "responses": { - "201": { - "description": "" - } - }, - "tags": [ - "Streams" - ], - "security": [ - { - "x-api-key": [] - } - ] - }, - "get": { - "operationId": "findAll", - "summary": "Retrieve all streams", - "parameters": [ - { - "name": "limit", - "required": true, - "in": "query", - "schema": { - "default": 20, - "type": "number" - } - }, - { - "name": "offset", - "required": true, - "in": "query", - "schema": { - "default": 0, - "type": "number" - } - } - ], - "responses": { - "200": { - "description": "" - } - }, - "tags": [ - "Streams" - ], - "security": [ - { - "x-api-key": [] - } - ] - }, - "delete": { - "operationId": "removeStreamsByAccountId", - "summary": "Remove all streams", - "parameters": [], - "responses": { - "200": { - "description": "" - } - }, - "tags": [ - "Streams" - ], - "security": [ - { - "x-api-key": [] - } - ] - } - }, - "/streams/rest/v1/streams/{id}": { - "patch": { - "operationId": "update", - "summary": "Update a stream", - "parameters": [ - { - "name": "id", - "required": true, - "in": "path", - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateStreamDto" - } - } - } - }, - "responses": { - "200": { - "description": "" - } - }, - "tags": [ - "Streams" - ], - "security": [ - { - "x-api-key": [] - } - ] - }, - "get": { - "operationId": "findOne", - "summary": "Retrieve a stream by ID", - "parameters": [ - { - "name": "id", - "required": true, - "in": "path", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "" - } - }, - "tags": [ - "Streams" - ], - "security": [ - { - "x-api-key": [] - } - ] - }, - "delete": { - "operationId": "remove", - "summary": "Remove a stream by ID", - "parameters": [ - { - "name": "id", - "required": true, - "in": "path", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "" - } - }, - "tags": [ - "Streams" - ], - "security": [ - { - "x-api-key": [] - } - ] - } - }, - "/streams/rest/v1/streams/test_filter": { - "post": { - "operationId": "testFilterFunction", - "summary": "Test a filter", - "parameters": [], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TestFilterFunctionDto" - } - } - } - }, - "responses": { - "201": { - "description": "" - } - }, - "tags": [ - "Streams" - ], - "security": [ - { - "x-api-key": [] - } - ] - } - }, - "/streams/rest/v1/streams/{id}/pause": { - "post": { - "operationId": "pauseStream", - "summary": "Pause stream", - "parameters": [ - { - "name": "id", - "required": true, - "in": "path", - "schema": { - "type": "string" - } - } - ], - "responses": { - "201": { - "description": "" - } - }, - "tags": [ - "Streams" - ], - "security": [ - { - "x-api-key": [] - } - ] - } - }, - "/streams/rest/v1/streams/{id}/activate": { - "post": { - "operationId": "activateStream", - "summary": "Activate stream", - "parameters": [ - { - "name": "id", - "required": true, - "in": "path", - "schema": { - "type": "string" - } - } - ], - "responses": { - "201": { - "description": "" - } - }, - "tags": [ - "Streams" - ], - "security": [ - { - "x-api-key": [] - } - ] - } - }, - "/streams/rest/v1/streams/enabled_count": { - "get": { - "operationId": "getEnabledStreams", - "summary": "Retrieve enable streams", - "parameters": [], - "responses": { - "200": { - "description": "" - } - }, - "tags": [ - "Streams" - ], - "security": [ - { - "x-api-key": [] - } - ] - } - } - }, - "info": { - "title": "Streams REST API", - "description": "", - "version": "1.0", - "contact": {} - }, - "tags": [ - { - "name": "Streams", - "description": "" - } - ], - "servers": [], - "components": { - "securitySchemes": { - "x-api-key": { - "type": "apiKey", - "in": "header", - "name": "x-api-key" - } - }, - "schemas": { - "S3Attributes": { - "type": "object", - "properties": { - "endpoint": { - "type": "string" - }, - "access_key": { - "type": "string" - }, - "secret_key": { - "type": "string" - }, - "bucket": { - "type": "string" - }, - "object_prefix": { - "type": "string" - }, - "file_compression": { - "type": "string" - }, - "file_type": { - "type": "string", - "enum": [ - ".json", - ".parquet" - ], - "example": ".json" - }, - "max_retry": { - "type": "number" - }, - "retry_interval_sec": { - "type": "number" - }, - "use_ssl": { - "type": "boolean" - } - }, - "required": [ - "endpoint", - "access_key", - "secret_key", - "bucket", - "object_prefix", - "file_compression", - "file_type", - "max_retry", - "retry_interval_sec", - "use_ssl" - ] - }, - "WebhookAttributes": { - "type": "object", - "properties": { - "url": { - "type": "string" - }, - "security_token": { - "type": "string" - }, - "compression": { - "type": "string" - }, - "headers": { - "type": "object" - }, - "max_retry": { - "type": "number" - }, - "retry_interval_sec": { - "type": "number" - }, - "post_timeout_sec": { - "type": "number" - } - }, - "required": [ - "url", - "security_token", - "compression", - "headers", - "max_retry", - "retry_interval_sec", - "post_timeout_sec" - ] - }, - "PostgresAttributes": { - "type": "object", - "properties": { - "username": { - "type": "string" - }, - "password": { - "type": "string" - }, - "host": { - "type": "string" - }, - "port": { - "type": "number" - }, - "database": { - "type": "string" - }, - "access_key": { - "type": "string" - }, - "sslmode": { - "type": "string", - "enum": [ - "disable", - "require" - ] - }, - "table_name": { - "type": "string" - }, - "max_retry": { - "type": "number" - }, - "retry_interval_sec": { - "type": "number" - } - }, - "required": [ - "username", - "password", - "host", - "port", - "database", - "access_key", - "sslmode", - "table_name", - "max_retry", - "retry_interval_sec" - ] - }, - "QuickfunctionsAttributes": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "namespace": { - "type": "string" - }, - "headers": { - "type": "object" - }, - "max_retry": { - "type": "number" - }, - "retry_interval_sec": { - "type": "number" - }, - "post_timeout_sec": { - "type": "number" - }, - "security_token": { - "type": "string" - } - }, - "required": [ - "name", - "namespace", - "headers", - "max_retry", - "retry_interval_sec", - "post_timeout_sec", - "security_token" - ] - }, - "AzureAttributes": { - "type": "object", - "properties": { - "storage_account": { - "type": "string" - }, - "container": { - "type": "string" - }, - "sas_token": { - "type": "string" - }, - "blob_prefix": { - "type": "string" - }, - "file_compression_type": { - "type": "string" - }, - "file_type": { - "type": "string", - "enum": [ - ".json", - ".parquet" - ] - }, - "max_retry": { - "type": "number" - }, - "retry_interval_sec": { - "type": "number" - } - }, - "required": [ - "storage_account", - "container", - "blob_prefix", - "file_compression_type", - "file_type", - "max_retry", - "retry_interval_sec" - ] - }, - "CreateStreamDto": { - "type": "object", - "properties": { - "name": { - "type": "string", - "example": "My Stream" - }, - "network": { - "type": "string", - "enum": [ - "abstract-mainnet", - "abstract-testnet", - "arbitrum-mainnet", - "arbitrum-sepolia", - "arc-testnet", - "avalanche-fuji", - "avalanche-mainnet", - "b3-mainnet", - "b3-sepolia", - "base-mainnet", - "base-sepolia", - "bera-mainnet", - "bera-bepolia", - "bch-mainnet", - "bch-testnet", - "bitcoin-mainnet", - "bitcoin-testnet4", - "blast-mainnet", - "blast-sepolia", - "bnbchain-mainnet", - "bnbchain-testnet", - "celo-mainnet", - "cyber-mainnet", - "cyber-sepolia", - "doge-mainnet", - "ethereum-hoodi", - "ethereum-mainnet", - "ethereum-sepolia", - "fantom-mainnet", - "flare-mainnet", - "flare-testnet", - "flow-mainnet", - "flow-testnet", - "fraxtal-mainnet", - "gnosis-mainnet", - "gravity-alpham", - "hemi-mainnet", - "hemi-testnet", - "hyperevm-mainnet", - "hypercore-mainnet", - "imx-mainnet", - "imx-testnet", - "injective-mainnet", - "injective-testnet", - "ink-mainnet", - "ink-sepolia", - "joc-mainnet", - "kaia-mainnet", - "kaia-testnet", - "katana-mainnet", - "lens-mainnet", - "lens-testnet", - "linea-mainnet", - "lisk-mainnet", - "litecoin-mainnet", - "litecoin-testnet", - "mantle-mainnet", - "mantle-sepolia", - "mode-mainnet", - "monad-mainnet", - "monad-testnet", - "morph-hoodi", - "morph-mainnet", - "nova-mainnet", - "omni-mainnet", - "omni-omega", - "optimism-mainnet", - "optimism-sepolia", - "peaq-mainnet", - "plasma-testnet", - "plasma-mainnet", - "polygon-amoy", - "polygon-mainnet", - "redstone-mainnet", - "sahara-testnet", - "scroll-mainnet", - "scroll-testnet", - "sei-mainnet", - "sei-testnet", - "solana-devnet", - "solana-mainnet", - "solana-testnet", - "soneium-mainnet", - "sonic-mainnet", - "sophon-mainnet", - "sophon-testnet", - "stellar-mainnet", - "stellar-testnet", - "story-aeneid", - "story-mainnet", - "tron-mainnet", - "unichain-mainnet", - "unichain-sepolia", - "vana-mainnet", - "vana-moksha", - "worldchain-mainnet", - "worldchain-sepolia", - "xai-mainnet", - "xai-sepolia", - "xlayer-mainnet", - "xrp-mainnet", - "xrp-testnet", - "xrplevm-mainnet", - "xrplevm-testnet", - "zerog-galileo", - "zerog-mainnet", - "zkevm-cardona", - "zkevm-mainnet", - "zksync-mainnet", - "zksync-sepolia", - "zora-mainnet" - ], - "example": "ethereum-mainnet" - }, - "dataset": { - "type": "string", - "enum": [ - "block", - "block_with_receipts", - "receipts", - "logs", - "transactions", - "trace_blocks", - "debug_traces", - "block_with_receipts_debug_trace", - "block_with_receipts_trace_block", - "programs_with_logs", - "ledger", - "events", - "orders", - "trades", - "book_updates", - "twap", - "writer_actions" - ], - "example": "block" - }, - "filter_function": { - "type": "string", - "example": "dHJ5IHsKICAgIHZhciBkYXRhID0gSlNPTi5wYXJzZShzdHJlYW1EYXRhKTsKICAgIC8vIENvbnZlcnQgaGV4IG51bWJlciB0byBkZWNpbWFsCiAgICB2YXIgbnVtYmVyRGVjaW1hbCA9IHBhcnNlSW50KGRhdGEubnVtYmVyLCAxNik7CiAgICB2YXIgZmlsdGVyZWREYXRhID0ge2hhc2g6IGRhdGEuaGFzaCwgbnVtYmVyOiBudW1iZXJEZWNpbWFsfTsKICAgIEpTT04uc3RyaW5naWZ5KGZpbHRlcmVkRGF0YSk7Cn0gY2F0Y2ggKGUpIHsKICAgIEpTT04uc3RyaW5naWZ5KHtlcnJvcjogZS5tZXNzYWdlfSk7Cn0K", - "description": "JS/ECMAScript compliant filter encoded in base64", - "format": "base64" - }, - "region": { - "type": "string", - "enum": [ - "usa_east", - "europe_central", - "asia_east" - ], - "example": "usa_east" - }, - "start_range": { - "type": "integer", - "example": 100, - "description": "Stream start at block number. If not provided, the stream will start at the latest block." - }, - "end_range": { - "type": "integer", - "example": 200, - "description": "Stream until block number" - }, - "dataset_batch_size": { - "type": "number", - "example": 1 - }, - "elastic_batch_enabled": { - "type": "boolean", - "example": true - }, - "include_stream_metadata": { - "type": "string", - "enum": [ - "body", - "header", - "none" - ], - "example": "body" - }, - "destination": { - "type": "string", - "enum": [ - "webhook", - "s3", - "azure", - "function", - "postgres" - ], - "example": "webhook" - }, - "fix_block_reorgs": { - "type": "number", - "example": 0, - "description": "Fix block reorgs by streaming correct blocks: 1. Ignore reorgs: 0" - }, - "keep_distance_from_tip": { - "type": "number", - "example": 0, - "description": "Stay away from tip by N blocks" - }, - "notification_email": { - "type": "string", - "example": "contact@example.com", - "description": "Notify when stream is terminated" - }, - "destination_attributes": { - "oneOf": [ - { - "$ref": "#/components/schemas/S3Attributes" - }, - { - "$ref": "#/components/schemas/WebhookAttributes" - }, - { - "$ref": "#/components/schemas/QuickfunctionsAttributes" - }, - { - "$ref": "#/components/schemas/PostgresAttributes" - }, - { - "$ref": "#/components/schemas/AzureAttributes" - } - ], - "example": { - "url": "http://localhost:8080/test", - "security_token": "sample-security-token", - "compression": "none", - "headers": { - "Content-Type": "Test", - "Authorization": "again" - }, - "max_retry": 3, - "retry_interval_sec": 1, - "post_timeout_sec": 10 - } - }, - "status": { - "type": "string", - "enum": [ - "active", - "paused" - ], - "example": "active" - } - }, - "required": [ - "name", - "network", - "dataset", - "filter_function", - "region", - "dataset_batch_size", - "elastic_batch_enabled", - "include_stream_metadata", - "destination", - "destination_attributes", - "status" - ] - }, - "UpdateStreamDto": { - "type": "object", - "properties": { - "name": { - "type": "string", - "example": "My Stream" - }, - "filter_function": { - "type": "string", - "example": "dHJ5IHsKICAgIHZhciBkYXRhID0gSlNPTi5wYXJzZShzdHJlYW1EYXRhKTsKICAgIC8vIENvbnZlcnQgaGV4IG51bWJlciB0byBkZWNpbWFsCiAgICB2YXIgbnVtYmVyRGVjaW1hbCA9IHBhcnNlSW50KGRhdGEubnVtYmVyLCAxNik7CiAgICB2YXIgZmlsdGVyZWREYXRhID0ge2hhc2g6IGRhdGEuaGFzaCwgbnVtYmVyOiBudW1iZXJEZWNpbWFsfTsKICAgIEpTT04uc3RyaW5naWZ5KGZpbHRlcmVkRGF0YSk7Cn0gY2F0Y2ggKGUpIHsKICAgIEpTT04uc3RyaW5naWZ5KHtlcnJvcjogZS5tZXNzYWdlfSk7Cn0K", - "description": "JS/ECMAScript compliant filter encoded in base64", - "format": "base64" - }, - "start_range": { - "type": "integer", - "example": 100, - "description": "Stream start at block number. If not provided, the stream will start at the latest block." - }, - "end_range": { - "type": "integer", - "example": 200, - "description": "Stream until block number" - }, - "dataset_batch_size": { - "type": "number", - "example": 1 - }, - "elastic_batch_enabled": { - "type": "boolean", - "example": true - }, - "include_stream_metadata": { - "type": "string", - "enum": [ - "body", - "header", - "none" - ], - "example": "body" - }, - "destination": { - "type": "string", - "enum": [ - "webhook", - "s3", - "azure", - "function", - "postgres" - ], - "example": "webhook" - }, - "fix_block_reorgs": { - "type": "number", - "example": 0, - "description": "Fix block reorgs by streaming correct blocks: 1. Ignore reorgs: 0" - }, - "keep_distance_from_tip": { - "type": "number", - "example": 0, - "description": "Stay away from tip by N blocks" - }, - "notification_email": { - "type": "string", - "example": "contact@example.com", - "description": "Notify when stream is terminated" - }, - "destination_attributes": { - "oneOf": [ - { - "$ref": "#/components/schemas/S3Attributes" - }, - { - "$ref": "#/components/schemas/WebhookAttributes" - }, - { - "$ref": "#/components/schemas/QuickfunctionsAttributes" - }, - { - "$ref": "#/components/schemas/PostgresAttributes" - }, - { - "$ref": "#/components/schemas/AzureAttributes" - } - ], - "example": { - "url": "http://localhost:8080/test", - "security_token": "sample-security-token", - "compression": "none", - "headers": { - "Content-Type": "Test", - "Authorization": "again" - }, - "max_retry": 3, - "retry_interval_sec": 1, - "post_timeout_sec": 10 - } - }, - "status": { - "type": "string", - "enum": [ - "active", - "paused" - ], - "example": "active" - } - } - }, - "TestFilterFunctionDto": { - "type": "object", - "properties": { - "network": { - "type": "string", - "enum": [ - "abstract-mainnet", - "abstract-testnet", - "arbitrum-mainnet", - "arbitrum-sepolia", - "arc-testnet", - "avalanche-fuji", - "avalanche-mainnet", - "b3-mainnet", - "b3-sepolia", - "base-mainnet", - "base-sepolia", - "bera-mainnet", - "bera-bepolia", - "bch-mainnet", - "bch-testnet", - "bitcoin-mainnet", - "bitcoin-testnet4", - "blast-mainnet", - "blast-sepolia", - "bnbchain-mainnet", - "bnbchain-testnet", - "celo-mainnet", - "cyber-mainnet", - "cyber-sepolia", - "doge-mainnet", - "ethereum-hoodi", - "ethereum-mainnet", - "ethereum-sepolia", - "fantom-mainnet", - "flare-mainnet", - "flare-testnet", - "flow-mainnet", - "flow-testnet", - "fraxtal-mainnet", - "gnosis-mainnet", - "gravity-alpham", - "hemi-mainnet", - "hemi-testnet", - "hyperevm-mainnet", - "hypercore-mainnet", - "imx-mainnet", - "imx-testnet", - "injective-mainnet", - "injective-testnet", - "ink-mainnet", - "ink-sepolia", - "joc-mainnet", - "kaia-mainnet", - "kaia-testnet", - "katana-mainnet", - "lens-mainnet", - "lens-testnet", - "linea-mainnet", - "lisk-mainnet", - "litecoin-mainnet", - "litecoin-testnet", - "mantle-mainnet", - "mantle-sepolia", - "mode-mainnet", - "monad-mainnet", - "monad-testnet", - "morph-hoodi", - "morph-mainnet", - "nova-mainnet", - "omni-mainnet", - "omni-omega", - "optimism-mainnet", - "optimism-sepolia", - "peaq-mainnet", - "plasma-testnet", - "plasma-mainnet", - "polygon-amoy", - "polygon-mainnet", - "redstone-mainnet", - "sahara-testnet", - "scroll-mainnet", - "scroll-testnet", - "sei-mainnet", - "sei-testnet", - "solana-devnet", - "solana-mainnet", - "solana-testnet", - "soneium-mainnet", - "sonic-mainnet", - "sophon-mainnet", - "sophon-testnet", - "stellar-mainnet", - "stellar-testnet", - "story-aeneid", - "story-mainnet", - "tron-mainnet", - "unichain-mainnet", - "unichain-sepolia", - "vana-mainnet", - "vana-moksha", - "worldchain-mainnet", - "worldchain-sepolia", - "xai-mainnet", - "xai-sepolia", - "xlayer-mainnet", - "xrp-mainnet", - "xrp-testnet", - "xrplevm-mainnet", - "xrplevm-testnet", - "zerog-galileo", - "zerog-mainnet", - "zkevm-cardona", - "zkevm-mainnet", - "zksync-mainnet", - "zksync-sepolia", - "zora-mainnet" - ], - "example": "ethereum-mainnet" - }, - "block": { - "type": "string", - "example": "17811625" - }, - "dataset": { - "type": "string", - "enum": [ - "block", - "block_with_receipts", - "receipts", - "logs", - "transactions", - "trace_blocks", - "debug_traces", - "block_with_receipts_debug_trace", - "block_with_receipts_trace_block", - "programs_with_logs", - "ledger", - "events", - "orders", - "trades", - "book_updates", - "twap", - "writer_actions" - ], - "example": "block" - }, - "filter_function": { - "type": "string", - "example": "ZnVuY3Rpb24gbWFpbihzdHJlYW0pIHsKICAvLyBJZiBzdHJlYW0gaXMgY29uZmlndXJlZCB3aXRoIG1ldGFkYXRhIGluIHRoZSBib2R5LCB0aGUgZGF0YSBtYXkgYmUgbmVzdGVkIHVuZGVyICJkYXRhIiBrZXkKICBjb25zdCBkYXRhID0gc3RyZWFtLmRhdGEgPyBzdHJlYW0uZGF0YSA6IHN0cmVhbTsKCiAgcmV0dXJuIGRhdGE7Cn0=", - "description": "JS/ECMAScript compliant filter encoded in base64", - "format": "base64" - } - }, - "required": [ - "network", - "block", - "dataset", - "filter_function" - ] - } - } - } -} +{"openapi":"3.0.0","paths":{"/streams/rest/v1/streams":{"post":{"operationId":"create","summary":"Create a new stream","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateStreamDto"}}}},"responses":{"201":{"description":""}},"tags":["Streams"],"security":[{"x-api-key":[]}]},"get":{"operationId":"findAll","summary":"Retrieve all streams","parameters":[{"name":"limit","required":true,"in":"query","schema":{"default":20,"type":"number"}},{"name":"offset","required":true,"in":"query","schema":{"default":0,"type":"number"}}],"responses":{"200":{"description":""}},"tags":["Streams"],"security":[{"x-api-key":[]}]},"delete":{"operationId":"removeStreamsByAccountId","summary":"Remove all streams","parameters":[],"responses":{"200":{"description":""}},"tags":["Streams"],"security":[{"x-api-key":[]}]}},"/streams/rest/v1/streams/{id}":{"patch":{"operationId":"update","summary":"Update a stream","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateStreamDto"}}}},"responses":{"200":{"description":""}},"tags":["Streams"],"security":[{"x-api-key":[]}]},"get":{"operationId":"findOne","summary":"Retrieve a stream by ID","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Streams"],"security":[{"x-api-key":[]}]},"delete":{"operationId":"remove","summary":"Remove a stream by ID","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Streams"],"security":[{"x-api-key":[]}]}},"/streams/rest/v1/streams/test_filter":{"post":{"operationId":"testFilterFunction","summary":"Test a filter","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestFilterFunctionDto"}}}},"responses":{"201":{"description":""}},"tags":["Streams"],"security":[{"x-api-key":[]}]}},"/streams/rest/v1/streams/{id}/pause":{"post":{"operationId":"pauseStream","summary":"Pause stream","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"tags":["Streams"],"security":[{"x-api-key":[]}]}},"/streams/rest/v1/streams/{id}/activate":{"post":{"operationId":"activateStream","summary":"Activate stream","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"tags":["Streams"],"security":[{"x-api-key":[]}]}},"/streams/rest/v1/streams/enabled_count":{"get":{"operationId":"getEnabledStreams","summary":"Retrieve enable streams","parameters":[],"responses":{"200":{"description":""}},"tags":["Streams"],"security":[{"x-api-key":[]}]}}},"info":{"title":"Streams REST API","description":"","version":"1.0","contact":{}},"tags":[{"name":"Streams","description":""}],"servers":[],"components":{"securitySchemes":{"x-api-key":{"type":"apiKey","in":"header","name":"x-api-key"}},"schemas":{"S3Attributes":{"type":"object","properties":{"endpoint":{"type":"string"},"access_key":{"type":"string"},"secret_key":{"type":"string"},"bucket":{"type":"string"},"object_prefix":{"type":"string"},"file_compression":{"type":"string"},"file_type":{"type":"string","enum":[".json",".parquet"],"example":".json"},"max_retry":{"type":"number"},"retry_interval_sec":{"type":"number"},"use_ssl":{"type":"boolean"}},"required":["endpoint","access_key","secret_key","bucket","object_prefix","file_compression","file_type","max_retry","retry_interval_sec","use_ssl"]},"WebhookAttributes":{"type":"object","properties":{"url":{"type":"string"},"security_token":{"type":"string"},"compression":{"type":"string"},"headers":{"type":"object"},"max_retry":{"type":"number"},"retry_interval_sec":{"type":"number"},"post_timeout_sec":{"type":"number"}},"required":["url","security_token","compression","headers","max_retry","retry_interval_sec","post_timeout_sec"]},"PostgresAttributes":{"type":"object","properties":{"username":{"type":"string"},"password":{"type":"string"},"host":{"type":"string"},"port":{"type":"number"},"database":{"type":"string"},"access_key":{"type":"string"},"sslmode":{"type":"string","enum":["disable","require"]},"table_name":{"type":"string"},"max_retry":{"type":"number"},"retry_interval_sec":{"type":"number"}},"required":["username","password","host","port","database","access_key","sslmode","table_name","max_retry","retry_interval_sec"]},"QuickfunctionsAttributes":{"type":"object","properties":{"name":{"type":"string"},"namespace":{"type":"string"},"headers":{"type":"object"},"max_retry":{"type":"number"},"retry_interval_sec":{"type":"number"},"post_timeout_sec":{"type":"number"},"security_token":{"type":"string"}},"required":["name","namespace","headers","max_retry","retry_interval_sec","post_timeout_sec","security_token"]},"AzureAttributes":{"type":"object","properties":{"storage_account":{"type":"string"},"container":{"type":"string"},"sas_token":{"type":"string"},"blob_prefix":{"type":"string"},"file_compression_type":{"type":"string"},"file_type":{"type":"string","enum":[".json",".parquet"]},"max_retry":{"type":"number"},"retry_interval_sec":{"type":"number"}},"required":["storage_account","container","blob_prefix","file_compression_type","file_type","max_retry","retry_interval_sec"]},"KafkaAttributes":{"type":"object","properties":{"bootstrap_servers":{"type":"string"},"topic_name":{"type":"string"},"username":{"type":"string"},"password":{"type":"string"},"mechanisms":{"type":"string","enum":["PLAIN","GSSAPI","SCRAM-SHA-256","SCRAM-SHA-512","OAUTHBEARER"]},"protocol":{"type":"string","enum":["plaintext","ssl","sasl_ssl","sasl_plaintext"]},"compression_type":{"type":"string","enum":["none","gzip","snappy","lz4","zstd"]},"batch_size":{"type":"number"},"linger_ms":{"type":"number"},"max_message_bytes":{"type":"number"},"timeout_sec":{"type":"number"},"max_retry":{"type":"number"},"retry_interval_sec":{"type":"number"},"ssl_ca_pem":{"type":"string"},"ssl_certificate_pem":{"type":"string"},"ssl_key_pem":{"type":"string"}},"required":["bootstrap_servers","topic_name","compression_type","batch_size","linger_ms","max_message_bytes","timeout_sec","max_retry","retry_interval_sec"]},"ExtraDestinationDto":{"type":"object","properties":{"destination":{"type":"string","enum":["webhook","s3","azure","function","postgres","kafka"],"example":"webhook"},"destination_attributes":{"oneOf":[{"$ref":"#/components/schemas/S3Attributes"},{"$ref":"#/components/schemas/WebhookAttributes"},{"$ref":"#/components/schemas/QuickfunctionsAttributes"},{"$ref":"#/components/schemas/PostgresAttributes"},{"$ref":"#/components/schemas/AzureAttributes"},{"$ref":"#/components/schemas/KafkaAttributes"}],"example":{"url":"http://localhost:8080/test","security_token":"sample-security-token","compression":"none","headers":{},"max_retry":3,"retry_interval_sec":1,"post_timeout_sec":10}}},"required":["destination","destination_attributes"]},"CreateStreamDto":{"type":"object","properties":{"name":{"type":"string","example":"My Stream"},"network":{"type":"string","enum":["abstract-mainnet","abstract-testnet","arbitrum-mainnet","arbitrum-sepolia","arc-testnet","avalanche-fuji","avalanche-mainnet","b3-mainnet","b3-sepolia","base-mainnet","base-sepolia","bera-mainnet","bera-bepolia","bch-mainnet","bch-testnet","bitcoin-mainnet","bitcoin-testnet4","blast-mainnet","blast-sepolia","bnbchain-mainnet","bnbchain-testnet","celo-mainnet","cyber-mainnet","cyber-sepolia","doge-mainnet","ethereum-hoodi","ethereum-mainnet","ethereum-sepolia","fantom-mainnet","flare-mainnet","flare-testnet","flow-mainnet","flow-testnet","fraxtal-mainnet","gnosis-mainnet","gravity-alpham","hedera-mainnet","hedera-testnet","hemi-mainnet","hemi-testnet","hyperevm-mainnet","hyperevm-testnet","hypercore-mainnet","imx-mainnet","imx-testnet","injective-mainnet","injective-testnet","ink-mainnet","ink-sepolia","joc-mainnet","kaia-mainnet","kaia-testnet","katana-mainnet","lens-mainnet","lens-testnet","linea-mainnet","lisk-mainnet","ltc-mainnet","ltc-testnet","mantle-mainnet","mantle-sepolia","mode-mainnet","monad-mainnet","monad-testnet","morph-hoodi","morph-mainnet","nova-mainnet","omni-mainnet","omni-omega","optimism-mainnet","optimism-sepolia","peaq-mainnet","plasma-testnet","plasma-mainnet","polygon-amoy","polygon-mainnet","redstone-mainnet","sahara-testnet","scroll-mainnet","scroll-testnet","sei-mainnet","sei-testnet","solana-devnet","solana-mainnet","solana-testnet","soneium-mainnet","sonic-mainnet","sophon-mainnet","sophon-testnet","stellar-mainnet","stellar-testnet","story-aeneid","story-mainnet","tempo-mainnet","tempo-testnet","tron-mainnet","unichain-mainnet","unichain-sepolia","vana-mainnet","vana-moksha","worldchain-mainnet","worldchain-sepolia","xai-mainnet","xai-sepolia","xlayer-mainnet","xrp-mainnet","xrp-testnet","xrplevm-mainnet","xrplevm-testnet","zerog-galileo","zerog-mainnet","zkevm-cardona","zkevm-mainnet","zksync-mainnet","zksync-sepolia","zora-mainnet"],"example":"ethereum-mainnet"},"dataset":{"type":"string","enum":["block","block_with_receipts","receipts","logs","transactions","trace_blocks","debug_traces","block_with_receipts_debug_trace","block_with_receipts_trace_block","programs_with_logs","ledger","events","orders","trades","book_updates","twap","writer_actions","events_with_orders"],"example":"block"},"filter_function":{"type":"string","example":"dHJ5IHsKICAgIHZhciBkYXRhID0gSlNPTi5wYXJzZShzdHJlYW1EYXRhKTsKICAgIC8vIENvbnZlcnQgaGV4IG51bWJlciB0byBkZWNpbWFsCiAgICB2YXIgbnVtYmVyRGVjaW1hbCA9IHBhcnNlSW50KGRhdGEubnVtYmVyLCAxNik7CiAgICB2YXIgZmlsdGVyZWREYXRhID0ge2hhc2g6IGRhdGEuaGFzaCwgbnVtYmVyOiBudW1iZXJEZWNpbWFsfTsKICAgIEpTT04uc3RyaW5naWZ5KGZpbHRlcmVkRGF0YSk7Cn0gY2F0Y2ggKGUpIHsKICAgIEpTT04uc3RyaW5naWZ5KHtlcnJvcjogZS5tZXNzYWdlfSk7Cn0K","description":"JS/ECMAScript compliant filter encoded in base64","format":"base64"},"region":{"type":"string","enum":["usa_east","europe_central","asia_east"],"example":"usa_east"},"start_range":{"type":"integer","example":100,"description":"Stream start at block number. If not provided, the stream will start at the latest block."},"end_range":{"type":"integer","example":200,"description":"Stream until block number"},"dataset_batch_size":{"type":"number","example":1},"elastic_batch_enabled":{"type":"boolean","example":true},"destination":{"type":"string","enum":["webhook","s3","azure","function","postgres","kafka"],"example":"webhook"},"fix_block_reorgs":{"type":"number","example":0,"description":"Fix block reorgs by streaming correct blocks: 1. Ignore reorgs: 0"},"keep_distance_from_tip":{"type":"number","example":0,"description":"Stay away from tip by N blocks"},"notification_email":{"type":"string","example":"contact@example.com","description":"Notify when stream is terminated"},"destination_attributes":{"oneOf":[{"$ref":"#/components/schemas/S3Attributes"},{"$ref":"#/components/schemas/WebhookAttributes"},{"$ref":"#/components/schemas/QuickfunctionsAttributes"},{"$ref":"#/components/schemas/PostgresAttributes"},{"$ref":"#/components/schemas/AzureAttributes"},{"$ref":"#/components/schemas/KafkaAttributes"}],"example":{"url":"http://localhost:8080/test","security_token":"sample-security-token","compression":"none","headers":{"Content-Type":"Test","Authorization":"again"},"max_retry":3,"retry_interval_sec":1,"post_timeout_sec":10}},"extra_destinations":{"description":"Additional destinations for the stream","type":"array","items":{"$ref":"#/components/schemas/ExtraDestinationDto"}},"status":{"type":"string","enum":["active","paused"],"example":"active"}},"required":["name","network","dataset","filter_function","region","dataset_batch_size","elastic_batch_enabled","destination","destination_attributes","status"]},"UpdateStreamDto":{"type":"object","properties":{"name":{"type":"string","example":"My Stream"},"filter_function":{"type":"string","example":"dHJ5IHsKICAgIHZhciBkYXRhID0gSlNPTi5wYXJzZShzdHJlYW1EYXRhKTsKICAgIC8vIENvbnZlcnQgaGV4IG51bWJlciB0byBkZWNpbWFsCiAgICB2YXIgbnVtYmVyRGVjaW1hbCA9IHBhcnNlSW50KGRhdGEubnVtYmVyLCAxNik7CiAgICB2YXIgZmlsdGVyZWREYXRhID0ge2hhc2g6IGRhdGEuaGFzaCwgbnVtYmVyOiBudW1iZXJEZWNpbWFsfTsKICAgIEpTT04uc3RyaW5naWZ5KGZpbHRlcmVkRGF0YSk7Cn0gY2F0Y2ggKGUpIHsKICAgIEpTT04uc3RyaW5naWZ5KHtlcnJvcjogZS5tZXNzYWdlfSk7Cn0K","description":"JS/ECMAScript compliant filter encoded in base64","format":"base64"},"start_range":{"type":"integer","example":100,"description":"Stream start at block number. If not provided, the stream will start at the latest block."},"end_range":{"type":"integer","example":200,"description":"Stream until block number"},"dataset_batch_size":{"type":"number","example":1},"elastic_batch_enabled":{"type":"boolean","example":true},"destination":{"type":"string","enum":["webhook","s3","azure","function","postgres","kafka"],"example":"webhook"},"fix_block_reorgs":{"type":"number","example":0,"description":"Fix block reorgs by streaming correct blocks: 1. Ignore reorgs: 0"},"keep_distance_from_tip":{"type":"number","example":0,"description":"Stay away from tip by N blocks"},"notification_email":{"type":"string","example":"contact@example.com","description":"Notify when stream is terminated"},"destination_attributes":{"oneOf":[{"$ref":"#/components/schemas/S3Attributes"},{"$ref":"#/components/schemas/WebhookAttributes"},{"$ref":"#/components/schemas/QuickfunctionsAttributes"},{"$ref":"#/components/schemas/PostgresAttributes"},{"$ref":"#/components/schemas/AzureAttributes"},{"$ref":"#/components/schemas/KafkaAttributes"}],"example":{"url":"http://localhost:8080/test","security_token":"sample-security-token","compression":"none","headers":{"Content-Type":"Test","Authorization":"again"},"max_retry":3,"retry_interval_sec":1,"post_timeout_sec":10}},"extra_destinations":{"description":"Additional destinations for the stream","type":"array","items":{"$ref":"#/components/schemas/ExtraDestinationDto"}},"status":{"type":"string","enum":["active","paused"],"example":"active"}}},"TestFilterFunctionDto":{"type":"object","properties":{"network":{"type":"string","enum":["abstract-mainnet","abstract-testnet","arbitrum-mainnet","arbitrum-sepolia","arc-testnet","avalanche-fuji","avalanche-mainnet","b3-mainnet","b3-sepolia","base-mainnet","base-sepolia","bera-mainnet","bera-bepolia","bch-mainnet","bch-testnet","bitcoin-mainnet","bitcoin-testnet4","blast-mainnet","blast-sepolia","bnbchain-mainnet","bnbchain-testnet","celo-mainnet","cyber-mainnet","cyber-sepolia","doge-mainnet","ethereum-hoodi","ethereum-mainnet","ethereum-sepolia","fantom-mainnet","flare-mainnet","flare-testnet","flow-mainnet","flow-testnet","fraxtal-mainnet","gnosis-mainnet","gravity-alpham","hedera-mainnet","hedera-testnet","hemi-mainnet","hemi-testnet","hyperevm-mainnet","hyperevm-testnet","hypercore-mainnet","imx-mainnet","imx-testnet","injective-mainnet","injective-testnet","ink-mainnet","ink-sepolia","joc-mainnet","kaia-mainnet","kaia-testnet","katana-mainnet","lens-mainnet","lens-testnet","linea-mainnet","lisk-mainnet","ltc-mainnet","ltc-testnet","mantle-mainnet","mantle-sepolia","mode-mainnet","monad-mainnet","monad-testnet","morph-hoodi","morph-mainnet","nova-mainnet","omni-mainnet","omni-omega","optimism-mainnet","optimism-sepolia","peaq-mainnet","plasma-testnet","plasma-mainnet","polygon-amoy","polygon-mainnet","redstone-mainnet","sahara-testnet","scroll-mainnet","scroll-testnet","sei-mainnet","sei-testnet","solana-devnet","solana-mainnet","solana-testnet","soneium-mainnet","sonic-mainnet","sophon-mainnet","sophon-testnet","stellar-mainnet","stellar-testnet","story-aeneid","story-mainnet","tempo-mainnet","tempo-testnet","tron-mainnet","unichain-mainnet","unichain-sepolia","vana-mainnet","vana-moksha","worldchain-mainnet","worldchain-sepolia","xai-mainnet","xai-sepolia","xlayer-mainnet","xrp-mainnet","xrp-testnet","xrplevm-mainnet","xrplevm-testnet","zerog-galileo","zerog-mainnet","zkevm-cardona","zkevm-mainnet","zksync-mainnet","zksync-sepolia","zora-mainnet"],"example":"ethereum-mainnet"},"block":{"type":"string","example":"17811625"},"dataset":{"type":"string","enum":["block","block_with_receipts","receipts","logs","transactions","trace_blocks","debug_traces","block_with_receipts_debug_trace","block_with_receipts_trace_block","programs_with_logs","ledger","events","orders","trades","book_updates","twap","writer_actions","events_with_orders"],"example":"block"},"filter_function":{"type":"string","example":"ZnVuY3Rpb24gbWFpbihzdHJlYW0pIHsKICAvLyBJZiBzdHJlYW0gaXMgY29uZmlndXJlZCB3aXRoIG1ldGFkYXRhIGluIHRoZSBib2R5LCB0aGUgZGF0YSBtYXkgYmUgbmVzdGVkIHVuZGVyICJkYXRhIiBrZXkKICBjb25zdCBkYXRhID0gc3RyZWFtLmRhdGEgPyBzdHJlYW0uZGF0YSA6IHN0cmVhbTsKCiAgcmV0dXJuIGRhdGE7Cn0=","description":"JS/ECMAScript compliant filter encoded in base64","format":"base64"}},"required":["network","block","dataset","filter_function"]}}}} \ No newline at end of file diff --git a/api/streams/streams.gen.go b/api/streams/streams.gen.go index f5f2093..5b1a426 100644 --- a/api/streams/streams.gen.go +++ b/api/streams/streams.gen.go @@ -35,6 +35,7 @@ const ( CreateStreamDtoDatasetBookUpdates CreateStreamDtoDataset = "book_updates" CreateStreamDtoDatasetDebugTraces CreateStreamDtoDataset = "debug_traces" CreateStreamDtoDatasetEvents CreateStreamDtoDataset = "events" + CreateStreamDtoDatasetEventsWithOrders CreateStreamDtoDataset = "events_with_orders" CreateStreamDtoDatasetLedger CreateStreamDtoDataset = "ledger" CreateStreamDtoDatasetLogs CreateStreamDtoDataset = "logs" CreateStreamDtoDatasetOrders CreateStreamDtoDataset = "orders" @@ -51,18 +52,12 @@ const ( const ( CreateStreamDtoDestinationAzure CreateStreamDtoDestination = "azure" CreateStreamDtoDestinationFunction CreateStreamDtoDestination = "function" + CreateStreamDtoDestinationKafka CreateStreamDtoDestination = "kafka" CreateStreamDtoDestinationPostgres CreateStreamDtoDestination = "postgres" CreateStreamDtoDestinationS3 CreateStreamDtoDestination = "s3" CreateStreamDtoDestinationWebhook CreateStreamDtoDestination = "webhook" ) -// Defines values for CreateStreamDtoIncludeStreamMetadata. -const ( - CreateStreamDtoIncludeStreamMetadataBody CreateStreamDtoIncludeStreamMetadata = "body" - CreateStreamDtoIncludeStreamMetadataHeader CreateStreamDtoIncludeStreamMetadata = "header" - CreateStreamDtoIncludeStreamMetadataNone CreateStreamDtoIncludeStreamMetadata = "none" -) - // Defines values for CreateStreamDtoNetwork. const ( CreateStreamDtoNetworkAbstractMainnet CreateStreamDtoNetwork = "abstract-mainnet" @@ -101,10 +96,13 @@ const ( CreateStreamDtoNetworkFraxtalMainnet CreateStreamDtoNetwork = "fraxtal-mainnet" CreateStreamDtoNetworkGnosisMainnet CreateStreamDtoNetwork = "gnosis-mainnet" CreateStreamDtoNetworkGravityAlpham CreateStreamDtoNetwork = "gravity-alpham" + CreateStreamDtoNetworkHederaMainnet CreateStreamDtoNetwork = "hedera-mainnet" + CreateStreamDtoNetworkHederaTestnet CreateStreamDtoNetwork = "hedera-testnet" CreateStreamDtoNetworkHemiMainnet CreateStreamDtoNetwork = "hemi-mainnet" CreateStreamDtoNetworkHemiTestnet CreateStreamDtoNetwork = "hemi-testnet" CreateStreamDtoNetworkHypercoreMainnet CreateStreamDtoNetwork = "hypercore-mainnet" CreateStreamDtoNetworkHyperevmMainnet CreateStreamDtoNetwork = "hyperevm-mainnet" + CreateStreamDtoNetworkHyperevmTestnet CreateStreamDtoNetwork = "hyperevm-testnet" CreateStreamDtoNetworkImxMainnet CreateStreamDtoNetwork = "imx-mainnet" CreateStreamDtoNetworkImxTestnet CreateStreamDtoNetwork = "imx-testnet" CreateStreamDtoNetworkInjectiveMainnet CreateStreamDtoNetwork = "injective-mainnet" @@ -119,8 +117,8 @@ const ( CreateStreamDtoNetworkLensTestnet CreateStreamDtoNetwork = "lens-testnet" CreateStreamDtoNetworkLineaMainnet CreateStreamDtoNetwork = "linea-mainnet" CreateStreamDtoNetworkLiskMainnet CreateStreamDtoNetwork = "lisk-mainnet" - CreateStreamDtoNetworkLitecoinMainnet CreateStreamDtoNetwork = "litecoin-mainnet" - CreateStreamDtoNetworkLitecoinTestnet CreateStreamDtoNetwork = "litecoin-testnet" + CreateStreamDtoNetworkLtcMainnet CreateStreamDtoNetwork = "ltc-mainnet" + CreateStreamDtoNetworkLtcTestnet CreateStreamDtoNetwork = "ltc-testnet" CreateStreamDtoNetworkMantleMainnet CreateStreamDtoNetwork = "mantle-mainnet" CreateStreamDtoNetworkMantleSepolia CreateStreamDtoNetwork = "mantle-sepolia" CreateStreamDtoNetworkModeMainnet CreateStreamDtoNetwork = "mode-mainnet" @@ -155,6 +153,8 @@ const ( CreateStreamDtoNetworkStellarTestnet CreateStreamDtoNetwork = "stellar-testnet" CreateStreamDtoNetworkStoryAeneid CreateStreamDtoNetwork = "story-aeneid" CreateStreamDtoNetworkStoryMainnet CreateStreamDtoNetwork = "story-mainnet" + CreateStreamDtoNetworkTempoMainnet CreateStreamDtoNetwork = "tempo-mainnet" + CreateStreamDtoNetworkTempoTestnet CreateStreamDtoNetwork = "tempo-testnet" CreateStreamDtoNetworkTronMainnet CreateStreamDtoNetwork = "tron-mainnet" CreateStreamDtoNetworkUnichainMainnet CreateStreamDtoNetwork = "unichain-mainnet" CreateStreamDtoNetworkUnichainSepolia CreateStreamDtoNetwork = "unichain-sepolia" @@ -191,6 +191,42 @@ const ( CreateStreamDtoStatusPaused CreateStreamDtoStatus = "paused" ) +// Defines values for ExtraDestinationDtoDestination. +const ( + ExtraDestinationDtoDestinationAzure ExtraDestinationDtoDestination = "azure" + ExtraDestinationDtoDestinationFunction ExtraDestinationDtoDestination = "function" + ExtraDestinationDtoDestinationKafka ExtraDestinationDtoDestination = "kafka" + ExtraDestinationDtoDestinationPostgres ExtraDestinationDtoDestination = "postgres" + ExtraDestinationDtoDestinationS3 ExtraDestinationDtoDestination = "s3" + ExtraDestinationDtoDestinationWebhook ExtraDestinationDtoDestination = "webhook" +) + +// Defines values for KafkaAttributesCompressionType. +const ( + Gzip KafkaAttributesCompressionType = "gzip" + Lz4 KafkaAttributesCompressionType = "lz4" + None KafkaAttributesCompressionType = "none" + Snappy KafkaAttributesCompressionType = "snappy" + Zstd KafkaAttributesCompressionType = "zstd" +) + +// Defines values for KafkaAttributesMechanisms. +const ( + GSSAPI KafkaAttributesMechanisms = "GSSAPI" + OAUTHBEARER KafkaAttributesMechanisms = "OAUTHBEARER" + PLAIN KafkaAttributesMechanisms = "PLAIN" + SCRAMSHA256 KafkaAttributesMechanisms = "SCRAM-SHA-256" + SCRAMSHA512 KafkaAttributesMechanisms = "SCRAM-SHA-512" +) + +// Defines values for KafkaAttributesProtocol. +const ( + Plaintext KafkaAttributesProtocol = "plaintext" + SaslPlaintext KafkaAttributesProtocol = "sasl_plaintext" + SaslSsl KafkaAttributesProtocol = "sasl_ssl" + Ssl KafkaAttributesProtocol = "ssl" +) + // Defines values for PostgresAttributesSslmode. const ( Disable PostgresAttributesSslmode = "disable" @@ -212,6 +248,7 @@ const ( TestFilterFunctionDtoDatasetBookUpdates TestFilterFunctionDtoDataset = "book_updates" TestFilterFunctionDtoDatasetDebugTraces TestFilterFunctionDtoDataset = "debug_traces" TestFilterFunctionDtoDatasetEvents TestFilterFunctionDtoDataset = "events" + TestFilterFunctionDtoDatasetEventsWithOrders TestFilterFunctionDtoDataset = "events_with_orders" TestFilterFunctionDtoDatasetLedger TestFilterFunctionDtoDataset = "ledger" TestFilterFunctionDtoDatasetLogs TestFilterFunctionDtoDataset = "logs" TestFilterFunctionDtoDatasetOrders TestFilterFunctionDtoDataset = "orders" @@ -262,10 +299,13 @@ const ( TestFilterFunctionDtoNetworkFraxtalMainnet TestFilterFunctionDtoNetwork = "fraxtal-mainnet" TestFilterFunctionDtoNetworkGnosisMainnet TestFilterFunctionDtoNetwork = "gnosis-mainnet" TestFilterFunctionDtoNetworkGravityAlpham TestFilterFunctionDtoNetwork = "gravity-alpham" + TestFilterFunctionDtoNetworkHederaMainnet TestFilterFunctionDtoNetwork = "hedera-mainnet" + TestFilterFunctionDtoNetworkHederaTestnet TestFilterFunctionDtoNetwork = "hedera-testnet" TestFilterFunctionDtoNetworkHemiMainnet TestFilterFunctionDtoNetwork = "hemi-mainnet" TestFilterFunctionDtoNetworkHemiTestnet TestFilterFunctionDtoNetwork = "hemi-testnet" TestFilterFunctionDtoNetworkHypercoreMainnet TestFilterFunctionDtoNetwork = "hypercore-mainnet" TestFilterFunctionDtoNetworkHyperevmMainnet TestFilterFunctionDtoNetwork = "hyperevm-mainnet" + TestFilterFunctionDtoNetworkHyperevmTestnet TestFilterFunctionDtoNetwork = "hyperevm-testnet" TestFilterFunctionDtoNetworkImxMainnet TestFilterFunctionDtoNetwork = "imx-mainnet" TestFilterFunctionDtoNetworkImxTestnet TestFilterFunctionDtoNetwork = "imx-testnet" TestFilterFunctionDtoNetworkInjectiveMainnet TestFilterFunctionDtoNetwork = "injective-mainnet" @@ -280,8 +320,8 @@ const ( TestFilterFunctionDtoNetworkLensTestnet TestFilterFunctionDtoNetwork = "lens-testnet" TestFilterFunctionDtoNetworkLineaMainnet TestFilterFunctionDtoNetwork = "linea-mainnet" TestFilterFunctionDtoNetworkLiskMainnet TestFilterFunctionDtoNetwork = "lisk-mainnet" - TestFilterFunctionDtoNetworkLitecoinMainnet TestFilterFunctionDtoNetwork = "litecoin-mainnet" - TestFilterFunctionDtoNetworkLitecoinTestnet TestFilterFunctionDtoNetwork = "litecoin-testnet" + TestFilterFunctionDtoNetworkLtcMainnet TestFilterFunctionDtoNetwork = "ltc-mainnet" + TestFilterFunctionDtoNetworkLtcTestnet TestFilterFunctionDtoNetwork = "ltc-testnet" TestFilterFunctionDtoNetworkMantleMainnet TestFilterFunctionDtoNetwork = "mantle-mainnet" TestFilterFunctionDtoNetworkMantleSepolia TestFilterFunctionDtoNetwork = "mantle-sepolia" TestFilterFunctionDtoNetworkModeMainnet TestFilterFunctionDtoNetwork = "mode-mainnet" @@ -316,6 +356,8 @@ const ( TestFilterFunctionDtoNetworkStellarTestnet TestFilterFunctionDtoNetwork = "stellar-testnet" TestFilterFunctionDtoNetworkStoryAeneid TestFilterFunctionDtoNetwork = "story-aeneid" TestFilterFunctionDtoNetworkStoryMainnet TestFilterFunctionDtoNetwork = "story-mainnet" + TestFilterFunctionDtoNetworkTempoMainnet TestFilterFunctionDtoNetwork = "tempo-mainnet" + TestFilterFunctionDtoNetworkTempoTestnet TestFilterFunctionDtoNetwork = "tempo-testnet" TestFilterFunctionDtoNetworkTronMainnet TestFilterFunctionDtoNetwork = "tron-mainnet" TestFilterFunctionDtoNetworkUnichainMainnet TestFilterFunctionDtoNetwork = "unichain-mainnet" TestFilterFunctionDtoNetworkUnichainSepolia TestFilterFunctionDtoNetwork = "unichain-sepolia" @@ -341,18 +383,12 @@ const ( // Defines values for UpdateStreamDtoDestination. const ( - UpdateStreamDtoDestinationAzure UpdateStreamDtoDestination = "azure" - UpdateStreamDtoDestinationFunction UpdateStreamDtoDestination = "function" - UpdateStreamDtoDestinationPostgres UpdateStreamDtoDestination = "postgres" - UpdateStreamDtoDestinationS3 UpdateStreamDtoDestination = "s3" - UpdateStreamDtoDestinationWebhook UpdateStreamDtoDestination = "webhook" -) - -// Defines values for UpdateStreamDtoIncludeStreamMetadata. -const ( - UpdateStreamDtoIncludeStreamMetadataBody UpdateStreamDtoIncludeStreamMetadata = "body" - UpdateStreamDtoIncludeStreamMetadataHeader UpdateStreamDtoIncludeStreamMetadata = "header" - UpdateStreamDtoIncludeStreamMetadataNone UpdateStreamDtoIncludeStreamMetadata = "none" + Azure UpdateStreamDtoDestination = "azure" + Function UpdateStreamDtoDestination = "function" + Kafka UpdateStreamDtoDestination = "kafka" + Postgres UpdateStreamDtoDestination = "postgres" + S3 UpdateStreamDtoDestination = "s3" + Webhook UpdateStreamDtoDestination = "webhook" ) // Defines values for UpdateStreamDtoStatus. @@ -387,12 +423,14 @@ type CreateStreamDto struct { // EndRange Stream until block number EndRange *int `json:"end_range,omitempty"` + // ExtraDestinations Additional destinations for the stream + ExtraDestinations *[]ExtraDestinationDto `json:"extra_destinations,omitempty"` + // FilterFunction JS/ECMAScript compliant filter encoded in base64 FilterFunction string `json:"filter_function"` // FixBlockReorgs Fix block reorgs by streaming correct blocks: 1. Ignore reorgs: 0 - FixBlockReorgs *float32 `json:"fix_block_reorgs,omitempty"` - IncludeStreamMetadata CreateStreamDtoIncludeStreamMetadata `json:"include_stream_metadata"` + FixBlockReorgs *float32 `json:"fix_block_reorgs,omitempty"` // KeepDistanceFromTip Stay away from tip by N blocks KeepDistanceFromTip *float32 `json:"keep_distance_from_tip,omitempty"` @@ -419,9 +457,6 @@ type CreateStreamDto_DestinationAttributes struct { union json.RawMessage } -// CreateStreamDtoIncludeStreamMetadata defines model for CreateStreamDto.IncludeStreamMetadata. -type CreateStreamDtoIncludeStreamMetadata string - // CreateStreamDtoNetwork defines model for CreateStreamDto.Network. type CreateStreamDtoNetwork string @@ -431,6 +466,49 @@ type CreateStreamDtoRegion string // CreateStreamDtoStatus defines model for CreateStreamDto.Status. type CreateStreamDtoStatus string +// ExtraDestinationDto defines model for ExtraDestinationDto. +type ExtraDestinationDto struct { + Destination ExtraDestinationDtoDestination `json:"destination"` + DestinationAttributes ExtraDestinationDto_DestinationAttributes `json:"destination_attributes"` +} + +// ExtraDestinationDtoDestination defines model for ExtraDestinationDto.Destination. +type ExtraDestinationDtoDestination string + +// ExtraDestinationDto_DestinationAttributes defines model for ExtraDestinationDto.DestinationAttributes. +type ExtraDestinationDto_DestinationAttributes struct { + union json.RawMessage +} + +// KafkaAttributes defines model for KafkaAttributes. +type KafkaAttributes struct { + BatchSize float32 `json:"batch_size"` + BootstrapServers string `json:"bootstrap_servers"` + CompressionType KafkaAttributesCompressionType `json:"compression_type"` + LingerMs float32 `json:"linger_ms"` + MaxMessageBytes float32 `json:"max_message_bytes"` + MaxRetry float32 `json:"max_retry"` + Mechanisms *KafkaAttributesMechanisms `json:"mechanisms,omitempty"` + Password *string `json:"password,omitempty"` + Protocol *KafkaAttributesProtocol `json:"protocol,omitempty"` + RetryIntervalSec float32 `json:"retry_interval_sec"` + SslCaPem *string `json:"ssl_ca_pem,omitempty"` + SslCertificatePem *string `json:"ssl_certificate_pem,omitempty"` + SslKeyPem *string `json:"ssl_key_pem,omitempty"` + TimeoutSec float32 `json:"timeout_sec"` + TopicName string `json:"topic_name"` + Username *string `json:"username,omitempty"` +} + +// KafkaAttributesCompressionType defines model for KafkaAttributes.CompressionType. +type KafkaAttributesCompressionType string + +// KafkaAttributesMechanisms defines model for KafkaAttributes.Mechanisms. +type KafkaAttributesMechanisms string + +// KafkaAttributesProtocol defines model for KafkaAttributes.Protocol. +type KafkaAttributesProtocol string + // PostgresAttributes defines model for PostgresAttributes. type PostgresAttributes struct { AccessKey string `json:"access_key"` @@ -502,12 +580,14 @@ type UpdateStreamDto struct { // EndRange Stream until block number EndRange *int `json:"end_range,omitempty"` + // ExtraDestinations Additional destinations for the stream + ExtraDestinations *[]ExtraDestinationDto `json:"extra_destinations,omitempty"` + // FilterFunction JS/ECMAScript compliant filter encoded in base64 FilterFunction *string `json:"filter_function,omitempty"` // FixBlockReorgs Fix block reorgs by streaming correct blocks: 1. Ignore reorgs: 0 - FixBlockReorgs *float32 `json:"fix_block_reorgs,omitempty"` - IncludeStreamMetadata *UpdateStreamDtoIncludeStreamMetadata `json:"include_stream_metadata,omitempty"` + FixBlockReorgs *float32 `json:"fix_block_reorgs,omitempty"` // KeepDistanceFromTip Stay away from tip by N blocks KeepDistanceFromTip *float32 `json:"keep_distance_from_tip,omitempty"` @@ -529,9 +609,6 @@ type UpdateStreamDto_DestinationAttributes struct { union json.RawMessage } -// UpdateStreamDtoIncludeStreamMetadata defines model for UpdateStreamDto.IncludeStreamMetadata. -type UpdateStreamDtoIncludeStreamMetadata string - // UpdateStreamDtoStatus defines model for UpdateStreamDto.Status. type UpdateStreamDtoStatus string @@ -691,6 +768,32 @@ func (t *CreateStreamDto_DestinationAttributes) MergeAzureAttributes(v AzureAttr return err } +// AsKafkaAttributes returns the union data inside the CreateStreamDto_DestinationAttributes as a KafkaAttributes +func (t CreateStreamDto_DestinationAttributes) AsKafkaAttributes() (KafkaAttributes, error) { + var body KafkaAttributes + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromKafkaAttributes overwrites any union data inside the CreateStreamDto_DestinationAttributes as the provided KafkaAttributes +func (t *CreateStreamDto_DestinationAttributes) FromKafkaAttributes(v KafkaAttributes) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeKafkaAttributes performs a merge with any union data inside the CreateStreamDto_DestinationAttributes, using the provided KafkaAttributes +func (t *CreateStreamDto_DestinationAttributes) MergeKafkaAttributes(v KafkaAttributes) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + func (t CreateStreamDto_DestinationAttributes) MarshalJSON() ([]byte, error) { b, err := t.union.MarshalJSON() return b, err @@ -701,6 +804,172 @@ func (t *CreateStreamDto_DestinationAttributes) UnmarshalJSON(b []byte) error { return err } +// AsS3Attributes returns the union data inside the ExtraDestinationDto_DestinationAttributes as a S3Attributes +func (t ExtraDestinationDto_DestinationAttributes) AsS3Attributes() (S3Attributes, error) { + var body S3Attributes + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromS3Attributes overwrites any union data inside the ExtraDestinationDto_DestinationAttributes as the provided S3Attributes +func (t *ExtraDestinationDto_DestinationAttributes) FromS3Attributes(v S3Attributes) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeS3Attributes performs a merge with any union data inside the ExtraDestinationDto_DestinationAttributes, using the provided S3Attributes +func (t *ExtraDestinationDto_DestinationAttributes) MergeS3Attributes(v S3Attributes) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsWebhookAttributes returns the union data inside the ExtraDestinationDto_DestinationAttributes as a WebhookAttributes +func (t ExtraDestinationDto_DestinationAttributes) AsWebhookAttributes() (WebhookAttributes, error) { + var body WebhookAttributes + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromWebhookAttributes overwrites any union data inside the ExtraDestinationDto_DestinationAttributes as the provided WebhookAttributes +func (t *ExtraDestinationDto_DestinationAttributes) FromWebhookAttributes(v WebhookAttributes) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeWebhookAttributes performs a merge with any union data inside the ExtraDestinationDto_DestinationAttributes, using the provided WebhookAttributes +func (t *ExtraDestinationDto_DestinationAttributes) MergeWebhookAttributes(v WebhookAttributes) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsQuickfunctionsAttributes returns the union data inside the ExtraDestinationDto_DestinationAttributes as a QuickfunctionsAttributes +func (t ExtraDestinationDto_DestinationAttributes) AsQuickfunctionsAttributes() (QuickfunctionsAttributes, error) { + var body QuickfunctionsAttributes + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromQuickfunctionsAttributes overwrites any union data inside the ExtraDestinationDto_DestinationAttributes as the provided QuickfunctionsAttributes +func (t *ExtraDestinationDto_DestinationAttributes) FromQuickfunctionsAttributes(v QuickfunctionsAttributes) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeQuickfunctionsAttributes performs a merge with any union data inside the ExtraDestinationDto_DestinationAttributes, using the provided QuickfunctionsAttributes +func (t *ExtraDestinationDto_DestinationAttributes) MergeQuickfunctionsAttributes(v QuickfunctionsAttributes) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsPostgresAttributes returns the union data inside the ExtraDestinationDto_DestinationAttributes as a PostgresAttributes +func (t ExtraDestinationDto_DestinationAttributes) AsPostgresAttributes() (PostgresAttributes, error) { + var body PostgresAttributes + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromPostgresAttributes overwrites any union data inside the ExtraDestinationDto_DestinationAttributes as the provided PostgresAttributes +func (t *ExtraDestinationDto_DestinationAttributes) FromPostgresAttributes(v PostgresAttributes) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergePostgresAttributes performs a merge with any union data inside the ExtraDestinationDto_DestinationAttributes, using the provided PostgresAttributes +func (t *ExtraDestinationDto_DestinationAttributes) MergePostgresAttributes(v PostgresAttributes) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsAzureAttributes returns the union data inside the ExtraDestinationDto_DestinationAttributes as a AzureAttributes +func (t ExtraDestinationDto_DestinationAttributes) AsAzureAttributes() (AzureAttributes, error) { + var body AzureAttributes + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromAzureAttributes overwrites any union data inside the ExtraDestinationDto_DestinationAttributes as the provided AzureAttributes +func (t *ExtraDestinationDto_DestinationAttributes) FromAzureAttributes(v AzureAttributes) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeAzureAttributes performs a merge with any union data inside the ExtraDestinationDto_DestinationAttributes, using the provided AzureAttributes +func (t *ExtraDestinationDto_DestinationAttributes) MergeAzureAttributes(v AzureAttributes) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsKafkaAttributes returns the union data inside the ExtraDestinationDto_DestinationAttributes as a KafkaAttributes +func (t ExtraDestinationDto_DestinationAttributes) AsKafkaAttributes() (KafkaAttributes, error) { + var body KafkaAttributes + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromKafkaAttributes overwrites any union data inside the ExtraDestinationDto_DestinationAttributes as the provided KafkaAttributes +func (t *ExtraDestinationDto_DestinationAttributes) FromKafkaAttributes(v KafkaAttributes) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeKafkaAttributes performs a merge with any union data inside the ExtraDestinationDto_DestinationAttributes, using the provided KafkaAttributes +func (t *ExtraDestinationDto_DestinationAttributes) MergeKafkaAttributes(v KafkaAttributes) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +func (t ExtraDestinationDto_DestinationAttributes) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *ExtraDestinationDto_DestinationAttributes) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} + // AsS3Attributes returns the union data inside the UpdateStreamDto_DestinationAttributes as a S3Attributes func (t UpdateStreamDto_DestinationAttributes) AsS3Attributes() (S3Attributes, error) { var body S3Attributes @@ -831,6 +1100,32 @@ func (t *UpdateStreamDto_DestinationAttributes) MergeAzureAttributes(v AzureAttr return err } +// AsKafkaAttributes returns the union data inside the UpdateStreamDto_DestinationAttributes as a KafkaAttributes +func (t UpdateStreamDto_DestinationAttributes) AsKafkaAttributes() (KafkaAttributes, error) { + var body KafkaAttributes + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromKafkaAttributes overwrites any union data inside the UpdateStreamDto_DestinationAttributes as the provided KafkaAttributes +func (t *UpdateStreamDto_DestinationAttributes) FromKafkaAttributes(v KafkaAttributes) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeKafkaAttributes performs a merge with any union data inside the UpdateStreamDto_DestinationAttributes, using the provided KafkaAttributes +func (t *UpdateStreamDto_DestinationAttributes) MergeKafkaAttributes(v KafkaAttributes) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + func (t UpdateStreamDto_DestinationAttributes) MarshalJSON() ([]byte, error) { b, err := t.union.MarshalJSON() return b, err diff --git a/internal/provider/stream_resource.go b/internal/provider/stream_resource.go index 2d23d08..c5b0265 100644 --- a/internal/provider/stream_resource.go +++ b/internal/provider/stream_resource.go @@ -210,7 +210,8 @@ func (r *StreamResource) Schema(ctx context.Context, req resource.SchemaRequest, }, "include_stream_metadata": schema.StringAttribute{ - Required: true, + Optional: true, + DeprecationMessage: "include_stream_metadata has been removed from the QuickNode Streams API and is no longer sent to the API. This field will be removed in a future provider release. You may safely remove it from your configuration.", Validators: []validator.String{ metadataValidator, }, @@ -759,9 +760,9 @@ func (r *StreamResource) Create(ctx context.Context, req resource.CreateRequest, Network: streams.CreateStreamDtoNetwork(data.Network.ValueString()), Dataset: streams.CreateStreamDtoDataset(data.Dataset.ValueString()), StartRange: startRangePtr, - DatasetBatchSize: datasetBatchSize, - IncludeStreamMetadata: streams.CreateStreamDtoIncludeStreamMetadata(data.IncludeStreamMetadata.ValueString()), - Destination: streams.CreateStreamDtoDestination(data.Destination.ValueString()), + DatasetBatchSize: datasetBatchSize, + // include_stream_metadata removed from QuickNode API (no longer accepted in create requests) + Destination: streams.CreateStreamDtoDestination(data.Destination.ValueString()), ElasticBatchEnabled: data.ElasticBatchEnabled.ValueBool(), Status: streams.CreateStreamDtoStatus(data.Status.ValueString()), FilterFunction: filterFunction, @@ -1005,7 +1006,7 @@ func (r *StreamResource) Update(ctx context.Context, req resource.UpdateRequest, startRange := int(plan.StartRange.ValueInt64()) datasetBatchSize := float32(plan.DatasetBatchSize.ValueInt64()) elasticBatchEnabled := plan.ElasticBatchEnabled.ValueBool() - includeStreamMetadata := streams.UpdateStreamDtoIncludeStreamMetadata(plan.IncludeStreamMetadata.ValueString()) + // include_stream_metadata removed from QuickNode API (no longer accepted in update requests) destination := streams.UpdateStreamDtoDestination(plan.Destination.ValueString()) status := streams.UpdateStreamDtoStatus(plan.Status.ValueString()) @@ -1083,9 +1084,9 @@ func (r *StreamResource) Update(ctx context.Context, req resource.UpdateRequest, Name: &name, StartRange: &startRange, EndRange: optionalFields.EndRange, - DatasetBatchSize: &datasetBatchSize, - IncludeStreamMetadata: &includeStreamMetadata, - Destination: &destination, + DatasetBatchSize: &datasetBatchSize, + // include_stream_metadata removed from QuickNode API (no longer accepted in update requests) + Destination: &destination, ElasticBatchEnabled: &elasticBatchEnabled, Status: &status, FilterFunction: filterFunction, From 14bbcf49841c18ea0bada3397b91eb8e9392aafe Mon Sep 17 00:00:00 2001 From: lwargin-circle Date: Thu, 16 Apr 2026 15:58:53 +0200 Subject: [PATCH 04/11] fix: handle include_stream_metadata fallback in Create and update acceptance test Create() also called readStreamFromAPI without a fallback, causing include_stream_metadata to be overwritten with null after stream creation. Pass the plan as fallback so the config value is preserved in state. Update the acceptance test: - Remove TestCheckResourceAttr for include_stream_metadata (API no longer returns it, value comes from config fallback not API verification) - Add ImportStateVerifyIgnore for include_stream_metadata (import has no prior state to fall back to, so the field will be null after import) Co-Authored-By: Claude Sonnet 4.6 --- internal/provider/stream_resource.go | 6 ++++-- internal/provider/stream_resource_test.go | 10 ++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/internal/provider/stream_resource.go b/internal/provider/stream_resource.go index c5b0265..badc184 100644 --- a/internal/provider/stream_resource.go +++ b/internal/provider/stream_resource.go @@ -820,8 +820,10 @@ func (r *StreamResource) Create(ctx context.Context, req resource.CreateRequest, return } - // Read full stream data from API to get computed fields - fullStreamData, err := r.readStreamFromAPI(ctx, data.Id.ValueString()) + // Read full stream data from API to get computed fields. + // Pass the current plan as fallback so that fields the QuickNode API no longer returns + // in GET responses (e.g. include_stream_metadata) are preserved from the plan value. + fullStreamData, err := r.readStreamFromAPI(ctx, data.Id.ValueString(), &data) if err != nil { resp.Diagnostics.AddError("Error reading stream", err.Error()) return diff --git a/internal/provider/stream_resource_test.go b/internal/provider/stream_resource_test.go index 693aede..191b351 100644 --- a/internal/provider/stream_resource_test.go +++ b/internal/provider/stream_resource_test.go @@ -47,7 +47,8 @@ func TestAccMinimalQuicknodeStreamResource(t *testing.T) { resource.TestCheckResourceAttr("quicknode_stream.main", "region", "usa_east"), resource.TestCheckResourceAttr("quicknode_stream.main", "elastic_batch_enabled", "true"), resource.TestCheckResourceAttr("quicknode_stream.main", "dataset_batch_size", "1"), - resource.TestCheckResourceAttr("quicknode_stream.main", "include_stream_metadata", "body"), + // include_stream_metadata is deprecated and no longer returned by the QuickNode API; + // the state value is preserved from config via fallback but not verified via API. resource.TestCheckResourceAttr("quicknode_stream.main", "start_range", "59274680"), resource.TestCheckResourceAttr("quicknode_stream.main", "destination_attributes.max_retry", "3"), resource.TestCheckResourceAttr("quicknode_stream.main", "destination_attributes.retry_interval_sec", "1"), @@ -56,9 +57,10 @@ func TestAccMinimalQuicknodeStreamResource(t *testing.T) { }, // ImportState testing { - ResourceName: "quicknode_stream.main", - ImportState: true, - ImportStateVerify: true, + ResourceName: "quicknode_stream.main", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"include_stream_metadata"}, }, // Update and Read testing { From 501ce8cc601c46e89e9c9880a3790f1bfae77cec Mon Sep 17 00:00:00 2001 From: lwargin-circle Date: Tue, 21 Apr 2026 21:43:22 +0200 Subject: [PATCH 05/11] fix(ci): bump trivy-action; regenerate stream resource docs - Pin aquasecurity/trivy-action to v0.35.0 so setup-trivy resolves (v0.2.2 tag removed). - Run tfplugindocs output for stream.md (include_stream_metadata optional/deprecated). Made-with: Cursor --- .github/workflows/test.yml | 2 +- docs/resources/stream.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f7dfd28..000b20d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -59,7 +59,7 @@ jobs: steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Trivy Scan - uses: aquasecurity/trivy-action@18f2510ee396bbf400402947b394f2dd8c87dbb0 # 0.29.0 + uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0 with: scan-type: fs scan-ref: '.' diff --git a/docs/resources/stream.md b/docs/resources/stream.md index 25af1a3..567a2f2 100644 --- a/docs/resources/stream.md +++ b/docs/resources/stream.md @@ -22,7 +22,6 @@ Stream resource for QuickNode Streams API - `destination` (String) - `destination_attributes` (Attributes) (see [below for nested schema](#nestedatt--destination_attributes)) - `elastic_batch_enabled` (Boolean) -- `include_stream_metadata` (String) - `name` (String) - `network` (String) - `region` (String) @@ -34,6 +33,7 @@ Stream resource for QuickNode Streams API - `end_range` (Number) - `filter_function` (String) JavaScript function to filter and modify stream data. Must be base64 encoded. - `fix_block_reorgs` (Number) +- `include_stream_metadata` (String, Deprecated) - `keep_distance_from_tip` (Number) - `notification_email` (String) From 52e56b4e34d4348e2ef10457c2f218921e6e05c3 Mon Sep 17 00:00:00 2001 From: lwargin-circle Date: Tue, 21 Apr 2026 21:54:00 +0200 Subject: [PATCH 06/11] fix(ci): install Trivy from GitHub releases on restricted runners setup-trivy uses install.sh which fetches binaries via get.trivy.dev; Circle hosted runners hit curl exit 6 (host resolve). Install the release tarball from github.com and skip the composite setup step. Made-with: Cursor --- .github/workflows/test.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 000b20d..3aba72e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -58,9 +58,32 @@ jobs: contents: read steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + # setup-trivy's install.sh downloads from get.trivy.dev; some runners cannot resolve it (curl exit 6). + - name: Install Trivy from GitHub releases + shell: bash + env: + TRIVY_VERSION: '0.69.3' + RUNNER_ARCH: ${{ runner.arch }} + run: | + set -euo pipefail + case "$RUNNER_ARCH" in + X64) suffix='Linux-64bit' ;; + ARM64) suffix='Linux-ARM64' ;; + *) echo "unsupported runner.arch=$RUNNER_ARCH"; exit 1 ;; + esac + ver="v${TRIVY_VERSION}" + name="trivy_${TRIVY_VERSION}_${suffix}.tar.gz" + curl -fsSL "https://github.com/aquasecurity/trivy/releases/download/${ver}/${name}" -o trivy.tgz + tar -xzf trivy.tgz trivy + mkdir -p "$HOME/bin" + install -m 0755 trivy "$HOME/bin/trivy" + echo "$HOME/bin" >> "$GITHUB_PATH" + rm -f trivy trivy.tgz - name: Trivy Scan uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0 with: + skip-setup-trivy: true + version: v0.69.3 scan-type: fs scan-ref: '.' exit-code: '1' From 506554793dbe6478a4456672be0ec81798b1d0c8 Mon Sep 17 00:00:00 2001 From: lwargin-circle Date: Tue, 21 Apr 2026 22:00:47 +0200 Subject: [PATCH 07/11] fix(deps): bump google.golang.org/grpc to v1.79.3 (GO-2026-4762) Resolves authorization bypass reported by Trivy/govulncheck so CI trivy-scan passes with exit-code 1. Made-with: Cursor --- go.mod | 6 +++--- go.sum | 46 ++++++++++++++++++++++++++-------------------- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/go.mod b/go.mod index d698a9e..87430d0 100644 --- a/go.mod +++ b/go.mod @@ -101,9 +101,9 @@ require ( golang.org/x/text v0.32.0 // indirect golang.org/x/tools v0.40.0 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect - google.golang.org/grpc v1.72.1 // indirect - google.golang.org/protobuf v1.36.7 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect + google.golang.org/grpc v1.79.3 // indirect + google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect honnef.co/go/tools v0.6.1 // indirect diff --git a/go.sum b/go.sum index 63a7c1f..6bf10de 100644 --- a/go.sum +++ b/go.sum @@ -32,6 +32,8 @@ github.com/bmatcuk/doublestar/v4 v4.9.1 h1:X8jg9rRZmJd4yRy7ZeNDRnM+T3ZfHv15JiBJ/ github.com/bmatcuk/doublestar/v4 v4.9.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -63,8 +65,8 @@ github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+ github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= @@ -279,18 +281,18 @@ github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6 github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM= go.abhg.dev/goldmark/frontmatter v0.2.0 h1:P8kPG0YkL12+aYk2yU3xHv4tcXzeVnN+gU0tJ5JnxRw= go.abhg.dev/goldmark/frontmatter v0.2.0/go.mod h1:XqrEkZuM57djk7zrlRUB02x8I5J0px76YjkOzhB4YlU= -go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= -go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= -go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= -go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= -go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= -go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= -go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= -go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= -go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= -go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= -go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -367,17 +369,21 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= +golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= +golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ= -google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= -google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= +google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -386,8 +392,8 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= -google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= +google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 6dec937e0dda835a1f6f89ac6063e66ae3dc657c Mon Sep 17 00:00:00 2001 From: lwargin-circle Date: Tue, 21 Apr 2026 22:34:32 +0200 Subject: [PATCH 08/11] ci(trivy): vuln-only scan, artifact + summary; drop upload-sarif Code scanning UI is not available without GHAS; upload-sarif was misleading. Use scanners=vuln, exit-code 0 (non-blocking), upload SARIF as workflow artifact, and print a table to the job summary for review. Made-with: Cursor --- .github/workflows/test.yml | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3aba72e..32c5988 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -53,7 +53,6 @@ jobs: name: Trivy Scan runs-on: github-hosted-small permissions: - security-events: write actions: read contents: read steps: @@ -79,6 +78,9 @@ jobs: install -m 0755 trivy "$HOME/bin/trivy" echo "$HOME/bin" >> "$GITHUB_PATH" rm -f trivy trivy.tgz + # Without GitHub Advanced Security (code scanning), upload-sarif has nowhere useful in the UI. + # scanners=vuln: dependency CVEs only (secret scanner often false-positives on fixtures/docs). + # exit-code=0: do not block merges; review SARIF artifact + job summary instead. - name: Trivy Scan uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0 with: @@ -86,14 +88,30 @@ jobs: version: v0.69.3 scan-type: fs scan-ref: '.' - exit-code: '1' + scanners: vuln + exit-code: '0' output: trivy-results.sarif format: sarif - - name: Upload Trivy scan results to GitHub Security tab - uses: github/codeql-action/upload-sarif@f6091c0113d1dcf9b98e269ee48e8a7e51b7bdd4 # v3.28.5 + - name: Upload Trivy SARIF artifact if: always() + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 with: - sarif_file: 'trivy-results.sarif' + name: trivy-results + path: trivy-results.sarif + if-no-files-found: warn + - name: Trivy table (job summary) + if: always() + shell: bash + run: | + { + echo '### Trivy filesystem scan (vulnerabilities only)' + echo '' + echo 'Download **trivy-results** artifact for full SARIF.' + echo '' + echo '```' + trivy fs --scanners vuln --format table --severity UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL --exit-code 0 . + echo '```' + } >> "$GITHUB_STEP_SUMMARY" generate: runs-on: github-hosted-small From a611a81724a7d143d29be3f7831f9a97eb7e888a Mon Sep 17 00:00:00 2001 From: lwargin-circle Date: Tue, 21 Apr 2026 22:41:46 +0200 Subject: [PATCH 09/11] fix(deps): bump cloudflare/circl to v1.6.3 (CVE-2026-1229) Trivy reported LOW CVE in circl v1.6.1; fixed upstream in v1.6.3. Ignore local trivy-results.sarif; restore Trivy exit-code 1 on findings. Made-with: Cursor --- .github/workflows/test.yml | 5 ++--- .gitignore | 3 +++ go.mod | 2 +- go.sum | 4 ++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 32c5988..04fafdd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -78,9 +78,8 @@ jobs: install -m 0755 trivy "$HOME/bin/trivy" echo "$HOME/bin" >> "$GITHUB_PATH" rm -f trivy trivy.tgz - # Without GitHub Advanced Security (code scanning), upload-sarif has nowhere useful in the UI. + # No upload-sarif: org repo may not expose GitHub Code Scanning UI (GHAS). Artifact + summary below. # scanners=vuln: dependency CVEs only (secret scanner often false-positives on fixtures/docs). - # exit-code=0: do not block merges; review SARIF artifact + job summary instead. - name: Trivy Scan uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0 with: @@ -89,7 +88,7 @@ jobs: scan-type: fs scan-ref: '.' scanners: vuln - exit-code: '0' + exit-code: '1' output: trivy-results.sarif format: sarif - name: Upload Trivy SARIF artifact diff --git a/.gitignore b/.gitignore index fd3ad8e..d229160 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,9 @@ website/node_modules .terraform/ *.log *.bak + +# Local security scan output +trivy-results.sarif *~ .*.swp .idea diff --git a/go.mod b/go.mod index 87430d0..de11acf 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,7 @@ require ( github.com/bgentry/speakeasy v0.2.0 // indirect github.com/bmatcuk/doublestar/v4 v4.9.1 // indirect github.com/bufbuild/protocompile v0.14.1 // indirect - github.com/cloudflare/circl v1.6.1 // indirect + github.com/cloudflare/circl v1.6.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect github.com/fatih/color v1.18.0 // indirect diff --git a/go.sum b/go.sum index 6bf10de..de03d29 100644 --- a/go.sum +++ b/go.sum @@ -37,8 +37,8 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= -github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= +github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8= +github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From 0c135d7535a85cee9c7b8dcd6bea8b6f63195c27 Mon Sep 17 00:00:00 2001 From: lwargin-circle Date: Tue, 21 Apr 2026 22:44:46 +0200 Subject: [PATCH 10/11] chore(license): ignore protobuf compound SPDX in dependency review google.golang.org/protobuf is BSD-3-Clause plus Google's golang patent grant; ScanCode reports it as incompatible without allowlisting, same as golang.org/x modules already listed here. Made-with: Cursor --- .licenseignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.licenseignore b/.licenseignore index 8e9ad42..be9db78 100644 --- a/.licenseignore +++ b/.licenseignore @@ -5,6 +5,7 @@ pkg:golang/github.com/hashicorp/terraform-registry-address@v0.2.5 # License scanner doesn't understand compound licenses: # License: BSD-3-Clause AND LicenseRef-scancode-google-patent-license-golang +pkg:golang/google.golang.org/protobuf pkg:golang/golang.org/x/crypto pkg:golang/golang.org/x/mod pkg:golang/golang.org/x/net From ac13072d4451749bc51a438abd13397b1bd13491 Mon Sep 17 00:00:00 2001 From: lwargin-circle Date: Tue, 21 Apr 2026 22:51:16 +0200 Subject: [PATCH 11/11] ci(trivy): upload SARIF artifact only for private repositories Public workflow artifacts are downloadable by anyone; keep the job summary table for public repos and attach SARIF only when private. Made-with: Cursor --- .github/workflows/test.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 04fafdd..687e232 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -91,8 +91,10 @@ jobs: exit-code: '1' output: trivy-results.sarif format: sarif + # On public repos, workflow artifacts are world-readable; SARIF is low-risk (same as go.mod+CVE DB) + # but we only attach it for private repos. Public: table in job summary only. - name: Upload Trivy SARIF artifact - if: always() + if: always() && github.event.repository.private uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 with: name: trivy-results @@ -105,7 +107,11 @@ jobs: { echo '### Trivy filesystem scan (vulnerabilities only)' echo '' - echo 'Download **trivy-results** artifact for full SARIF.' + if [[ "${{ github.event.repository.private }}" == "true" ]]; then + echo 'Full SARIF: workflow artifact **trivy-results** (private repo only).' + else + echo 'Public repo: no SARIF artifact (artifacts are public). Table below matches dependency scan.' + fi echo '' echo '```' trivy fs --scanners vuln --format table --severity UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL --exit-code 0 .