feat: webhook system with retain.completed event, UI, and docs (#487)
* doc: update cookbook
* fix(cookbook): preserve tag keys during sync, strip local .md links
- Fix extract_tags_from_readme/notebook to return dict[str,str] preserving
sdk/topic keys instead of bare values, preventing topics like
"Customer Service" from being misclassified as SDK
- Add strip_local_md_links() to remove relative .md references that
would cause broken link errors in Docusaurus build
* ci: run test-doc-examples independently without waiting for test-rust-cli
Build the CLI directly in the job instead of downloading the artifact,
so test-doc-examples can start at the beginning in parallel with all other jobs.
* feat: webhook system with task-owned retry, retain.completed event, and UI
- New webhook system: register per-bank webhooks with HMAC signing, configurable
HTTP method/timeout/headers/params (http_config JSONB), and PATCH support
- Webhook deliveries run as async_operations (webhook_delivery type) with
task-owned retry via RetryTaskAt exception and exponential backoff
(60s / 5m / 30m / 2h / 8h, max 6 attempts)
- New retain.completed event fires per-document for both sync and async retain
- Delivery debug info (status code, response body) stored in result_metadata
- Control plane UI: webhooks tab per bank with create/edit/delete and a
deliveries table with cursor pagination and expandable response details
- 28 webhook tests covering HMAC signing, delivery retries, CRUD endpoints,
PATCH update, and retain.completed queuing
- Docs page at developer/api/webhooks documenting event payloads and delivery
- OpenAPI spec and all client SDKs (Python, TypeScript, Rust, Go) regenerated
* fix: update tests for task-owned retry model and guard _webhook_manager attribute
- test_worker.py: test_executor_exception_triggers_retry now raises RetryTaskAt
(plain exceptions are immediate failures in the new system); rename
test_executor_exception_marks_failed_after_max_retries to
test_executor_exception_marks_failed_immediately to reflect new semantics
- test_batch_api.py: remove max_retries kwarg from WorkerPoller constructor
- memory_engine.py: use getattr for _webhook_manager in _fire_retain_webhook
to avoid AttributeError when engine is created without __init__ (tests)
* fix: remove max_retries from benchmark WorkerPoller call
* fix(webhooks): transactional outbox, observations_deleted tracking, sidebar
- Queue webhook delivery rows atomically with the primary operation using the
transactional outbox pattern — prevents lost events on process crash:
- Retain (sync + async): outbox_callback passed into orchestrator.retain_batch
and called inside the DB transaction, replacing the post-commit fire call
- Consolidation: new _mark_operation_completed_and_fire_webhook combines the
status UPDATE and webhook INSERT in one transaction
- Added fire_event_with_conn() to WebhookManager for in-connection delivery
- Track observations_deleted count in consolidation stats and expose it in the
consolidation.completed webhook payload (was always None)
- Add Webhooks page to docs sidebar
- Document at-least-once delivery guarantee with operation_id dedup guidance
* fix(ui): add retain.completed to available webhook event types
* feat(ui): add delete confirmation dialog for webhooks
* fix(webhooks): include operation_id in task_payload so delivery is marked completed
The task_payload JSON was missing the operation_id field, causing execute_task
to see operation_id=None and skip _mark_operation_completed — leaving every
delivery row stuck in 'pending' forever.
Added a test that inserts a real async_operations row and verifies the status
transitions to 'completed' after a successful execute_task call.
* style: fix prettier formatting in webhooks-view
This commit is contained in:
parent
51d2fc5309
commit
abbf874d84
52 changed files with 10727 additions and 80 deletions
|
|
@ -0,0 +1,62 @@
|
|||
"""Add webhooks table and next_retry_at to async_operations.
|
||||
|
||||
Webhook deliveries are handled as async_operations tasks (operation_type='webhook_delivery')
|
||||
rather than a dedicated webhook_deliveries table.
|
||||
|
||||
Revision ID: e4f5a6b7c8d9
|
||||
Revises: d2e3f4a5b6c7
|
||||
Create Date: 2026-03-04
|
||||
"""
|
||||
|
||||
from collections.abc import Sequence
|
||||
|
||||
from alembic import context, op
|
||||
|
||||
revision: str = "e4f5a6b7c8d9"
|
||||
down_revision: str | Sequence[str] | None = "d2e3f4a5b6c7"
|
||||
branch_labels: str | Sequence[str] | None = None
|
||||
depends_on: str | Sequence[str] | None = None
|
||||
|
||||
|
||||
def _get_schema_prefix() -> str:
|
||||
schema = context.config.get_main_option("target_schema")
|
||||
return f'"{schema}".' if schema else ""
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
schema = _get_schema_prefix()
|
||||
|
||||
op.execute(
|
||||
f"""
|
||||
CREATE TABLE IF NOT EXISTS {schema}webhooks (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
bank_id TEXT,
|
||||
url TEXT NOT NULL,
|
||||
secret TEXT,
|
||||
event_types TEXT[] NOT NULL DEFAULT '{{}}',
|
||||
enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
)
|
||||
"""
|
||||
)
|
||||
|
||||
# Index for bank-scoped webhook lookup
|
||||
op.execute(f"CREATE INDEX IF NOT EXISTS idx_webhooks_bank_id ON {schema}webhooks(bank_id)")
|
||||
|
||||
# Add next_retry_at to async_operations for task-owned retry scheduling
|
||||
op.execute(f"ALTER TABLE {schema}async_operations ADD COLUMN IF NOT EXISTS next_retry_at TIMESTAMPTZ NULL")
|
||||
|
||||
# Index for polling: status + next_retry_at
|
||||
op.execute(
|
||||
f"CREATE INDEX IF NOT EXISTS idx_async_operations_status_retry "
|
||||
f"ON {schema}async_operations(status, next_retry_at)"
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
schema = _get_schema_prefix()
|
||||
op.execute(f"DROP INDEX IF EXISTS {schema}idx_async_operations_status_retry")
|
||||
op.execute(f"ALTER TABLE {schema}async_operations DROP COLUMN IF EXISTS next_retry_at")
|
||||
op.execute(f"DROP INDEX IF EXISTS {schema}idx_webhooks_bank_id")
|
||||
op.execute(f"DROP TABLE IF EXISTS {schema}webhooks")
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
"""Add http_config JSONB column to webhooks table.
|
||||
|
||||
Stores HTTP delivery configuration (method, timeout, headers, params) as a
|
||||
single JSONB column rather than separate columns.
|
||||
|
||||
Revision ID: f7g8h9i0j1k2
|
||||
Revises: e4f5a6b7c8d9
|
||||
Create Date: 2026-03-04
|
||||
"""
|
||||
|
||||
from collections.abc import Sequence
|
||||
|
||||
from alembic import context, op
|
||||
|
||||
revision: str = "f7g8h9i0j1k2"
|
||||
down_revision: str | Sequence[str] | None = "e4f5a6b7c8d9"
|
||||
branch_labels: str | Sequence[str] | None = None
|
||||
depends_on: str | Sequence[str] | None = None
|
||||
|
||||
|
||||
def _get_schema_prefix() -> str:
|
||||
schema = context.config.get_main_option("target_schema")
|
||||
return f'"{schema}".' if schema else ""
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
schema = _get_schema_prefix()
|
||||
op.execute(f"ALTER TABLE {schema}webhooks ADD COLUMN IF NOT EXISTS http_config JSONB NOT NULL DEFAULT '{{}}'")
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
schema = _get_schema_prefix()
|
||||
op.execute(f"ALTER TABLE {schema}webhooks DROP COLUMN IF EXISTS http_config")
|
||||
|
|
@ -1627,6 +1627,123 @@ class VersionResponse(BaseModel):
|
|||
features: FeaturesInfo = Field(description="Enabled feature flags")
|
||||
|
||||
|
||||
# =========================================================================
|
||||
# Webhook Models
|
||||
# =========================================================================
|
||||
|
||||
|
||||
from hindsight_api.webhooks.models import WebhookHttpConfig
|
||||
|
||||
|
||||
class CreateWebhookRequest(BaseModel):
|
||||
"""Request model for registering a webhook."""
|
||||
|
||||
url: str = Field(description="HTTP(S) endpoint URL to deliver events to")
|
||||
secret: str | None = Field(default=None, description="HMAC-SHA256 signing secret (optional)")
|
||||
event_types: list[str] = Field(
|
||||
default=["consolidation.completed"],
|
||||
description="List of event types to deliver. Currently supported: 'consolidation.completed'",
|
||||
)
|
||||
enabled: bool = Field(default=True, description="Whether this webhook is active")
|
||||
http_config: WebhookHttpConfig = Field(
|
||||
default_factory=WebhookHttpConfig,
|
||||
description="HTTP delivery configuration (method, timeout, headers, params)",
|
||||
)
|
||||
|
||||
|
||||
class WebhookResponse(BaseModel):
|
||||
"""Response model for a webhook."""
|
||||
|
||||
id: str
|
||||
bank_id: str | None
|
||||
url: str
|
||||
secret: str | None = Field(default=None, description="Signing secret (redacted in responses)")
|
||||
event_types: list[str]
|
||||
enabled: bool
|
||||
http_config: WebhookHttpConfig = Field(default_factory=WebhookHttpConfig)
|
||||
created_at: str | None = None
|
||||
updated_at: str | None = None
|
||||
|
||||
|
||||
class UpdateWebhookRequest(BaseModel):
|
||||
"""Request model for updating a webhook. Only provided fields are updated."""
|
||||
|
||||
url: str | None = Field(default=None, description="HTTP(S) endpoint URL")
|
||||
secret: str | None = Field(
|
||||
default=None, description="HMAC-SHA256 signing secret. Omit to keep existing; send null to clear."
|
||||
)
|
||||
event_types: list[str] | None = Field(default=None, description="List of event types")
|
||||
enabled: bool | None = Field(default=None, description="Whether this webhook is active")
|
||||
http_config: WebhookHttpConfig | None = Field(default=None, description="HTTP delivery configuration")
|
||||
|
||||
|
||||
class WebhookListResponse(BaseModel):
|
||||
"""Response model for listing webhooks."""
|
||||
|
||||
items: list[WebhookResponse]
|
||||
|
||||
|
||||
class WebhookDeliveryResponse(BaseModel):
|
||||
"""Response model for a webhook delivery record."""
|
||||
|
||||
id: str
|
||||
webhook_id: str | None
|
||||
url: str
|
||||
event_type: str
|
||||
status: str
|
||||
attempts: int
|
||||
next_retry_at: str | None = None
|
||||
last_error: str | None = None
|
||||
last_response_status: int | None = None
|
||||
last_response_body: str | None = None
|
||||
last_attempt_at: str | None = None
|
||||
created_at: str | None = None
|
||||
updated_at: str | None = None
|
||||
|
||||
@classmethod
|
||||
def from_async_operation_row(cls, row: dict) -> "WebhookDeliveryResponse":
|
||||
import json as _json
|
||||
|
||||
raw = row["task_payload"]
|
||||
if isinstance(raw, str):
|
||||
task_payload = _json.loads(raw)
|
||||
elif isinstance(raw, dict):
|
||||
task_payload = raw
|
||||
else:
|
||||
task_payload = {}
|
||||
|
||||
raw_meta = row.get("result_metadata")
|
||||
if isinstance(raw_meta, str):
|
||||
result_metadata = _json.loads(raw_meta) if raw_meta else {}
|
||||
elif isinstance(raw_meta, dict):
|
||||
result_metadata = raw_meta
|
||||
else:
|
||||
result_metadata = {}
|
||||
|
||||
return cls(
|
||||
id=str(row["operation_id"]),
|
||||
webhook_id=task_payload.get("webhook_id"),
|
||||
url=task_payload.get("url", ""),
|
||||
event_type=task_payload.get("event_type", ""),
|
||||
status=row["status"],
|
||||
attempts=row["retry_count"] + 1,
|
||||
next_retry_at=row["next_retry_at"],
|
||||
last_error=row["error_message"],
|
||||
last_response_status=result_metadata.get("last_status_code"),
|
||||
last_response_body=result_metadata.get("last_response_body"),
|
||||
last_attempt_at=result_metadata.get("last_attempt_at"),
|
||||
created_at=row["created_at"],
|
||||
updated_at=row["updated_at"],
|
||||
)
|
||||
|
||||
|
||||
class WebhookDeliveryListResponse(BaseModel):
|
||||
"""Response model for listing webhook deliveries."""
|
||||
|
||||
items: list[WebhookDeliveryResponse]
|
||||
next_cursor: str | None = None
|
||||
|
||||
|
||||
def create_app(
|
||||
memory: MemoryEngine,
|
||||
initialize_memory: bool = True,
|
||||
|
|
@ -1726,7 +1843,6 @@ def create_app(
|
|||
worker_id=worker_id,
|
||||
executor=memory.execute_task,
|
||||
poll_interval_ms=config.worker_poll_interval_ms,
|
||||
max_retries=config.worker_max_retries,
|
||||
schema=schema,
|
||||
tenant_extension=memory._tenant_extension,
|
||||
max_slots=config.worker_max_slots,
|
||||
|
|
@ -3756,6 +3872,318 @@ def _register_routes(app: FastAPI):
|
|||
logger.error(f"Error in POST /v1/default/banks/{bank_id}/consolidate: {error_detail}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
# =========================================================================
|
||||
# Webhook Endpoints
|
||||
# =========================================================================
|
||||
|
||||
@app.post(
|
||||
"/v1/default/banks/{bank_id}/webhooks",
|
||||
response_model=WebhookResponse,
|
||||
summary="Register webhook",
|
||||
description="Register a webhook endpoint to receive event notifications for this bank.",
|
||||
operation_id="create_webhook",
|
||||
tags=["Webhooks"],
|
||||
status_code=201,
|
||||
)
|
||||
async def api_create_webhook(
|
||||
bank_id: str,
|
||||
request: CreateWebhookRequest,
|
||||
request_context: RequestContext = Depends(get_request_context),
|
||||
):
|
||||
"""Register a webhook for a bank."""
|
||||
try:
|
||||
pool = await app.state.memory._get_pool()
|
||||
from hindsight_api.engine.memory_engine import fq_table
|
||||
|
||||
webhook_id = uuid.uuid4()
|
||||
now = datetime.utcnow().isoformat() + "Z"
|
||||
row = await pool.fetchrow(
|
||||
f"""
|
||||
INSERT INTO {fq_table("webhooks")}
|
||||
(id, bank_id, url, secret, event_types, enabled, http_config, created_at, updated_at)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb, NOW(), NOW())
|
||||
RETURNING id, bank_id, url, secret, event_types, enabled,
|
||||
http_config::text, created_at::text, updated_at::text
|
||||
""",
|
||||
webhook_id,
|
||||
bank_id,
|
||||
request.url,
|
||||
request.secret,
|
||||
request.event_types,
|
||||
request.enabled,
|
||||
request.http_config.model_dump_json(),
|
||||
)
|
||||
return WebhookResponse(
|
||||
id=str(row["id"]),
|
||||
bank_id=row["bank_id"],
|
||||
url=row["url"],
|
||||
secret=None, # Never return secret in responses
|
||||
event_types=list(row["event_types"]) if row["event_types"] else [],
|
||||
enabled=row["enabled"],
|
||||
http_config=WebhookHttpConfig.model_validate_json(row["http_config"])
|
||||
if row["http_config"]
|
||||
else WebhookHttpConfig(),
|
||||
created_at=row["created_at"],
|
||||
updated_at=row["updated_at"],
|
||||
)
|
||||
except (AuthenticationError, HTTPException):
|
||||
raise
|
||||
except Exception as e:
|
||||
import traceback
|
||||
|
||||
error_detail = f"{str(e)}\n\nTraceback:\n{traceback.format_exc()}"
|
||||
logger.error(f"Error in POST /v1/default/banks/{bank_id}/webhooks: {error_detail}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.get(
|
||||
"/v1/default/banks/{bank_id}/webhooks",
|
||||
response_model=WebhookListResponse,
|
||||
summary="List webhooks",
|
||||
description="List all webhooks registered for a bank.",
|
||||
operation_id="list_webhooks",
|
||||
tags=["Webhooks"],
|
||||
)
|
||||
async def api_list_webhooks(
|
||||
bank_id: str,
|
||||
request_context: RequestContext = Depends(get_request_context),
|
||||
):
|
||||
"""List webhooks for a bank."""
|
||||
try:
|
||||
pool = await app.state.memory._get_pool()
|
||||
from hindsight_api.engine.memory_engine import fq_table
|
||||
|
||||
rows = await pool.fetch(
|
||||
f"""
|
||||
SELECT id, bank_id, url, secret, event_types, enabled,
|
||||
http_config::text, created_at::text, updated_at::text
|
||||
FROM {fq_table("webhooks")}
|
||||
WHERE bank_id = $1
|
||||
ORDER BY created_at
|
||||
""",
|
||||
bank_id,
|
||||
)
|
||||
return WebhookListResponse(
|
||||
items=[
|
||||
WebhookResponse(
|
||||
id=str(row["id"]),
|
||||
bank_id=row["bank_id"],
|
||||
url=row["url"],
|
||||
secret=None, # Never return secret in responses
|
||||
event_types=list(row["event_types"]) if row["event_types"] else [],
|
||||
enabled=row["enabled"],
|
||||
http_config=WebhookHttpConfig.model_validate_json(row["http_config"])
|
||||
if row["http_config"]
|
||||
else WebhookHttpConfig(),
|
||||
created_at=row["created_at"],
|
||||
updated_at=row["updated_at"],
|
||||
)
|
||||
for row in rows
|
||||
]
|
||||
)
|
||||
except (AuthenticationError, HTTPException):
|
||||
raise
|
||||
except Exception as e:
|
||||
import traceback
|
||||
|
||||
error_detail = f"{str(e)}\n\nTraceback:\n{traceback.format_exc()}"
|
||||
logger.error(f"Error in GET /v1/default/banks/{bank_id}/webhooks: {error_detail}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.delete(
|
||||
"/v1/default/banks/{bank_id}/webhooks/{webhook_id}",
|
||||
response_model=DeleteResponse,
|
||||
summary="Delete webhook",
|
||||
description="Remove a registered webhook.",
|
||||
operation_id="delete_webhook",
|
||||
tags=["Webhooks"],
|
||||
)
|
||||
async def api_delete_webhook(
|
||||
bank_id: str,
|
||||
webhook_id: str,
|
||||
request_context: RequestContext = Depends(get_request_context),
|
||||
):
|
||||
"""Delete a webhook."""
|
||||
try:
|
||||
pool = await app.state.memory._get_pool()
|
||||
from hindsight_api.engine.memory_engine import fq_table
|
||||
|
||||
result = await pool.execute(
|
||||
f"DELETE FROM {fq_table('webhooks')} WHERE id = $1 AND bank_id = $2",
|
||||
uuid.UUID(webhook_id),
|
||||
bank_id,
|
||||
)
|
||||
deleted = int(result.split()[-1]) if result else 0
|
||||
if deleted == 0:
|
||||
raise HTTPException(status_code=404, detail="Webhook not found")
|
||||
return DeleteResponse(success=True)
|
||||
except (AuthenticationError, HTTPException):
|
||||
raise
|
||||
except Exception as e:
|
||||
import traceback
|
||||
|
||||
error_detail = f"{str(e)}\n\nTraceback:\n{traceback.format_exc()}"
|
||||
logger.error(f"Error in DELETE /v1/default/banks/{bank_id}/webhooks/{webhook_id}: {error_detail}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.patch(
|
||||
"/v1/default/banks/{bank_id}/webhooks/{webhook_id}",
|
||||
response_model=WebhookResponse,
|
||||
summary="Update webhook",
|
||||
description="Update one or more fields of a registered webhook. Only provided fields are changed.",
|
||||
operation_id="update_webhook",
|
||||
tags=["Webhooks"],
|
||||
)
|
||||
async def api_update_webhook(
|
||||
bank_id: str,
|
||||
webhook_id: str,
|
||||
request: UpdateWebhookRequest,
|
||||
request_context: RequestContext = Depends(get_request_context),
|
||||
):
|
||||
"""Update a webhook's fields (PATCH semantics — only sent fields are updated)."""
|
||||
try:
|
||||
pool = await app.state.memory._get_pool()
|
||||
from hindsight_api.engine.memory_engine import fq_table
|
||||
|
||||
set_clauses: list[str] = []
|
||||
params: list = [uuid.UUID(webhook_id), bank_id]
|
||||
|
||||
fields = request.model_fields_set
|
||||
if "url" in fields:
|
||||
params.append(request.url)
|
||||
set_clauses.append(f"url = ${len(params)}")
|
||||
if "secret" in fields:
|
||||
params.append(request.secret)
|
||||
set_clauses.append(f"secret = ${len(params)}")
|
||||
if "event_types" in fields:
|
||||
params.append(request.event_types)
|
||||
set_clauses.append(f"event_types = ${len(params)}")
|
||||
if "enabled" in fields:
|
||||
params.append(request.enabled)
|
||||
set_clauses.append(f"enabled = ${len(params)}")
|
||||
if "http_config" in fields:
|
||||
params.append(request.http_config.model_dump_json())
|
||||
set_clauses.append(f"http_config = ${len(params)}::jsonb")
|
||||
|
||||
if not set_clauses:
|
||||
raise HTTPException(status_code=422, detail="No fields provided to update")
|
||||
|
||||
set_clauses.append("updated_at = NOW()")
|
||||
row = await pool.fetchrow(
|
||||
f"""
|
||||
UPDATE {fq_table("webhooks")}
|
||||
SET {", ".join(set_clauses)}
|
||||
WHERE id = $1 AND bank_id = $2
|
||||
RETURNING id, bank_id, url, secret, event_types, enabled,
|
||||
http_config::text, created_at::text, updated_at::text
|
||||
""",
|
||||
*params,
|
||||
)
|
||||
if not row:
|
||||
raise HTTPException(status_code=404, detail="Webhook not found")
|
||||
return WebhookResponse(
|
||||
id=str(row["id"]),
|
||||
bank_id=row["bank_id"],
|
||||
url=row["url"],
|
||||
secret=None,
|
||||
event_types=list(row["event_types"]) if row["event_types"] else [],
|
||||
enabled=row["enabled"],
|
||||
http_config=WebhookHttpConfig.model_validate_json(row["http_config"])
|
||||
if row["http_config"]
|
||||
else WebhookHttpConfig(),
|
||||
created_at=row["created_at"],
|
||||
updated_at=row["updated_at"],
|
||||
)
|
||||
except (AuthenticationError, HTTPException):
|
||||
raise
|
||||
except Exception as e:
|
||||
import traceback
|
||||
|
||||
error_detail = f"{str(e)}\n\nTraceback:\n{traceback.format_exc()}"
|
||||
logger.error(f"Error in PATCH /v1/default/banks/{bank_id}/webhooks/{webhook_id}: {error_detail}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.get(
|
||||
"/v1/default/banks/{bank_id}/webhooks/{webhook_id}/deliveries",
|
||||
response_model=WebhookDeliveryListResponse,
|
||||
summary="List webhook deliveries",
|
||||
description="Inspect delivery history for a webhook (useful for debugging).",
|
||||
operation_id="list_webhook_deliveries",
|
||||
tags=["Webhooks"],
|
||||
)
|
||||
async def api_list_webhook_deliveries(
|
||||
bank_id: str,
|
||||
webhook_id: str,
|
||||
limit: int = Query(default=50, le=200, description="Maximum number of deliveries to return"),
|
||||
cursor: str | None = Query(default=None, description="Pagination cursor (created_at of last item)"),
|
||||
request_context: RequestContext = Depends(get_request_context),
|
||||
):
|
||||
"""List deliveries for a specific webhook, newest first. Use next_cursor for pagination."""
|
||||
try:
|
||||
pool = await app.state.memory._get_pool()
|
||||
from hindsight_api.engine.memory_engine import fq_table
|
||||
|
||||
# Verify webhook belongs to this bank
|
||||
webhook_row = await pool.fetchrow(
|
||||
f"SELECT id FROM {fq_table('webhooks')} WHERE id = $1 AND bank_id = $2",
|
||||
uuid.UUID(webhook_id),
|
||||
bank_id,
|
||||
)
|
||||
if not webhook_row:
|
||||
raise HTTPException(status_code=404, detail="Webhook not found")
|
||||
|
||||
# Fetch limit+1 to detect if there's a next page
|
||||
fetch_limit = limit + 1
|
||||
if cursor:
|
||||
rows = await pool.fetch(
|
||||
f"""
|
||||
SELECT operation_id, status, retry_count, next_retry_at::text,
|
||||
error_message, task_payload, result_metadata::text, created_at::text, updated_at::text
|
||||
FROM {fq_table("async_operations")}
|
||||
WHERE operation_type = 'webhook_delivery'
|
||||
AND bank_id = $1
|
||||
AND task_payload->>'webhook_id' = $2
|
||||
AND created_at < $3::timestamptz
|
||||
ORDER BY created_at DESC
|
||||
LIMIT $4
|
||||
""",
|
||||
bank_id,
|
||||
webhook_id,
|
||||
cursor,
|
||||
fetch_limit,
|
||||
)
|
||||
else:
|
||||
rows = await pool.fetch(
|
||||
f"""
|
||||
SELECT operation_id, status, retry_count, next_retry_at::text,
|
||||
error_message, task_payload, result_metadata::text, created_at::text, updated_at::text
|
||||
FROM {fq_table("async_operations")}
|
||||
WHERE operation_type = 'webhook_delivery'
|
||||
AND bank_id = $1
|
||||
AND task_payload->>'webhook_id' = $2
|
||||
ORDER BY created_at DESC
|
||||
LIMIT $3
|
||||
""",
|
||||
bank_id,
|
||||
webhook_id,
|
||||
fetch_limit,
|
||||
)
|
||||
|
||||
has_more = len(rows) > limit
|
||||
page = rows[:limit]
|
||||
next_cursor = page[-1]["created_at"] if has_more and page else None
|
||||
return WebhookDeliveryListResponse(
|
||||
items=[WebhookDeliveryResponse.from_async_operation_row(dict(row)) for row in page],
|
||||
next_cursor=next_cursor,
|
||||
)
|
||||
except (AuthenticationError, HTTPException):
|
||||
raise
|
||||
except Exception as e:
|
||||
import traceback
|
||||
|
||||
error_detail = f"{str(e)}\n\nTraceback:\n{traceback.format_exc()}"
|
||||
logger.error(f"Error in GET /v1/default/banks/{bank_id}/webhooks/{webhook_id}/deliveries: {error_detail}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.post(
|
||||
"/v1/default/banks/{bank_id}/memories",
|
||||
response_model=RetainResponse,
|
||||
|
|
@ -3848,6 +4276,12 @@ def _register_routes(app: FastAPI):
|
|||
document_tags=request.document_tags,
|
||||
request_context=request_context,
|
||||
return_usage=True,
|
||||
outbox_callback=app.state.memory._build_retain_outbox_callback(
|
||||
bank_id=bank_id,
|
||||
contents=contents,
|
||||
operation_id=None,
|
||||
schema=request_context.tenant_id,
|
||||
),
|
||||
)
|
||||
|
||||
return RetainResponse.model_validate(
|
||||
|
|
|
|||
|
|
@ -294,6 +294,12 @@ ENV_CONSOLIDATION_LLM_BATCH_SIZE = "HINDSIGHT_API_CONSOLIDATION_LLM_BATCH_SIZE"
|
|||
ENV_CONSOLIDATION_MAX_TOKENS = "HINDSIGHT_API_CONSOLIDATION_MAX_TOKENS"
|
||||
ENV_OBSERVATIONS_MISSION = "HINDSIGHT_API_OBSERVATIONS_MISSION"
|
||||
|
||||
# Webhook configuration (global, static - server-level only)
|
||||
ENV_WEBHOOK_URL = "HINDSIGHT_API_WEBHOOK_URL"
|
||||
ENV_WEBHOOK_SECRET = "HINDSIGHT_API_WEBHOOK_SECRET"
|
||||
ENV_WEBHOOK_EVENT_TYPES = "HINDSIGHT_API_WEBHOOK_EVENT_TYPES"
|
||||
ENV_WEBHOOK_DELIVERY_POLL_INTERVAL_SECONDS = "HINDSIGHT_API_WEBHOOK_DELIVERY_POLL_INTERVAL_SECONDS"
|
||||
|
||||
# Optimization flags
|
||||
ENV_SKIP_LLM_VERIFICATION = "HINDSIGHT_API_SKIP_LLM_VERIFICATION"
|
||||
ENV_LAZY_RERANKER = "HINDSIGHT_API_LAZY_RERANKER"
|
||||
|
|
@ -497,6 +503,12 @@ Use this tool PROACTIVELY to:
|
|||
# Default embedding dimension (used by initial migration, adjusted at runtime)
|
||||
EMBEDDING_DIMENSION = DEFAULT_EMBEDDING_DIMENSION
|
||||
|
||||
# Webhook configuration defaults
|
||||
DEFAULT_WEBHOOK_URL = None # None = no global webhook configured
|
||||
DEFAULT_WEBHOOK_SECRET = None # None = no signing
|
||||
DEFAULT_WEBHOOK_EVENT_TYPES = "consolidation.completed" # Comma-separated; default = all supported events
|
||||
DEFAULT_WEBHOOK_DELIVERY_POLL_INTERVAL_SECONDS = 30 # How often to poll for pending deliveries
|
||||
|
||||
|
||||
class JsonFormatter(logging.Formatter):
|
||||
"""JSON formatter for structured logging.
|
||||
|
|
@ -750,6 +762,12 @@ class HindsightConfig:
|
|||
otel_service_name: str
|
||||
otel_deployment_environment: str
|
||||
|
||||
# Webhook configuration (static - server-level only, not per-bank)
|
||||
webhook_url: str | None # Global webhook URL (None = disabled)
|
||||
webhook_secret: str | None # HMAC signing secret (None = unsigned)
|
||||
webhook_event_types: list[str] # Event types to deliver globally
|
||||
webhook_delivery_poll_interval_seconds: int # How often the delivery worker polls
|
||||
|
||||
# Class-level sets for configuration categorization
|
||||
|
||||
# CREDENTIAL_FIELDS: Never exposed via API, never configurable per-tenant/bank
|
||||
|
|
@ -1187,6 +1205,20 @@ class HindsightConfig:
|
|||
otel_exporter_otlp_headers=os.getenv(ENV_OTEL_EXPORTER_OTLP_HEADERS) or None,
|
||||
otel_service_name=os.getenv(ENV_OTEL_SERVICE_NAME, DEFAULT_OTEL_SERVICE_NAME),
|
||||
otel_deployment_environment=os.getenv(ENV_OTEL_DEPLOYMENT_ENVIRONMENT, DEFAULT_OTEL_DEPLOYMENT_ENVIRONMENT),
|
||||
# Webhook configuration (static, server-level only)
|
||||
webhook_url=os.getenv(ENV_WEBHOOK_URL) or DEFAULT_WEBHOOK_URL,
|
||||
webhook_secret=os.getenv(ENV_WEBHOOK_SECRET) or DEFAULT_WEBHOOK_SECRET,
|
||||
webhook_event_types=[
|
||||
t.strip()
|
||||
for t in os.getenv(ENV_WEBHOOK_EVENT_TYPES, DEFAULT_WEBHOOK_EVENT_TYPES).split(",")
|
||||
if t.strip()
|
||||
],
|
||||
webhook_delivery_poll_interval_seconds=int(
|
||||
os.getenv(
|
||||
ENV_WEBHOOK_DELIVERY_POLL_INTERVAL_SECONDS,
|
||||
str(DEFAULT_WEBHOOK_DELIVERY_POLL_INTERVAL_SECONDS),
|
||||
)
|
||||
),
|
||||
)
|
||||
config.validate()
|
||||
return config
|
||||
|
|
|
|||
|
|
@ -180,11 +180,12 @@ async def run_consolidation_job(
|
|||
perf.log(f"[1] Found {total_count} pending memories to consolidate")
|
||||
|
||||
# Process each memory with individual commits for crash recovery
|
||||
stats = {
|
||||
stats: dict[str, int] = {
|
||||
"memories_processed": 0,
|
||||
"observations_created": 0,
|
||||
"observations_updated": 0,
|
||||
"observations_merged": 0,
|
||||
"observations_deleted": 0,
|
||||
"actions_executed": 0,
|
||||
"skipped": 0,
|
||||
}
|
||||
|
|
@ -273,11 +274,12 @@ async def run_consolidation_job(
|
|||
# explicit list[list[str]]
|
||||
obs_tags_list = _obs_parsed
|
||||
|
||||
batch_deleted: int = 0
|
||||
if obs_tags_list:
|
||||
# Multi-pass: run one observation consolidation pass per tag set
|
||||
results = []
|
||||
for obs_tags in obs_tags_list:
|
||||
pass_results = await _process_memory_batch(
|
||||
pass_results, pass_deleted = await _process_memory_batch(
|
||||
conn=conn,
|
||||
memory_engine=memory_engine,
|
||||
llm_config=llm_config,
|
||||
|
|
@ -288,6 +290,7 @@ async def run_consolidation_job(
|
|||
config=config,
|
||||
obs_tags_override=obs_tags,
|
||||
)
|
||||
batch_deleted += pass_deleted
|
||||
# Merge results: prefer non-skipped actions
|
||||
if not results:
|
||||
results = pass_results
|
||||
|
|
@ -315,7 +318,7 @@ async def run_consolidation_job(
|
|||
}
|
||||
else:
|
||||
# Normal single pass using the memory's own tags
|
||||
results = await _process_memory_batch(
|
||||
results, batch_deleted = await _process_memory_batch(
|
||||
conn=conn,
|
||||
memory_engine=memory_engine,
|
||||
llm_config=llm_config,
|
||||
|
|
@ -325,6 +328,7 @@ async def run_consolidation_job(
|
|||
perf=perf,
|
||||
config=config,
|
||||
)
|
||||
stats["observations_deleted"] += batch_deleted
|
||||
|
||||
await conn.executemany(
|
||||
f"UPDATE {fq_table('memory_units')} SET consolidated_at = NOW() WHERE id = $1",
|
||||
|
|
@ -521,7 +525,7 @@ async def _process_memory_batch(
|
|||
perf: ConsolidationPerfLog | None = None,
|
||||
config: Any = None,
|
||||
obs_tags_override: list[str] | None = None,
|
||||
) -> list[dict[str, Any]]:
|
||||
) -> tuple[list[dict[str, Any]], int]:
|
||||
"""
|
||||
Process a batch of memories in a single LLM call.
|
||||
|
||||
|
|
@ -656,6 +660,7 @@ async def _process_memory_batch(
|
|||
for m in source_mems:
|
||||
per_memory_updated.add(str(m["id"]))
|
||||
|
||||
deleted_count = 0
|
||||
for delete in llm_result.deletes:
|
||||
# Security: the observation must be present in the unioned recall
|
||||
if not any(str(obs.id) == delete.observation_id for obs in union_observations):
|
||||
|
|
@ -664,6 +669,7 @@ async def _process_memory_batch(
|
|||
)
|
||||
continue
|
||||
await _execute_delete_action(conn=conn, bank_id=bank_id, observation_id=delete.observation_id)
|
||||
deleted_count += 1
|
||||
|
||||
# Build per-memory result dicts for the stats tracker in the outer loop
|
||||
results: list[dict[str, Any]] = []
|
||||
|
|
@ -680,7 +686,7 @@ async def _process_memory_batch(
|
|||
else:
|
||||
results.append({"action": "skipped", "reason": "no_durable_knowledge"})
|
||||
|
||||
return results
|
||||
return results, deleted_count
|
||||
|
||||
|
||||
def _min_date(dates: "Any") -> "datetime | None":
|
||||
|
|
|
|||
|
|
@ -15,15 +15,19 @@ import json
|
|||
import logging
|
||||
import time
|
||||
import uuid
|
||||
from collections.abc import Awaitable, Callable
|
||||
from datetime import UTC, datetime, timedelta
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
import asyncpg
|
||||
import httpx
|
||||
import tiktoken
|
||||
|
||||
from ..config import get_config
|
||||
from ..metrics import get_metrics_collector
|
||||
from ..tracing import create_operation_span
|
||||
from ..utils import mask_network_location
|
||||
from ..worker.exceptions import RetryTaskAt
|
||||
from .db_budget import budgeted_operation
|
||||
from .operation_metadata import (
|
||||
BatchRetainChildMetadata,
|
||||
|
|
@ -359,6 +363,10 @@ class MemoryEngine(MemoryEngineInterface):
|
|||
self._run_migrations = run_migrations
|
||||
self._retain_entity_lookup = config.retain_entity_lookup
|
||||
|
||||
# Webhook manager (will be created in initialize() after pool is ready)
|
||||
self._webhook_manager = None
|
||||
self._http_client: httpx.AsyncClient | None = None
|
||||
|
||||
# Initialize entity resolver (will be created in initialize())
|
||||
self.entity_resolver = None
|
||||
|
||||
|
|
@ -582,6 +590,12 @@ class MemoryEngine(MemoryEngineInterface):
|
|||
document_tags=document_tags,
|
||||
request_context=context,
|
||||
operation_id=operation_id,
|
||||
outbox_callback=self._build_retain_outbox_callback(
|
||||
bank_id=bank_id,
|
||||
contents=contents,
|
||||
operation_id=operation_id,
|
||||
schema=context.tenant_id,
|
||||
),
|
||||
)
|
||||
|
||||
# If this retain was triggered by file conversion, update document with file metadata
|
||||
|
|
@ -778,6 +792,7 @@ class MemoryEngine(MemoryEngineInterface):
|
|||
)
|
||||
|
||||
logger.info(f"[CONSOLIDATION] bank={bank_id} completed: {result.get('memories_processed', 0)} processed")
|
||||
return result
|
||||
|
||||
async def _handle_refresh_mental_model(self, task_dict: dict[str, Any]):
|
||||
"""
|
||||
|
|
@ -949,15 +964,18 @@ class MemoryEngine(MemoryEngineInterface):
|
|||
logger.error(f"Failed to check operation status {operation_id}: {e}")
|
||||
# Continue with processing if we can't check status
|
||||
|
||||
consolidation_result: dict | None = None
|
||||
try:
|
||||
if task_type == "batch_retain":
|
||||
await self._handle_batch_retain(task_dict)
|
||||
elif task_type == "file_convert_retain":
|
||||
await self._handle_file_convert_retain(task_dict)
|
||||
elif task_type == "consolidation":
|
||||
await self._handle_consolidation(task_dict)
|
||||
consolidation_result = await self._handle_consolidation(task_dict)
|
||||
elif task_type == "refresh_mental_model":
|
||||
await self._handle_refresh_mental_model(task_dict)
|
||||
elif task_type == "webhook_delivery":
|
||||
await self._handle_webhook_delivery(task_dict)
|
||||
else:
|
||||
logger.error(f"Unknown task type: {task_type}")
|
||||
# Don't retry unknown task types
|
||||
|
|
@ -967,9 +985,22 @@ class MemoryEngine(MemoryEngineInterface):
|
|||
|
||||
# Task succeeded - mark operation as completed
|
||||
# file_convert_retain marks itself as completed in a transaction, skip double-marking
|
||||
if operation_id and task_type != "file_convert_retain":
|
||||
if operation_id and task_type not in ("file_convert_retain",):
|
||||
if task_type == "consolidation":
|
||||
# Atomically mark completed AND queue webhook delivery in one transaction
|
||||
await self._mark_operation_completed_and_fire_webhook(
|
||||
operation_id=operation_id,
|
||||
bank_id=task_dict.get("bank_id", ""),
|
||||
status="completed",
|
||||
result=consolidation_result,
|
||||
schema=schema,
|
||||
)
|
||||
else:
|
||||
await self._mark_operation_completed(operation_id)
|
||||
|
||||
except RetryTaskAt:
|
||||
# Task-owned retry: let the poller handle scheduling
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Task execution failed: {task_type}, error: {e}")
|
||||
import traceback
|
||||
|
|
@ -984,10 +1015,193 @@ class MemoryEngine(MemoryEngineInterface):
|
|||
if operation_id:
|
||||
await self._mark_operation_failed(operation_id, str(e), error_traceback)
|
||||
else:
|
||||
# Retryable: re-raise so the worker poller handles retry/fail via _retry_or_fail,
|
||||
# which correctly resets status='pending' and increments the DB retry_count.
|
||||
if task_type == "consolidation" and operation_id:
|
||||
# Fire failure webhook (non-transactional — operation not yet marked failed;
|
||||
# poller will mark it failed after this raise)
|
||||
await self._fire_consolidation_webhook(
|
||||
bank_id=task_dict.get("bank_id", ""),
|
||||
operation_id=operation_id,
|
||||
status="failed",
|
||||
result=None,
|
||||
error_message=str(e),
|
||||
schema=schema,
|
||||
)
|
||||
# Retryable: use RetryTaskAt if under the retry limit, else re-raise (poller marks failed)
|
||||
retry_count = task_dict.get("_retry_count", 0)
|
||||
if retry_count < 3:
|
||||
raise RetryTaskAt(retry_at=datetime.now(UTC) + timedelta(seconds=60), message=str(e))
|
||||
raise
|
||||
|
||||
async def _fire_consolidation_webhook(
|
||||
self,
|
||||
bank_id: str,
|
||||
operation_id: str,
|
||||
status: str,
|
||||
result: dict | None,
|
||||
error_message: str | None = None,
|
||||
schema: str | None = None,
|
||||
) -> None:
|
||||
"""Fire a consolidation webhook event. Non-fatal - logs errors but does not raise."""
|
||||
if not self._webhook_manager:
|
||||
return
|
||||
try:
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from ..webhooks.models import ConsolidationEventData, WebhookEvent, WebhookEventType
|
||||
|
||||
data = ConsolidationEventData(
|
||||
observations_created=result.get("observations_created") if result else None,
|
||||
observations_updated=result.get("observations_updated") if result else None,
|
||||
observations_deleted=result.get("observations_deleted") if result else None,
|
||||
error_message=error_message,
|
||||
)
|
||||
event = WebhookEvent(
|
||||
event=WebhookEventType.CONSOLIDATION_COMPLETED,
|
||||
bank_id=bank_id,
|
||||
operation_id=operation_id,
|
||||
status=status,
|
||||
timestamp=datetime.now(timezone.utc),
|
||||
data=data,
|
||||
)
|
||||
await self._webhook_manager.fire_event(event, schema=schema)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to fire consolidation webhook for operation {operation_id}: {e}")
|
||||
|
||||
def _build_retain_outbox_callback(
|
||||
self,
|
||||
bank_id: str,
|
||||
contents: list[dict],
|
||||
operation_id: str | None,
|
||||
schema: str | None = None,
|
||||
) -> "Callable[[asyncpg.Connection], Awaitable[None]] | None":
|
||||
"""Build a transactional outbox callback for retain.completed webhook events.
|
||||
|
||||
Returns a coroutine function that queues one webhook delivery row per content
|
||||
item using the provided connection (inside the retain transaction). Returns None
|
||||
if no webhook manager is configured.
|
||||
"""
|
||||
webhook_manager = getattr(self, "_webhook_manager", None)
|
||||
if not webhook_manager:
|
||||
return None
|
||||
|
||||
from ..webhooks.models import RetainEventData, WebhookEvent, WebhookEventType
|
||||
|
||||
now = datetime.now(UTC)
|
||||
op_id = operation_id or uuid.uuid4().hex
|
||||
events = []
|
||||
for content in contents:
|
||||
doc_id = content.get("document_id")
|
||||
tags = content.get("tags")
|
||||
data = RetainEventData(
|
||||
document_id=doc_id,
|
||||
tags=tags if isinstance(tags, list) else None,
|
||||
)
|
||||
events.append(
|
||||
WebhookEvent(
|
||||
event=WebhookEventType.RETAIN_COMPLETED,
|
||||
bank_id=bank_id,
|
||||
operation_id=op_id,
|
||||
status="completed",
|
||||
timestamp=now,
|
||||
data=data,
|
||||
)
|
||||
)
|
||||
|
||||
async def _callback(conn: asyncpg.Connection) -> None:
|
||||
for event in events:
|
||||
await webhook_manager.fire_event_with_conn(event, conn, schema=schema)
|
||||
|
||||
return _callback
|
||||
|
||||
async def _update_webhook_delivery_metadata(
|
||||
self, operation_id: str, status_code: int | None, response_body: str | None
|
||||
) -> None:
|
||||
"""Persist last HTTP attempt info into async_operations.result_metadata."""
|
||||
try:
|
||||
pool = await self._get_pool()
|
||||
meta = json.dumps(
|
||||
{
|
||||
"last_status_code": status_code,
|
||||
"last_response_body": (response_body or "")[:2048],
|
||||
"last_attempt_at": datetime.now(UTC).isoformat(),
|
||||
}
|
||||
)
|
||||
async with acquire_with_retry(pool) as conn:
|
||||
await conn.execute(
|
||||
f"UPDATE {fq_table('async_operations')} SET result_metadata = $2::jsonb, updated_at = now() WHERE operation_id = $1",
|
||||
uuid.UUID(operation_id),
|
||||
meta,
|
||||
)
|
||||
except Exception as meta_err:
|
||||
logger.debug(f"Failed to update webhook delivery metadata: {meta_err}")
|
||||
|
||||
async def _handle_webhook_delivery(self, task_dict: dict[str, Any]) -> None:
|
||||
"""Deliver a webhook event via HTTP.
|
||||
|
||||
Raises RetryTaskAt to schedule a retry on failure (up to MAX_ATTEMPTS).
|
||||
Raises the original exception when retries are exhausted (poller marks failed).
|
||||
Response status code and body are stored in result_metadata for debugging.
|
||||
"""
|
||||
from ..webhooks.manager import MAX_ATTEMPTS, RETRY_DELAYS
|
||||
from ..webhooks.models import WebhookHttpConfig
|
||||
|
||||
url = task_dict["url"]
|
||||
secret = task_dict.get("secret")
|
||||
event_type = task_dict["event_type"]
|
||||
raw_payload = task_dict["payload"]
|
||||
retry_count = task_dict.get("_retry_count", 0)
|
||||
operation_id: str | None = task_dict.get("_operation_id")
|
||||
http_config = WebhookHttpConfig.model_validate(task_dict.get("http_config") or {})
|
||||
|
||||
if isinstance(raw_payload, dict):
|
||||
payload_bytes = json.dumps(raw_payload).encode()
|
||||
else:
|
||||
payload_bytes = str(raw_payload).encode()
|
||||
|
||||
headers: dict[str, str] = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Hindsight-Event": event_type,
|
||||
**http_config.headers,
|
||||
}
|
||||
if secret and self._webhook_manager:
|
||||
headers["X-Hindsight-Signature"] = self._webhook_manager._sign_payload(secret, payload_bytes)
|
||||
|
||||
if self._http_client is None:
|
||||
raise RuntimeError("HTTP client not initialized")
|
||||
|
||||
response = None
|
||||
try:
|
||||
request_kwargs: dict[str, Any] = {
|
||||
"headers": headers,
|
||||
"params": http_config.params if http_config.params else None,
|
||||
"timeout": http_config.timeout_seconds,
|
||||
}
|
||||
if http_config.method.upper() == "GET":
|
||||
response = await self._http_client.get(url, **request_kwargs)
|
||||
else:
|
||||
response = await self._http_client.post(url, content=payload_bytes, **request_kwargs)
|
||||
response.raise_for_status()
|
||||
if operation_id:
|
||||
await self._update_webhook_delivery_metadata(operation_id, response.status_code, response.text)
|
||||
except Exception as e:
|
||||
status_code = response.status_code if response is not None else None
|
||||
response_body = response.text if response is not None else None
|
||||
if operation_id:
|
||||
await self._update_webhook_delivery_metadata(operation_id, status_code, response_body)
|
||||
if retry_count >= MAX_ATTEMPTS - 1:
|
||||
logger.error(
|
||||
f"webhook_delivery permanently_failed url={url} attempts={retry_count + 1} "
|
||||
f"status_code={status_code} error={e}"
|
||||
)
|
||||
raise
|
||||
delay = RETRY_DELAYS[retry_count] if retry_count < len(RETRY_DELAYS) else RETRY_DELAYS[-1]
|
||||
retry_at = datetime.now(UTC) + timedelta(seconds=delay)
|
||||
logger.warning(
|
||||
f"webhook_delivery failed url={url} attempt={retry_count + 1}/{MAX_ATTEMPTS} "
|
||||
f"status_code={status_code} retry_in={delay}s error={e}"
|
||||
)
|
||||
raise RetryTaskAt(retry_at=retry_at, message=str(e))
|
||||
|
||||
async def _delete_operation_record(self, operation_id: str):
|
||||
"""Helper to delete an operation record from the database."""
|
||||
try:
|
||||
|
|
@ -1058,6 +1272,58 @@ class MemoryEngine(MemoryEngineInterface):
|
|||
except Exception as e:
|
||||
logger.error(f"Failed to mark operation as completed {operation_id}: {e}")
|
||||
|
||||
async def _mark_operation_completed_and_fire_webhook(
|
||||
self,
|
||||
operation_id: str,
|
||||
bank_id: str,
|
||||
status: str,
|
||||
result: dict | None,
|
||||
schema: str | None = None,
|
||||
error_message: str | None = None,
|
||||
) -> None:
|
||||
"""Mark an operation as completed and queue webhook deliveries in a single transaction.
|
||||
|
||||
Uses the transactional outbox pattern: the webhook delivery row is inserted in the
|
||||
same database transaction as the status update. This guarantees at-least-once delivery
|
||||
even if the process crashes immediately after committing.
|
||||
"""
|
||||
from ..webhooks.models import ConsolidationEventData, WebhookEvent, WebhookEventType
|
||||
|
||||
try:
|
||||
pool = await self._get_pool()
|
||||
async with acquire_with_retry(pool) as conn:
|
||||
async with conn.transaction():
|
||||
await conn.execute(
|
||||
f"""
|
||||
UPDATE {fq_table("async_operations")}
|
||||
SET status = 'completed', updated_at = NOW(), completed_at = NOW()
|
||||
WHERE operation_id = $1
|
||||
""",
|
||||
uuid.UUID(operation_id),
|
||||
)
|
||||
logger.info(f"Marked async operation as completed: {operation_id}")
|
||||
await self._maybe_update_parent_operation(operation_id, conn)
|
||||
|
||||
# Queue webhook deliveries inside the same transaction
|
||||
if self._webhook_manager:
|
||||
data = ConsolidationEventData(
|
||||
observations_created=result.get("observations_created") if result else None,
|
||||
observations_updated=result.get("observations_updated") if result else None,
|
||||
observations_deleted=result.get("observations_deleted") if result else None,
|
||||
error_message=error_message,
|
||||
)
|
||||
event = WebhookEvent(
|
||||
event=WebhookEventType.CONSOLIDATION_COMPLETED,
|
||||
bank_id=bank_id,
|
||||
operation_id=operation_id,
|
||||
status=status,
|
||||
timestamp=datetime.now(UTC),
|
||||
data=data,
|
||||
)
|
||||
await self._webhook_manager.fire_event_with_conn(event, conn, schema=schema)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to mark operation completed and fire webhook {operation_id}: {e}")
|
||||
|
||||
async def _maybe_update_parent_operation(self, child_operation_id: str, conn):
|
||||
"""Check if this is a child operation and update parent status if all siblings are done.
|
||||
|
||||
|
|
@ -1381,6 +1647,32 @@ class MemoryEngine(MemoryEngineInterface):
|
|||
else:
|
||||
logger.debug("Iris parser not registered (VECTORIZE_TOKEN or VECTORIZE_ORG_ID not set)")
|
||||
|
||||
# Initialize webhook manager
|
||||
from ..webhooks import WebhookManager
|
||||
from ..webhooks.models import WebhookConfig
|
||||
|
||||
webhook_global: list[WebhookConfig] = []
|
||||
if config.webhook_url:
|
||||
webhook_global = [
|
||||
WebhookConfig(
|
||||
id="", # No DB row for env-configured global webhook
|
||||
bank_id=None,
|
||||
url=config.webhook_url,
|
||||
secret=config.webhook_secret,
|
||||
event_types=config.webhook_event_types,
|
||||
enabled=True,
|
||||
)
|
||||
]
|
||||
self._webhook_manager = WebhookManager(
|
||||
pool=self._pool,
|
||||
global_webhooks=webhook_global,
|
||||
tenant_extension=self._tenant_extension,
|
||||
)
|
||||
logger.debug("Webhook manager initialized")
|
||||
|
||||
# Long-lived HTTP client for webhook delivery tasks
|
||||
self._http_client = httpx.AsyncClient(timeout=30.0)
|
||||
|
||||
# Set executor for task backend and initialize
|
||||
self._task_backend.set_executor(self.execute_task)
|
||||
await self._task_backend.initialize()
|
||||
|
|
@ -1440,6 +1732,11 @@ class MemoryEngine(MemoryEngineInterface):
|
|||
# Shutdown task backend
|
||||
await self._task_backend.shutdown()
|
||||
|
||||
# Close HTTP client used for webhook delivery
|
||||
if self._http_client is not None:
|
||||
await self._http_client.aclose()
|
||||
self._http_client = None
|
||||
|
||||
# Close pool
|
||||
if self._pool is not None:
|
||||
self._pool.terminate()
|
||||
|
|
@ -1580,6 +1877,7 @@ class MemoryEngine(MemoryEngineInterface):
|
|||
document_tags: list[str] | None = None,
|
||||
return_usage: bool = False,
|
||||
operation_id: str | None = None,
|
||||
outbox_callback: "Callable[[asyncpg.Connection], Awaitable[None]] | None" = None,
|
||||
):
|
||||
"""
|
||||
Store multiple content items as memory units in ONE batch operation.
|
||||
|
|
@ -1728,6 +2026,9 @@ class MemoryEngine(MemoryEngineInterface):
|
|||
confidence_score=confidence_score,
|
||||
document_tags=document_tags,
|
||||
operation_id=operation_id,
|
||||
# Outbox callback runs inside the last sub-batch's transaction so the
|
||||
# webhook delivery row is committed atomically with the final retain data.
|
||||
outbox_callback=outbox_callback if i == len(sub_batches) else None,
|
||||
)
|
||||
all_results.extend(sub_results)
|
||||
total_usage = total_usage + sub_usage
|
||||
|
|
@ -1749,6 +2050,7 @@ class MemoryEngine(MemoryEngineInterface):
|
|||
confidence_score=confidence_score,
|
||||
document_tags=document_tags,
|
||||
operation_id=operation_id,
|
||||
outbox_callback=outbox_callback,
|
||||
)
|
||||
|
||||
# Call post-operation hook if validator is configured
|
||||
|
|
@ -1799,6 +2101,7 @@ class MemoryEngine(MemoryEngineInterface):
|
|||
confidence_score: float | None = None,
|
||||
document_tags: list[str] | None = None,
|
||||
operation_id: str | None = None,
|
||||
outbox_callback: "Callable[[asyncpg.Connection], Awaitable[None]] | None" = None,
|
||||
) -> tuple[list[list[str]], "TokenUsage"]:
|
||||
"""
|
||||
Internal method for batch processing without chunking logic.
|
||||
|
|
@ -1849,6 +2152,7 @@ class MemoryEngine(MemoryEngineInterface):
|
|||
config=resolved_config,
|
||||
operation_id=operation_id,
|
||||
schema=request_context.tenant_id if request_context else None,
|
||||
outbox_callback=outbox_callback,
|
||||
)
|
||||
|
||||
def recall(
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ Coordinates all retain pipeline modules to store memories efficiently.
|
|||
import logging
|
||||
import time
|
||||
import uuid
|
||||
from collections.abc import Awaitable, Callable
|
||||
from datetime import UTC, datetime
|
||||
from typing import Any
|
||||
|
||||
|
|
@ -52,6 +53,8 @@ def parse_datetime_flexible(value: Any) -> datetime:
|
|||
raise TypeError(f"Expected datetime or string, got {type(value).__name__}")
|
||||
|
||||
|
||||
import asyncpg
|
||||
|
||||
from ..response_models import TokenUsage
|
||||
from . import (
|
||||
chunk_storage,
|
||||
|
|
@ -82,6 +85,7 @@ async def retain_batch(
|
|||
document_tags: list[str] | None = None,
|
||||
operation_id: str | None = None,
|
||||
schema: str | None = None,
|
||||
outbox_callback: Callable[["asyncpg.Connection"], Awaitable[None]] | None = None,
|
||||
) -> tuple[list[list[str]], TokenUsage]:
|
||||
"""
|
||||
Process a batch of content through the retain pipeline.
|
||||
|
|
@ -484,6 +488,11 @@ async def retain_batch(
|
|||
# Map results back to original content items
|
||||
result_unit_ids = _map_results_to_contents(contents, extracted_facts, unit_ids)
|
||||
|
||||
# Transactional outbox: queue any side-effect tasks (e.g. webhook deliveries)
|
||||
# inside the same transaction so they are atomically committed with the retain data.
|
||||
if outbox_callback:
|
||||
await outbox_callback(conn)
|
||||
|
||||
# Flush entity stats (mention_count / last_seen) now that the transaction
|
||||
# has committed. Uses a fresh pool connection — no locks held.
|
||||
await entity_resolver.flush_pending_stats()
|
||||
|
|
|
|||
|
|
@ -307,6 +307,10 @@ def main():
|
|||
otel_exporter_otlp_headers=config.otel_exporter_otlp_headers,
|
||||
otel_service_name=config.otel_service_name,
|
||||
otel_deployment_environment=config.otel_deployment_environment,
|
||||
webhook_url=config.webhook_url,
|
||||
webhook_secret=config.webhook_secret,
|
||||
webhook_event_types=config.webhook_event_types,
|
||||
webhook_delivery_poll_interval_seconds=config.webhook_delivery_poll_interval_seconds,
|
||||
)
|
||||
config.configure_logging()
|
||||
if not args.daemon:
|
||||
|
|
|
|||
13
hindsight-api/hindsight_api/webhooks/__init__.py
Normal file
13
hindsight-api/hindsight_api/webhooks/__init__.py
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
"""Webhook system for Hindsight API event notifications."""
|
||||
|
||||
from .manager import WebhookManager
|
||||
from .models import ConsolidationEventData, RetainEventData, WebhookConfig, WebhookEvent, WebhookEventType
|
||||
|
||||
__all__ = [
|
||||
"WebhookManager",
|
||||
"WebhookConfig",
|
||||
"WebhookEvent",
|
||||
"WebhookEventType",
|
||||
"ConsolidationEventData",
|
||||
"RetainEventData",
|
||||
]
|
||||
238
hindsight-api/hindsight_api/webhooks/manager.py
Normal file
238
hindsight-api/hindsight_api/webhooks/manager.py
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
"""Webhook manager for delivering event notifications."""
|
||||
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
import logging
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import asyncpg
|
||||
|
||||
from .models import WebhookConfig, WebhookEvent, WebhookHttpConfig
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from hindsight_api.extensions.tenant import TenantExtension
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Retry delay schedule in seconds: 5 retries after the first attempt.
|
||||
# Fast early retries catch transient failures; later retries handle longer outages.
|
||||
RETRY_DELAYS = [5, 300, 1800, 7200, 18000]
|
||||
MAX_ATTEMPTS = len(RETRY_DELAYS) + 1 # first attempt + len(RETRY_DELAYS) retries
|
||||
|
||||
|
||||
def _fq_table(table: str, schema: str | None = None) -> str:
|
||||
"""Get fully-qualified table name with optional schema prefix."""
|
||||
if schema:
|
||||
return f'"{schema}".{table}'
|
||||
return table
|
||||
|
||||
|
||||
def _parse_http_config(value: str | dict | None) -> WebhookHttpConfig:
|
||||
"""Parse http_config column value (JSONB returned as text or dict) into a model."""
|
||||
if value is None:
|
||||
return WebhookHttpConfig()
|
||||
if isinstance(value, str):
|
||||
return WebhookHttpConfig.model_validate_json(value)
|
||||
return WebhookHttpConfig.model_validate(value)
|
||||
|
||||
|
||||
class WebhookManager:
|
||||
"""
|
||||
Manages webhook registration and event firing.
|
||||
|
||||
Supports both global webhooks (configured via env vars) and per-bank
|
||||
webhooks stored in the database. Deliveries are queued as async_operations
|
||||
tasks (operation_type='webhook_delivery') and picked up by the worker poller.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
pool: asyncpg.Pool,
|
||||
global_webhooks: list[WebhookConfig],
|
||||
tenant_extension: "TenantExtension | None" = None,
|
||||
):
|
||||
self._pool = pool
|
||||
self._global_webhooks = global_webhooks
|
||||
self._tenant_extension = tenant_extension
|
||||
|
||||
def _sign_payload(self, secret: str, payload_bytes: bytes) -> str:
|
||||
"""Compute HMAC-SHA256 signature for a payload."""
|
||||
return "sha256=" + hmac.new(secret.encode(), payload_bytes, hashlib.sha256).hexdigest()
|
||||
|
||||
async def fire_event(self, event: WebhookEvent, schema: str | None = None) -> None:
|
||||
"""
|
||||
Queue webhook deliveries for an event as async_operations tasks.
|
||||
|
||||
Loads per-bank and global webhooks, inserts pending webhook_delivery tasks for
|
||||
any webhook whose event_types list matches the fired event type. The worker
|
||||
poller picks these up and calls MemoryEngine._handle_webhook_delivery().
|
||||
|
||||
Args:
|
||||
event: The event to deliver.
|
||||
schema: Database schema (for multi-tenant). None = default schema.
|
||||
"""
|
||||
webhook_table = _fq_table("webhooks", schema)
|
||||
ops_table = _fq_table("async_operations", schema)
|
||||
now = datetime.now(timezone.utc)
|
||||
payload_str = event.model_dump_json()
|
||||
|
||||
try:
|
||||
# Load per-bank webhooks from DB (bank-specific + global NULL rows)
|
||||
rows = await self._pool.fetch(
|
||||
f"""
|
||||
SELECT id, bank_id, url, secret, event_types, enabled, http_config::text
|
||||
FROM {webhook_table}
|
||||
WHERE (bank_id = $1 OR bank_id IS NULL) AND enabled = true
|
||||
""",
|
||||
event.bank_id,
|
||||
)
|
||||
|
||||
db_webhooks = [
|
||||
WebhookConfig(
|
||||
id=str(row["id"]),
|
||||
bank_id=row["bank_id"],
|
||||
url=row["url"],
|
||||
secret=row["secret"],
|
||||
event_types=list(row["event_types"]) if row["event_types"] else [],
|
||||
enabled=row["enabled"],
|
||||
http_config=_parse_http_config(row["http_config"]),
|
||||
)
|
||||
for row in rows
|
||||
]
|
||||
|
||||
# Merge with global webhooks from env config
|
||||
all_webhooks = self._global_webhooks + db_webhooks
|
||||
matched = 0
|
||||
|
||||
for webhook in all_webhooks:
|
||||
if not webhook.enabled:
|
||||
continue
|
||||
if event.event.value not in webhook.event_types:
|
||||
continue
|
||||
|
||||
operation_id = uuid.uuid4()
|
||||
webhook_id = webhook.id if webhook.id else None
|
||||
|
||||
task_payload = json.dumps(
|
||||
{
|
||||
"type": "webhook_delivery",
|
||||
"operation_id": str(operation_id),
|
||||
"bank_id": event.bank_id,
|
||||
"url": webhook.url,
|
||||
"secret": webhook.secret,
|
||||
"event_type": event.event.value,
|
||||
"payload": payload_str,
|
||||
"webhook_id": webhook_id,
|
||||
"http_config": webhook.http_config.model_dump(),
|
||||
}
|
||||
)
|
||||
|
||||
await self._pool.execute(
|
||||
f"""
|
||||
INSERT INTO {ops_table}
|
||||
(operation_id, bank_id, operation_type, status, task_payload, result_metadata, created_at, updated_at)
|
||||
VALUES ($1, $2, 'webhook_delivery', 'pending', $3::jsonb, '{{}}'::jsonb, $4, $4)
|
||||
""",
|
||||
operation_id,
|
||||
event.bank_id,
|
||||
task_payload,
|
||||
now,
|
||||
)
|
||||
matched += 1
|
||||
|
||||
logger.debug(f"Fired webhook event {event.event} for bank {event.bank_id}: {matched} delivery(ies) queued")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to queue webhook deliveries for event {event.event}: {e}")
|
||||
|
||||
async def fire_event_with_conn(
|
||||
self, event: WebhookEvent, conn: asyncpg.Connection, schema: str | None = None
|
||||
) -> None:
|
||||
"""
|
||||
Queue webhook deliveries within an existing database connection/transaction.
|
||||
|
||||
Identical to fire_event() but uses the provided connection instead of acquiring
|
||||
one from the pool. Use this to atomically insert delivery tasks in the same
|
||||
transaction as the primary operation (transactional outbox pattern).
|
||||
|
||||
Args:
|
||||
event: The event to deliver.
|
||||
conn: Existing asyncpg connection (may be inside an active transaction).
|
||||
schema: Database schema (for multi-tenant). None = default schema.
|
||||
"""
|
||||
webhook_table = _fq_table("webhooks", schema)
|
||||
ops_table = _fq_table("async_operations", schema)
|
||||
now = datetime.now(timezone.utc)
|
||||
payload_str = event.model_dump_json()
|
||||
|
||||
try:
|
||||
rows = await conn.fetch(
|
||||
f"""
|
||||
SELECT id, bank_id, url, secret, event_types, enabled, http_config::text
|
||||
FROM {webhook_table}
|
||||
WHERE (bank_id = $1 OR bank_id IS NULL) AND enabled = true
|
||||
""",
|
||||
event.bank_id,
|
||||
)
|
||||
|
||||
db_webhooks = [
|
||||
WebhookConfig(
|
||||
id=str(row["id"]),
|
||||
bank_id=row["bank_id"],
|
||||
url=row["url"],
|
||||
secret=row["secret"],
|
||||
event_types=list(row["event_types"]) if row["event_types"] else [],
|
||||
enabled=row["enabled"],
|
||||
http_config=_parse_http_config(row["http_config"]),
|
||||
)
|
||||
for row in rows
|
||||
]
|
||||
|
||||
all_webhooks = self._global_webhooks + db_webhooks
|
||||
matched = 0
|
||||
|
||||
for webhook in all_webhooks:
|
||||
if not webhook.enabled:
|
||||
continue
|
||||
if event.event.value not in webhook.event_types:
|
||||
continue
|
||||
|
||||
operation_id = uuid.uuid4()
|
||||
webhook_id = webhook.id if webhook.id else None
|
||||
|
||||
task_payload = json.dumps(
|
||||
{
|
||||
"type": "webhook_delivery",
|
||||
"operation_id": str(operation_id),
|
||||
"bank_id": event.bank_id,
|
||||
"url": webhook.url,
|
||||
"secret": webhook.secret,
|
||||
"event_type": event.event.value,
|
||||
"payload": payload_str,
|
||||
"webhook_id": webhook_id,
|
||||
"http_config": webhook.http_config.model_dump(),
|
||||
}
|
||||
)
|
||||
|
||||
await conn.execute(
|
||||
f"""
|
||||
INSERT INTO {ops_table}
|
||||
(operation_id, bank_id, operation_type, status, task_payload, result_metadata, created_at, updated_at)
|
||||
VALUES ($1, $2, 'webhook_delivery', 'pending', $3::jsonb, '{{}}'::jsonb, $4, $4)
|
||||
""",
|
||||
operation_id,
|
||||
event.bank_id,
|
||||
task_payload,
|
||||
now,
|
||||
)
|
||||
matched += 1
|
||||
|
||||
logger.debug(
|
||||
f"Fired webhook event {event.event} for bank {event.bank_id}: {matched} delivery(ies) queued (in-transaction)"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to queue webhook deliveries (in-transaction) for event {event.event}: {e}")
|
||||
51
hindsight-api/hindsight_api/webhooks/models.py
Normal file
51
hindsight-api/hindsight_api/webhooks/models.py
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
"""Pydantic models for the webhook system."""
|
||||
|
||||
from datetime import datetime
|
||||
from enum import StrEnum
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class WebhookEventType(StrEnum):
|
||||
CONSOLIDATION_COMPLETED = "consolidation.completed"
|
||||
RETAIN_COMPLETED = "retain.completed"
|
||||
|
||||
|
||||
class ConsolidationEventData(BaseModel):
|
||||
observations_created: int | None = None
|
||||
observations_updated: int | None = None
|
||||
observations_deleted: int | None = None
|
||||
error_message: str | None = None
|
||||
|
||||
|
||||
class RetainEventData(BaseModel):
|
||||
document_id: str | None = None
|
||||
tags: list[str] | None = None
|
||||
|
||||
|
||||
class WebhookEvent(BaseModel):
|
||||
event: WebhookEventType
|
||||
bank_id: str
|
||||
operation_id: str
|
||||
status: str # "completed" or "failed"
|
||||
timestamp: datetime
|
||||
data: ConsolidationEventData | RetainEventData
|
||||
|
||||
|
||||
class WebhookHttpConfig(BaseModel):
|
||||
"""HTTP delivery configuration for a webhook."""
|
||||
|
||||
method: str = Field(default="POST", description="HTTP method: GET or POST")
|
||||
timeout_seconds: int = Field(default=30, description="HTTP request timeout in seconds")
|
||||
headers: dict[str, str] = Field(default_factory=dict, description="Custom HTTP headers")
|
||||
params: dict[str, str] = Field(default_factory=dict, description="Custom HTTP query parameters")
|
||||
|
||||
|
||||
class WebhookConfig(BaseModel):
|
||||
id: str
|
||||
bank_id: str | None
|
||||
url: str
|
||||
secret: str | None
|
||||
event_types: list[str]
|
||||
enabled: bool
|
||||
http_config: WebhookHttpConfig = Field(default_factory=WebhookHttpConfig)
|
||||
9
hindsight-api/hindsight_api/worker/exceptions.py
Normal file
9
hindsight-api/hindsight_api/worker/exceptions.py
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
from datetime import datetime
|
||||
|
||||
|
||||
class RetryTaskAt(Exception):
|
||||
"""Raise from a task handler to schedule a retry at a specific time."""
|
||||
|
||||
def __init__(self, retry_at: datetime, message: str = ""):
|
||||
self.retry_at = retry_at
|
||||
super().__init__(message)
|
||||
|
|
@ -219,7 +219,6 @@ def main():
|
|||
worker_id=args.worker_id,
|
||||
executor=memory.execute_task,
|
||||
poll_interval_ms=args.poll_interval,
|
||||
max_retries=args.max_retries,
|
||||
schema=schema,
|
||||
tenant_extension=tenant_extension,
|
||||
max_slots=config.worker_max_slots,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ from collections.abc import Awaitable, Callable
|
|||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from .exceptions import RetryTaskAt
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import asyncpg
|
||||
|
||||
|
|
@ -57,7 +59,6 @@ class WorkerPoller:
|
|||
worker_id: str,
|
||||
executor: Callable[[dict[str, Any]], Awaitable[None]],
|
||||
poll_interval_ms: int = 500,
|
||||
max_retries: int = 3,
|
||||
schema: str | None = None,
|
||||
tenant_extension: "TenantExtension | None" = None,
|
||||
max_slots: int = 10,
|
||||
|
|
@ -71,7 +72,6 @@ class WorkerPoller:
|
|||
worker_id: Unique identifier for this worker
|
||||
executor: Async function to execute tasks (typically MemoryEngine.execute_task)
|
||||
poll_interval_ms: Interval between polls when no tasks found (milliseconds)
|
||||
max_retries: Maximum retry attempts before marking task as failed
|
||||
schema: Database schema for single-tenant support (deprecated, use tenant_extension)
|
||||
tenant_extension: Extension for dynamic multi-tenant discovery. If None, creates a
|
||||
DefaultTenantExtension with the configured schema.
|
||||
|
|
@ -82,7 +82,6 @@ class WorkerPoller:
|
|||
self._worker_id = worker_id
|
||||
self._executor = executor
|
||||
self._poll_interval_ms = poll_interval_ms
|
||||
self._max_retries = max_retries
|
||||
self._schema = schema
|
||||
# Always set tenant extension (use DefaultTenantExtension if none provided)
|
||||
if tenant_extension is None:
|
||||
|
|
@ -218,11 +217,12 @@ class WorkerPoller:
|
|||
# 1. Claim non-consolidation tasks (up to limit)
|
||||
non_consolidation_rows = await conn.fetch(
|
||||
f"""
|
||||
SELECT operation_id, task_payload
|
||||
SELECT operation_id, task_payload, retry_count
|
||||
FROM {table}
|
||||
WHERE status = 'pending'
|
||||
AND task_payload IS NOT NULL
|
||||
AND operation_type != 'consolidation'
|
||||
AND (next_retry_at IS NULL OR next_retry_at <= NOW())
|
||||
ORDER BY created_at
|
||||
LIMIT $1
|
||||
FOR UPDATE SKIP LOCKED
|
||||
|
|
@ -238,11 +238,12 @@ class WorkerPoller:
|
|||
if consolidation_limit > 0 and remaining_limit > 0:
|
||||
consolidation_rows = await conn.fetch(
|
||||
f"""
|
||||
SELECT operation_id, task_payload
|
||||
SELECT operation_id, task_payload, retry_count
|
||||
FROM {table} AS pending
|
||||
WHERE status = 'pending'
|
||||
AND task_payload IS NOT NULL
|
||||
AND operation_type = 'consolidation'
|
||||
AND (next_retry_at IS NULL OR next_retry_at <= NOW())
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM {table} AS processing
|
||||
WHERE processing.bank_id = pending.bank_id
|
||||
|
|
@ -274,14 +275,19 @@ class WorkerPoller:
|
|||
)
|
||||
|
||||
# Parse and return task payloads with schema context
|
||||
return [
|
||||
result = []
|
||||
for row in all_rows:
|
||||
task_dict = json.loads(row["task_payload"])
|
||||
task_dict["_retry_count"] = row["retry_count"]
|
||||
task_dict["_operation_id"] = str(row["operation_id"])
|
||||
result.append(
|
||||
ClaimedTask(
|
||||
operation_id=str(row["operation_id"]),
|
||||
task_dict=json.loads(row["task_payload"]),
|
||||
task_dict=task_dict,
|
||||
schema=schema,
|
||||
)
|
||||
for row in all_rows
|
||||
]
|
||||
)
|
||||
return result
|
||||
|
||||
async def _mark_completed(self, operation_id: str, schema: str | None):
|
||||
"""Mark a task as completed."""
|
||||
|
|
@ -310,40 +316,22 @@ class WorkerPoller:
|
|||
error_message,
|
||||
)
|
||||
|
||||
async def _retry_or_fail(self, operation_id: str, error_message: str, schema: str | None):
|
||||
"""Increment retry count or mark as failed if max retries exceeded."""
|
||||
async def _schedule_retry(self, operation_id: str, retry_at: "Any", error_message: str, schema: str | None):
|
||||
"""Reset task to pending with a future retry timestamp."""
|
||||
table = fq_table("async_operations", schema)
|
||||
|
||||
# Get current retry count
|
||||
row = await self._pool.fetchrow(
|
||||
f"SELECT retry_count FROM {table} WHERE operation_id = $1",
|
||||
operation_id,
|
||||
)
|
||||
|
||||
if row is None:
|
||||
logger.warning(f"Operation {operation_id} not found, cannot retry")
|
||||
return
|
||||
|
||||
retry_count = row["retry_count"]
|
||||
|
||||
if retry_count >= self._max_retries:
|
||||
# Max retries exceeded, mark as failed
|
||||
await self._mark_failed(
|
||||
operation_id, f"Max retries ({self._max_retries}) exceeded. Last error: {error_message}", schema
|
||||
)
|
||||
logger.error(f"Task {operation_id} failed after {retry_count} retries")
|
||||
else:
|
||||
# Increment retry and reset to pending
|
||||
error_message = error_message[:5000] if len(error_message) > 5000 else error_message
|
||||
await self._pool.execute(
|
||||
f"""
|
||||
UPDATE {table}
|
||||
SET status = 'pending', worker_id = NULL, claimed_at = NULL,
|
||||
retry_count = retry_count + 1, updated_at = now()
|
||||
SET status = 'pending', next_retry_at = $2, worker_id = NULL, claimed_at = NULL,
|
||||
retry_count = retry_count + 1, error_message = $3, updated_at = now()
|
||||
WHERE operation_id = $1
|
||||
""",
|
||||
operation_id,
|
||||
retry_at,
|
||||
error_message,
|
||||
)
|
||||
logger.warning(f"Task {operation_id} failed, will retry (attempt {retry_count + 1}/{self._max_retries})")
|
||||
logger.warning(f"Task {operation_id} scheduled for retry at {retry_at}: {error_message}")
|
||||
|
||||
async def execute_task(self, task: ClaimedTask):
|
||||
"""Execute a single task as a background job (fire-and-forget)."""
|
||||
|
|
@ -378,11 +366,10 @@ class WorkerPoller:
|
|||
async def _execute_task_inner(self, task: ClaimedTask):
|
||||
"""Inner task execution with retry/fail handling.
|
||||
|
||||
Retryable task failures are re-raised by the executor (MemoryEngine.execute_task)
|
||||
and handled here via _retry_or_fail, which resets status='pending' (or marks as
|
||||
'failed' after max retries). Non-retryable failures (e.g., file_convert_retain) are
|
||||
handled by the executor internally — it marks the operation as failed and returns
|
||||
normally, so no exception reaches here.
|
||||
Tasks that want to be retried raise RetryTaskAt; the poller sets next_retry_at
|
||||
and resets status to 'pending'. All other exceptions are marked as failed immediately.
|
||||
Non-retryable failures (e.g., file_convert_retain) are handled by the executor
|
||||
internally — it marks the operation as failed and returns normally.
|
||||
"""
|
||||
task_type = task.task_dict.get("type", "unknown")
|
||||
bank_id = task.task_dict.get("bank_id", "unknown")
|
||||
|
|
@ -394,10 +381,12 @@ class WorkerPoller:
|
|||
task.task_dict["_schema"] = task.schema
|
||||
await self._executor(task.task_dict)
|
||||
logger.debug(f"Task {task.operation_id} execution finished")
|
||||
except RetryTaskAt as e:
|
||||
await self._schedule_retry(task.operation_id, e.retry_at, str(e), task.schema)
|
||||
except Exception as e:
|
||||
logger.error(f"Task {task.operation_id} failed: {e}")
|
||||
traceback.print_exc()
|
||||
await self._retry_or_fail(task.operation_id, str(e), task.schema)
|
||||
await self._mark_failed(task.operation_id, str(e), task.schema)
|
||||
|
||||
async def recover_own_tasks(self) -> int:
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -413,7 +413,6 @@ async def test_worker_batch_recovery(memory, request_context):
|
|||
worker_id="test_worker_recovery",
|
||||
executor=memory,
|
||||
poll_interval_ms=100,
|
||||
max_retries=3,
|
||||
schema=schema,
|
||||
tenant_extension=tenant_extension,
|
||||
max_slots=5,
|
||||
|
|
|
|||
780
hindsight-api/tests/test_webhooks.py
Normal file
780
hindsight-api/tests/test_webhooks.py
Normal file
|
|
@ -0,0 +1,780 @@
|
|||
"""Tests for the webhook system.
|
||||
|
||||
Covers:
|
||||
- Unit tests for HMAC signing and retry constants (no DB required)
|
||||
- Integration tests for fire_event() using a real DB (inserts into async_operations)
|
||||
- Integration tests for _handle_webhook_delivery() on the memory engine
|
||||
- HTTP API integration tests for CRUD and delivery listing endpoints
|
||||
"""
|
||||
|
||||
import json
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
|
||||
from hindsight_api.api import create_app
|
||||
from hindsight_api.engine.memory_engine import MemoryEngine
|
||||
from hindsight_api.webhooks.manager import MAX_ATTEMPTS, RETRY_DELAYS, WebhookManager
|
||||
from hindsight_api.webhooks.models import (
|
||||
ConsolidationEventData,
|
||||
RetainEventData,
|
||||
WebhookConfig,
|
||||
WebhookEvent,
|
||||
WebhookEventType,
|
||||
)
|
||||
from hindsight_api.worker.exceptions import RetryTaskAt
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def _make_event(bank_id: str = "bank-1") -> WebhookEvent:
|
||||
return WebhookEvent(
|
||||
event=WebhookEventType.CONSOLIDATION_COMPLETED,
|
||||
bank_id=bank_id,
|
||||
operation_id=uuid.uuid4().hex,
|
||||
status="completed",
|
||||
timestamp=datetime.now(timezone.utc),
|
||||
data=ConsolidationEventData(observations_created=1),
|
||||
)
|
||||
|
||||
|
||||
def _make_delivery_task(
|
||||
bank_id: str = "bank-1",
|
||||
url: str = "https://example.com/hook",
|
||||
retry_count: int = 0,
|
||||
webhook_id: str | None = None,
|
||||
) -> dict:
|
||||
return {
|
||||
"type": "webhook_delivery",
|
||||
"bank_id": bank_id,
|
||||
"url": url,
|
||||
"secret": None,
|
||||
"event_type": "consolidation.completed",
|
||||
"payload": '{"event":"consolidation.completed"}',
|
||||
"webhook_id": webhook_id,
|
||||
"_retry_count": retry_count,
|
||||
}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Unit tests (no DB)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestHmacSigning:
|
||||
"""Unit tests for WebhookManager._sign_payload()."""
|
||||
|
||||
def _make_manager(self) -> WebhookManager:
|
||||
"""Create a WebhookManager with a dummy pool (not used for signing)."""
|
||||
pool = MagicMock()
|
||||
return WebhookManager(pool=pool, global_webhooks=[])
|
||||
|
||||
def test_hmac_signing_format(self):
|
||||
"""_sign_payload should return a string starting with 'sha256='."""
|
||||
manager = self._make_manager()
|
||||
sig = manager._sign_payload("my-secret", b"hello world")
|
||||
assert sig.startswith("sha256="), f"Expected 'sha256=' prefix, got: {sig!r}"
|
||||
hex_part = sig[len("sha256="):]
|
||||
# SHA-256 hex digest is always 64 characters
|
||||
assert len(hex_part) == 64
|
||||
# Hex characters only
|
||||
assert all(c in "0123456789abcdef" for c in hex_part)
|
||||
|
||||
def test_hmac_signing_is_deterministic(self):
|
||||
"""Same secret + payload always produces the same signature."""
|
||||
manager = self._make_manager()
|
||||
payload = b'{"event":"consolidation.completed"}'
|
||||
sig1 = manager._sign_payload("secret-key", payload)
|
||||
sig2 = manager._sign_payload("secret-key", payload)
|
||||
assert sig1 == sig2
|
||||
|
||||
def test_hmac_signing_differs_with_different_secret(self):
|
||||
"""Different secrets must produce different signatures."""
|
||||
manager = self._make_manager()
|
||||
payload = b"payload"
|
||||
sig1 = manager._sign_payload("secret-a", payload)
|
||||
sig2 = manager._sign_payload("secret-b", payload)
|
||||
assert sig1 != sig2
|
||||
|
||||
def test_hmac_signing_differs_with_different_payload(self):
|
||||
"""Different payloads must produce different signatures."""
|
||||
manager = self._make_manager()
|
||||
sig1 = manager._sign_payload("secret", b"payload-one")
|
||||
sig2 = manager._sign_payload("secret", b"payload-two")
|
||||
assert sig1 != sig2
|
||||
|
||||
|
||||
class TestRetryConstants:
|
||||
"""Unit tests to verify retry schedule constants."""
|
||||
|
||||
def test_retry_delays_values(self):
|
||||
"""RETRY_DELAYS must match the documented schedule."""
|
||||
assert RETRY_DELAYS == [5, 300, 1800, 7200, 18000]
|
||||
|
||||
def test_max_attempts(self):
|
||||
"""MAX_ATTEMPTS should be len(RETRY_DELAYS) + 1."""
|
||||
assert MAX_ATTEMPTS == 6
|
||||
assert MAX_ATTEMPTS == len(RETRY_DELAYS) + 1
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# DB integration tests
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest_asyncio.fixture
|
||||
async def webhook_manager(memory: MemoryEngine) -> WebhookManager:
|
||||
"""Return a WebhookManager backed by the test pool with no global webhooks."""
|
||||
return WebhookManager(pool=memory._pool, global_webhooks=[])
|
||||
|
||||
|
||||
class TestFireEvent:
|
||||
"""Integration tests for WebhookManager.fire_event()."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_fire_event_creates_delivery(
|
||||
self, memory: MemoryEngine, webhook_manager: WebhookManager
|
||||
):
|
||||
"""fire_event() inserts a pending webhook_delivery task in async_operations."""
|
||||
bank_id = f"wh-test-{uuid.uuid4().hex[:8]}"
|
||||
webhook_id = uuid.uuid4()
|
||||
|
||||
async with memory._pool.acquire() as conn:
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO webhooks (id, bank_id, url, secret, event_types, enabled, created_at, updated_at)
|
||||
VALUES ($1, $2, $3, NULL, $4, true, NOW(), NOW())
|
||||
""",
|
||||
webhook_id,
|
||||
bank_id,
|
||||
"https://example.com/hook",
|
||||
["consolidation.completed"],
|
||||
)
|
||||
|
||||
try:
|
||||
event = _make_event(bank_id)
|
||||
await webhook_manager.fire_event(event)
|
||||
|
||||
async with memory._pool.acquire() as conn:
|
||||
rows = await conn.fetch(
|
||||
"""
|
||||
SELECT status, task_payload
|
||||
FROM async_operations
|
||||
WHERE operation_type = 'webhook_delivery'
|
||||
AND bank_id = $1
|
||||
AND task_payload->>'webhook_id' = $2
|
||||
""",
|
||||
bank_id,
|
||||
str(webhook_id),
|
||||
)
|
||||
|
||||
assert len(rows) == 1
|
||||
assert rows[0]["status"] == "pending"
|
||||
payload = rows[0]["task_payload"]
|
||||
if isinstance(payload, str):
|
||||
payload = json.loads(payload)
|
||||
assert payload["event_type"] == "consolidation.completed"
|
||||
finally:
|
||||
async with memory._pool.acquire() as conn:
|
||||
await conn.execute(
|
||||
"DELETE FROM async_operations WHERE operation_type = 'webhook_delivery' AND bank_id = $1",
|
||||
bank_id,
|
||||
)
|
||||
await conn.execute("DELETE FROM webhooks WHERE id = $1", webhook_id)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_fire_event_global_webhook(
|
||||
self, memory: MemoryEngine
|
||||
):
|
||||
"""fire_event() also queues delivery tasks for global webhooks (not stored in DB)."""
|
||||
bank_id = f"wh-global-{uuid.uuid4().hex[:8]}"
|
||||
global_webhook = WebhookConfig(
|
||||
id="", # No DB row
|
||||
bank_id=None,
|
||||
url="https://global.example.com/hook",
|
||||
secret=None,
|
||||
event_types=["consolidation.completed"],
|
||||
enabled=True,
|
||||
)
|
||||
manager = WebhookManager(pool=memory._pool, global_webhooks=[global_webhook])
|
||||
|
||||
event = _make_event(bank_id)
|
||||
await manager.fire_event(event)
|
||||
|
||||
async with memory._pool.acquire() as conn:
|
||||
rows = await conn.fetch(
|
||||
"""
|
||||
SELECT status, task_payload
|
||||
FROM async_operations
|
||||
WHERE operation_type = 'webhook_delivery'
|
||||
AND bank_id = $1
|
||||
AND task_payload->>'url' = 'https://global.example.com/hook'
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 1
|
||||
"""
|
||||
,
|
||||
bank_id,
|
||||
)
|
||||
|
||||
assert len(rows) == 1
|
||||
assert rows[0]["status"] == "pending"
|
||||
payload = rows[0]["task_payload"]
|
||||
if isinstance(payload, str):
|
||||
payload = json.loads(payload)
|
||||
assert payload["webhook_id"] is None # global webhook has no DB row
|
||||
|
||||
# Cleanup
|
||||
async with memory._pool.acquire() as conn:
|
||||
await conn.execute(
|
||||
"DELETE FROM async_operations WHERE operation_type = 'webhook_delivery' AND bank_id = $1",
|
||||
bank_id,
|
||||
)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_fire_event_no_match_if_event_type_mismatch(
|
||||
self, memory: MemoryEngine, webhook_manager: WebhookManager
|
||||
):
|
||||
"""Webhooks registered for a different event type receive no delivery task."""
|
||||
bank_id = f"wh-mismatch-{uuid.uuid4().hex[:8]}"
|
||||
webhook_id = uuid.uuid4()
|
||||
|
||||
async with memory._pool.acquire() as conn:
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO webhooks (id, bank_id, url, secret, event_types, enabled, created_at, updated_at)
|
||||
VALUES ($1, $2, $3, NULL, $4, true, NOW(), NOW())
|
||||
""",
|
||||
webhook_id,
|
||||
bank_id,
|
||||
"https://example.com/other-hook",
|
||||
["other.event"],
|
||||
)
|
||||
|
||||
try:
|
||||
event = _make_event(bank_id)
|
||||
await webhook_manager.fire_event(event)
|
||||
|
||||
async with memory._pool.acquire() as conn:
|
||||
count = await conn.fetchval(
|
||||
"""
|
||||
SELECT COUNT(*) FROM async_operations
|
||||
WHERE operation_type = 'webhook_delivery' AND bank_id = $1
|
||||
""",
|
||||
bank_id,
|
||||
)
|
||||
|
||||
assert count == 0
|
||||
finally:
|
||||
async with memory._pool.acquire() as conn:
|
||||
await conn.execute("DELETE FROM webhooks WHERE id = $1", webhook_id)
|
||||
|
||||
|
||||
class TestHandleWebhookDelivery:
|
||||
"""Integration tests for MemoryEngine._handle_webhook_delivery()."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_deliver_success(self, memory: MemoryEngine):
|
||||
"""A successful HTTP POST completes without raising."""
|
||||
task_dict = _make_delivery_task(retry_count=0)
|
||||
|
||||
mock_response = MagicMock()
|
||||
mock_response.raise_for_status = MagicMock()
|
||||
|
||||
with patch.object(memory._http_client, "post", new=AsyncMock(return_value=mock_response)):
|
||||
# Should not raise
|
||||
await memory._handle_webhook_delivery(task_dict)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_deliver_failure_raises_retry_task_at(self, memory: MemoryEngine):
|
||||
"""A failed HTTP POST raises RetryTaskAt when retries remain."""
|
||||
task_dict = _make_delivery_task(retry_count=0)
|
||||
|
||||
with patch.object(
|
||||
memory._http_client, "post", new=AsyncMock(side_effect=Exception("connection refused"))
|
||||
):
|
||||
with pytest.raises(RetryTaskAt):
|
||||
await memory._handle_webhook_delivery(task_dict)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_deliver_exhausted_retries_raises(self, memory: MemoryEngine):
|
||||
"""When retry_count reaches MAX_ATTEMPTS-1, a failure raises the original exception."""
|
||||
task_dict = _make_delivery_task(retry_count=MAX_ATTEMPTS - 1)
|
||||
|
||||
with patch.object(
|
||||
memory._http_client, "post", new=AsyncMock(side_effect=Exception("server error"))
|
||||
):
|
||||
with pytest.raises(Exception, match="server error"):
|
||||
await memory._handle_webhook_delivery(task_dict)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_deliver_retry_at_uses_delay_schedule(self, memory: MemoryEngine):
|
||||
"""RetryTaskAt.retry_at is approximately now + RETRY_DELAYS[retry_count]."""
|
||||
from datetime import timedelta
|
||||
|
||||
task_dict = _make_delivery_task(retry_count=1)
|
||||
|
||||
with patch.object(
|
||||
memory._http_client, "post", new=AsyncMock(side_effect=Exception("fail"))
|
||||
):
|
||||
before = datetime.now(timezone.utc)
|
||||
with pytest.raises(RetryTaskAt) as exc_info:
|
||||
await memory._handle_webhook_delivery(task_dict)
|
||||
after = datetime.now(timezone.utc)
|
||||
|
||||
retry_at = exc_info.value.retry_at
|
||||
expected_delay = RETRY_DELAYS[1] # retry_count=1
|
||||
assert retry_at >= before + timedelta(seconds=expected_delay - 2)
|
||||
assert retry_at <= after + timedelta(seconds=expected_delay + 2)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_execute_task_marks_operation_completed(self, memory: MemoryEngine):
|
||||
"""After a successful delivery, execute_task marks the async_operations row as completed."""
|
||||
operation_id = str(uuid.uuid4())
|
||||
bank_id = f"wh-exec-{uuid.uuid4().hex[:8]}"
|
||||
|
||||
# Insert a real async_operations row so _mark_operation_completed has something to update
|
||||
async with memory._pool.acquire() as conn:
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO async_operations
|
||||
(operation_id, bank_id, operation_type, status, task_payload, result_metadata, created_at, updated_at)
|
||||
VALUES ($1, $2, 'webhook_delivery', 'processing', '{}'::jsonb, '{}'::jsonb, NOW(), NOW())
|
||||
""",
|
||||
uuid.UUID(operation_id),
|
||||
bank_id,
|
||||
)
|
||||
|
||||
task_dict = {
|
||||
**_make_delivery_task(bank_id=bank_id, retry_count=0),
|
||||
"operation_id": operation_id,
|
||||
}
|
||||
|
||||
mock_response = MagicMock()
|
||||
mock_response.raise_for_status = MagicMock()
|
||||
|
||||
with patch.object(memory._http_client, "post", new=AsyncMock(return_value=mock_response)):
|
||||
await memory.execute_task(task_dict)
|
||||
|
||||
async with memory._pool.acquire() as conn:
|
||||
row = await conn.fetchrow(
|
||||
"SELECT status FROM async_operations WHERE operation_id = $1",
|
||||
uuid.UUID(operation_id),
|
||||
)
|
||||
|
||||
assert row is not None
|
||||
assert row["status"] == "completed", f"Expected 'completed', got '{row['status']}'"
|
||||
|
||||
# Cleanup
|
||||
async with memory._pool.acquire() as conn:
|
||||
await conn.execute(
|
||||
"DELETE FROM async_operations WHERE operation_id = $1",
|
||||
uuid.UUID(operation_id),
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# HTTP API integration tests
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest_asyncio.fixture
|
||||
async def api_client(memory: MemoryEngine):
|
||||
"""Async HTTP test client wired to the FastAPI app."""
|
||||
app = create_app(memory, initialize_memory=False)
|
||||
transport = httpx.ASGITransport(app=app)
|
||||
async with httpx.AsyncClient(transport=transport, base_url="http://test") as client:
|
||||
yield client
|
||||
|
||||
|
||||
class TestWebhookHttpApi:
|
||||
"""HTTP API integration tests for webhook CRUD endpoints."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_http_create_webhook(self, api_client: httpx.AsyncClient):
|
||||
"""POST /webhooks returns 201 and an id."""
|
||||
bank_id = f"http-wh-{uuid.uuid4().hex[:8]}"
|
||||
response = await api_client.post(
|
||||
f"/v1/default/banks/{bank_id}/webhooks",
|
||||
json={
|
||||
"url": "https://example.com/create",
|
||||
"event_types": ["consolidation.completed"],
|
||||
},
|
||||
)
|
||||
assert response.status_code == 201, response.text
|
||||
data = response.json()
|
||||
assert "id" in data
|
||||
assert data["url"] == "https://example.com/create"
|
||||
assert data["bank_id"] == bank_id
|
||||
assert data["secret"] is None # secrets are never echoed back
|
||||
|
||||
# Cleanup
|
||||
await api_client.delete(
|
||||
f"/v1/default/banks/{bank_id}/webhooks/{data['id']}"
|
||||
)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_http_list_webhooks(self, api_client: httpx.AsyncClient):
|
||||
"""GET /webhooks returns the webhooks registered for a bank."""
|
||||
bank_id = f"http-wh-{uuid.uuid4().hex[:8]}"
|
||||
|
||||
create_resp = await api_client.post(
|
||||
f"/v1/default/banks/{bank_id}/webhooks",
|
||||
json={"url": "https://example.com/list", "event_types": ["consolidation.completed"]},
|
||||
)
|
||||
assert create_resp.status_code == 201
|
||||
webhook_id = create_resp.json()["id"]
|
||||
|
||||
list_resp = await api_client.get(f"/v1/default/banks/{bank_id}/webhooks")
|
||||
assert list_resp.status_code == 200
|
||||
items = list_resp.json()["items"]
|
||||
assert any(item["id"] == webhook_id for item in items)
|
||||
|
||||
# Cleanup
|
||||
await api_client.delete(f"/v1/default/banks/{bank_id}/webhooks/{webhook_id}")
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_http_delete_webhook(self, api_client: httpx.AsyncClient):
|
||||
"""DELETE /webhooks/{id} removes the webhook; subsequent list returns empty for that bank."""
|
||||
bank_id = f"http-wh-{uuid.uuid4().hex[:8]}"
|
||||
|
||||
create_resp = await api_client.post(
|
||||
f"/v1/default/banks/{bank_id}/webhooks",
|
||||
json={"url": "https://example.com/delete", "event_types": ["consolidation.completed"]},
|
||||
)
|
||||
assert create_resp.status_code == 201
|
||||
webhook_id = create_resp.json()["id"]
|
||||
|
||||
delete_resp = await api_client.delete(
|
||||
f"/v1/default/banks/{bank_id}/webhooks/{webhook_id}"
|
||||
)
|
||||
assert delete_resp.status_code == 200
|
||||
assert delete_resp.json()["success"] is True
|
||||
|
||||
list_resp = await api_client.get(f"/v1/default/banks/{bank_id}/webhooks")
|
||||
assert list_resp.status_code == 200
|
||||
ids = [item["id"] for item in list_resp.json()["items"]]
|
||||
assert webhook_id not in ids
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_http_delete_webhook_not_found(self, api_client: httpx.AsyncClient):
|
||||
"""DELETE with a non-existent webhook id returns 404."""
|
||||
bank_id = f"http-wh-{uuid.uuid4().hex[:8]}"
|
||||
missing_id = str(uuid.uuid4())
|
||||
response = await api_client.delete(
|
||||
f"/v1/default/banks/{bank_id}/webhooks/{missing_id}"
|
||||
)
|
||||
assert response.status_code == 404
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_http_list_deliveries(
|
||||
self, memory: MemoryEngine, api_client: httpx.AsyncClient
|
||||
):
|
||||
"""GET /webhooks/{id}/deliveries returns delivery records for a webhook."""
|
||||
bank_id = f"http-wh-{uuid.uuid4().hex[:8]}"
|
||||
|
||||
# Create webhook via HTTP API
|
||||
create_resp = await api_client.post(
|
||||
f"/v1/default/banks/{bank_id}/webhooks",
|
||||
json={
|
||||
"url": "https://example.com/deliveries",
|
||||
"event_types": ["consolidation.completed"],
|
||||
},
|
||||
)
|
||||
assert create_resp.status_code == 201
|
||||
webhook_id = create_resp.json()["id"]
|
||||
|
||||
# Insert a delivery row directly into async_operations
|
||||
delivery_id = uuid.uuid4()
|
||||
now = datetime.now(timezone.utc)
|
||||
task_payload = json.dumps(
|
||||
{
|
||||
"type": "webhook_delivery",
|
||||
"bank_id": bank_id,
|
||||
"url": "https://example.com/deliveries",
|
||||
"secret": None,
|
||||
"event_type": "consolidation.completed",
|
||||
"payload": '{"event":"consolidation.completed"}',
|
||||
"webhook_id": webhook_id,
|
||||
}
|
||||
)
|
||||
async with memory._pool.acquire() as conn:
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO async_operations
|
||||
(operation_id, bank_id, operation_type, status, retry_count, task_payload, result_metadata, created_at, updated_at)
|
||||
VALUES ($1, $2, 'webhook_delivery', 'completed', 0, $3::jsonb, '{}'::jsonb, $4, $4)
|
||||
""",
|
||||
delivery_id,
|
||||
bank_id,
|
||||
task_payload,
|
||||
now,
|
||||
)
|
||||
|
||||
try:
|
||||
deliveries_resp = await api_client.get(
|
||||
f"/v1/default/banks/{bank_id}/webhooks/{webhook_id}/deliveries"
|
||||
)
|
||||
assert deliveries_resp.status_code == 200
|
||||
items = deliveries_resp.json()["items"]
|
||||
ids = [item["id"] for item in items]
|
||||
assert str(delivery_id) in ids
|
||||
|
||||
# Verify shape of a delivery item
|
||||
delivery = next(item for item in items if item["id"] == str(delivery_id))
|
||||
assert delivery["status"] == "completed"
|
||||
assert delivery["event_type"] == "consolidation.completed"
|
||||
assert delivery["attempts"] == 1
|
||||
finally:
|
||||
async with memory._pool.acquire() as conn:
|
||||
await conn.execute(
|
||||
"DELETE FROM async_operations WHERE operation_id = $1", delivery_id
|
||||
)
|
||||
await api_client.delete(
|
||||
f"/v1/default/banks/{bank_id}/webhooks/{webhook_id}"
|
||||
)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_http_list_deliveries_webhook_not_found(self, api_client: httpx.AsyncClient):
|
||||
"""GET /webhooks/{id}/deliveries for a non-existent webhook returns 404."""
|
||||
bank_id = f"http-wh-{uuid.uuid4().hex[:8]}"
|
||||
missing_id = str(uuid.uuid4())
|
||||
response = await api_client.get(
|
||||
f"/v1/default/banks/{bank_id}/webhooks/{missing_id}/deliveries"
|
||||
)
|
||||
assert response.status_code == 404
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_http_update_webhook_url(self, api_client: httpx.AsyncClient):
|
||||
"""PATCH /webhooks/{id} updates only the provided fields."""
|
||||
bank_id = f"http-wh-{uuid.uuid4().hex[:8]}"
|
||||
|
||||
create_resp = await api_client.post(
|
||||
f"/v1/default/banks/{bank_id}/webhooks",
|
||||
json={"url": "https://example.com/original", "event_types": ["consolidation.completed"]},
|
||||
)
|
||||
assert create_resp.status_code == 201
|
||||
webhook_id = create_resp.json()["id"]
|
||||
|
||||
patch_resp = await api_client.patch(
|
||||
f"/v1/default/banks/{bank_id}/webhooks/{webhook_id}",
|
||||
json={"url": "https://example.com/updated"},
|
||||
)
|
||||
assert patch_resp.status_code == 200
|
||||
data = patch_resp.json()
|
||||
assert data["url"] == "https://example.com/updated"
|
||||
# event_types should be unchanged
|
||||
assert "consolidation.completed" in data["event_types"]
|
||||
|
||||
# Cleanup
|
||||
await api_client.delete(f"/v1/default/banks/{bank_id}/webhooks/{webhook_id}")
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_http_update_webhook_event_types(self, api_client: httpx.AsyncClient):
|
||||
"""PATCH /webhooks/{id} can update event_types."""
|
||||
bank_id = f"http-wh-{uuid.uuid4().hex[:8]}"
|
||||
|
||||
create_resp = await api_client.post(
|
||||
f"/v1/default/banks/{bank_id}/webhooks",
|
||||
json={"url": "https://example.com/hook", "event_types": ["consolidation.completed"]},
|
||||
)
|
||||
assert create_resp.status_code == 201
|
||||
webhook_id = create_resp.json()["id"]
|
||||
|
||||
patch_resp = await api_client.patch(
|
||||
f"/v1/default/banks/{bank_id}/webhooks/{webhook_id}",
|
||||
json={"event_types": ["retain.completed"]},
|
||||
)
|
||||
assert patch_resp.status_code == 200
|
||||
data = patch_resp.json()
|
||||
assert data["event_types"] == ["retain.completed"]
|
||||
|
||||
# Cleanup
|
||||
await api_client.delete(f"/v1/default/banks/{bank_id}/webhooks/{webhook_id}")
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_http_update_webhook_enabled(self, api_client: httpx.AsyncClient):
|
||||
"""PATCH /webhooks/{id} can toggle enabled."""
|
||||
bank_id = f"http-wh-{uuid.uuid4().hex[:8]}"
|
||||
|
||||
create_resp = await api_client.post(
|
||||
f"/v1/default/banks/{bank_id}/webhooks",
|
||||
json={"url": "https://example.com/hook", "event_types": ["consolidation.completed"]},
|
||||
)
|
||||
assert create_resp.status_code == 201
|
||||
webhook_id = create_resp.json()["id"]
|
||||
assert create_resp.json()["enabled"] is True
|
||||
|
||||
patch_resp = await api_client.patch(
|
||||
f"/v1/default/banks/{bank_id}/webhooks/{webhook_id}",
|
||||
json={"enabled": False},
|
||||
)
|
||||
assert patch_resp.status_code == 200
|
||||
assert patch_resp.json()["enabled"] is False
|
||||
|
||||
# Cleanup
|
||||
await api_client.delete(f"/v1/default/banks/{bank_id}/webhooks/{webhook_id}")
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_http_update_webhook_http_config(self, api_client: httpx.AsyncClient):
|
||||
"""PATCH /webhooks/{id} can update http_config."""
|
||||
bank_id = f"http-wh-{uuid.uuid4().hex[:8]}"
|
||||
|
||||
create_resp = await api_client.post(
|
||||
f"/v1/default/banks/{bank_id}/webhooks",
|
||||
json={"url": "https://example.com/hook", "event_types": ["consolidation.completed"]},
|
||||
)
|
||||
assert create_resp.status_code == 201
|
||||
webhook_id = create_resp.json()["id"]
|
||||
|
||||
patch_resp = await api_client.patch(
|
||||
f"/v1/default/banks/{bank_id}/webhooks/{webhook_id}",
|
||||
json={
|
||||
"http_config": {
|
||||
"method": "POST",
|
||||
"timeout_seconds": 10,
|
||||
"headers": {"X-Custom": "value"},
|
||||
"params": {},
|
||||
}
|
||||
},
|
||||
)
|
||||
assert patch_resp.status_code == 200
|
||||
data = patch_resp.json()
|
||||
assert data["http_config"]["timeout_seconds"] == 10
|
||||
assert data["http_config"]["headers"] == {"X-Custom": "value"}
|
||||
|
||||
# Cleanup
|
||||
await api_client.delete(f"/v1/default/banks/{bank_id}/webhooks/{webhook_id}")
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_http_update_webhook_not_found(self, api_client: httpx.AsyncClient):
|
||||
"""PATCH /webhooks/{id} returns 404 for a non-existent webhook."""
|
||||
bank_id = f"http-wh-{uuid.uuid4().hex[:8]}"
|
||||
missing_id = str(uuid.uuid4())
|
||||
response = await api_client.patch(
|
||||
f"/v1/default/banks/{bank_id}/webhooks/{missing_id}",
|
||||
json={"url": "https://example.com/new"},
|
||||
)
|
||||
assert response.status_code == 404
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_http_update_webhook_no_fields(self, api_client: httpx.AsyncClient):
|
||||
"""PATCH /webhooks/{id} with empty body returns 422."""
|
||||
bank_id = f"http-wh-{uuid.uuid4().hex[:8]}"
|
||||
|
||||
create_resp = await api_client.post(
|
||||
f"/v1/default/banks/{bank_id}/webhooks",
|
||||
json={"url": "https://example.com/hook", "event_types": ["consolidation.completed"]},
|
||||
)
|
||||
assert create_resp.status_code == 201
|
||||
webhook_id = create_resp.json()["id"]
|
||||
|
||||
patch_resp = await api_client.patch(
|
||||
f"/v1/default/banks/{bank_id}/webhooks/{webhook_id}",
|
||||
json={},
|
||||
)
|
||||
assert patch_resp.status_code == 422
|
||||
|
||||
# Cleanup
|
||||
await api_client.delete(f"/v1/default/banks/{bank_id}/webhooks/{webhook_id}")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# retain.completed webhook tests
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestRetainCompletedWebhook:
|
||||
"""Tests for the retain.completed webhook event."""
|
||||
|
||||
def test_retain_event_data_model(self):
|
||||
"""RetainEventData can be constructed with optional fields."""
|
||||
data = RetainEventData(document_id="doc-123", tags=["tag1", "tag2"])
|
||||
assert data.document_id == "doc-123"
|
||||
assert data.tags == ["tag1", "tag2"]
|
||||
|
||||
empty = RetainEventData()
|
||||
assert empty.document_id is None
|
||||
assert empty.tags is None
|
||||
|
||||
def test_retain_event_type_value(self):
|
||||
"""WebhookEventType.RETAIN_COMPLETED has the correct string value."""
|
||||
assert WebhookEventType.RETAIN_COMPLETED == "retain.completed"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_fire_retain_webhook_queues_per_document(
|
||||
self, memory: MemoryEngine, webhook_manager: WebhookManager
|
||||
):
|
||||
"""_fire_retain_webhook queues one delivery task per content item."""
|
||||
bank_id = f"wh-retain-{uuid.uuid4().hex[:8]}"
|
||||
webhook_id = uuid.uuid4()
|
||||
|
||||
async with memory._pool.acquire() as conn:
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO webhooks (id, bank_id, url, secret, event_types, enabled, created_at, updated_at)
|
||||
VALUES ($1, $2, $3, NULL, $4, true, NOW(), NOW())
|
||||
""",
|
||||
webhook_id,
|
||||
bank_id,
|
||||
"https://example.com/retain-hook",
|
||||
["retain.completed"],
|
||||
)
|
||||
|
||||
try:
|
||||
contents = [
|
||||
{"content": "Alice works at Google", "document_id": "doc-1"},
|
||||
{"content": "Bob loves Python", "document_id": "doc-2"},
|
||||
]
|
||||
# Temporarily replace webhook manager on memory engine
|
||||
original_manager = memory._webhook_manager
|
||||
memory._webhook_manager = webhook_manager
|
||||
try:
|
||||
callback = memory._build_retain_outbox_callback(
|
||||
bank_id=bank_id,
|
||||
contents=contents,
|
||||
operation_id="test-op-123",
|
||||
)
|
||||
assert callback is not None
|
||||
async with memory._pool.acquire() as conn:
|
||||
await callback(conn)
|
||||
finally:
|
||||
memory._webhook_manager = original_manager
|
||||
|
||||
async with memory._pool.acquire() as conn:
|
||||
rows = await conn.fetch(
|
||||
"""
|
||||
SELECT task_payload
|
||||
FROM async_operations
|
||||
WHERE operation_type = 'webhook_delivery'
|
||||
AND bank_id = $1
|
||||
AND task_payload->>'event_type' = 'retain.completed'
|
||||
ORDER BY created_at
|
||||
""",
|
||||
bank_id,
|
||||
)
|
||||
|
||||
assert len(rows) == 2
|
||||
payloads = []
|
||||
for row in rows:
|
||||
p = row["task_payload"]
|
||||
if isinstance(p, str):
|
||||
p = json.loads(p)
|
||||
payloads.append(p)
|
||||
|
||||
doc_ids_in_payloads = [json.loads(p["payload"]).get("data", {}).get("document_id") for p in payloads]
|
||||
assert "doc-1" in doc_ids_in_payloads
|
||||
assert "doc-2" in doc_ids_in_payloads
|
||||
finally:
|
||||
async with memory._pool.acquire() as conn:
|
||||
await conn.execute(
|
||||
"DELETE FROM async_operations WHERE operation_type = 'webhook_delivery' AND bank_id = $1",
|
||||
bank_id,
|
||||
)
|
||||
await conn.execute("DELETE FROM webhooks WHERE id = $1", webhook_id)
|
||||
|
|
@ -294,14 +294,17 @@ class TestWorkerPoller:
|
|||
payload,
|
||||
)
|
||||
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from hindsight_api.worker.exceptions import RetryTaskAt
|
||||
|
||||
async def failing_executor(task_dict):
|
||||
raise ValueError("TimeoutError during recall")
|
||||
raise RetryTaskAt(retry_at=datetime.now(timezone.utc), message="TimeoutError during recall")
|
||||
|
||||
poller = WorkerPoller(
|
||||
pool=pool,
|
||||
worker_id="test-worker-1",
|
||||
executor=failing_executor,
|
||||
max_retries=3,
|
||||
)
|
||||
|
||||
task_dict = json.loads(payload)
|
||||
|
|
@ -326,39 +329,35 @@ class TestWorkerPoller:
|
|||
assert row["retry_count"] == 1
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_executor_exception_marks_failed_after_max_retries(self, pool, clean_operations):
|
||||
"""Test that a task is permanently marked 'failed' once retry_count hits max_retries.
|
||||
async def test_executor_exception_marks_failed_immediately(self, pool, clean_operations):
|
||||
"""Test that a plain exception (not RetryTaskAt) permanently marks a task as 'failed'.
|
||||
|
||||
After max_retries exhaustion the task must NOT be reset to 'pending' — it should
|
||||
be marked 'failed' with an error message so it stops consuming retry budget.
|
||||
With the task-owned retry model, plain exceptions are non-retryable — the poller
|
||||
marks them as 'failed' immediately. Tasks that want to be retried must raise RetryTaskAt.
|
||||
"""
|
||||
from hindsight_api.worker import WorkerPoller
|
||||
from hindsight_api.worker.poller import ClaimedTask
|
||||
|
||||
max_retries = 3
|
||||
bank_id = f"test-worker-{uuid.uuid4().hex[:8]}"
|
||||
op_id = uuid.uuid4()
|
||||
payload = json.dumps({"type": "consolidation", "operation_id": str(op_id), "bank_id": bank_id})
|
||||
# Insert with retry_count already at the limit
|
||||
await pool.execute(
|
||||
"""
|
||||
INSERT INTO async_operations (operation_id, bank_id, operation_type, status, task_payload, worker_id, claimed_at, retry_count)
|
||||
VALUES ($1, $2, 'consolidation', 'processing', $3::jsonb, 'test-worker-1', now(), $4)
|
||||
VALUES ($1, $2, 'consolidation', 'processing', $3::jsonb, 'test-worker-1', now(), 0)
|
||||
""",
|
||||
op_id,
|
||||
bank_id,
|
||||
payload,
|
||||
max_retries,
|
||||
)
|
||||
|
||||
async def failing_executor(task_dict):
|
||||
raise ValueError("Still failing after all retries")
|
||||
raise ValueError("Non-retryable error")
|
||||
|
||||
poller = WorkerPoller(
|
||||
pool=pool,
|
||||
worker_id="test-worker-1",
|
||||
executor=failing_executor,
|
||||
max_retries=max_retries,
|
||||
)
|
||||
|
||||
task_dict = json.loads(payload)
|
||||
|
|
@ -373,11 +372,10 @@ class TestWorkerPoller:
|
|||
op_id,
|
||||
)
|
||||
assert row["status"] == "failed", (
|
||||
f"Expected 'failed' after max retries, got '{row['status']}'"
|
||||
f"Expected 'failed' for plain exception, got '{row['status']}'"
|
||||
)
|
||||
assert row["error_message"] is not None
|
||||
assert "Max retries" in row["error_message"]
|
||||
assert row["retry_count"] == max_retries # not incremented further
|
||||
assert row["retry_count"] == 0 # not incremented; plain exception = immediate fail
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_executor_failed_status_not_overridden(self, pool, clean_operations):
|
||||
|
|
|
|||
|
|
@ -2111,6 +2111,248 @@ paths:
|
|||
summary: Trigger consolidation
|
||||
tags:
|
||||
- Banks
|
||||
/v1/default/banks/{bank_id}/webhooks:
|
||||
get:
|
||||
description: List all webhooks registered for a bank.
|
||||
operationId: list_webhooks
|
||||
parameters:
|
||||
- explode: false
|
||||
in: path
|
||||
name: bank_id
|
||||
required: true
|
||||
schema:
|
||||
title: Bank Id
|
||||
type: string
|
||||
style: simple
|
||||
- explode: false
|
||||
in: header
|
||||
name: authorization
|
||||
required: false
|
||||
schema:
|
||||
nullable: true
|
||||
type: string
|
||||
style: simple
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/WebhookListResponse'
|
||||
description: Successful Response
|
||||
"422":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/HTTPValidationError'
|
||||
description: Validation Error
|
||||
summary: List webhooks
|
||||
tags:
|
||||
- Webhooks
|
||||
post:
|
||||
description: Register a webhook endpoint to receive event notifications for
|
||||
this bank.
|
||||
operationId: create_webhook
|
||||
parameters:
|
||||
- explode: false
|
||||
in: path
|
||||
name: bank_id
|
||||
required: true
|
||||
schema:
|
||||
title: Bank Id
|
||||
type: string
|
||||
style: simple
|
||||
- explode: false
|
||||
in: header
|
||||
name: authorization
|
||||
required: false
|
||||
schema:
|
||||
nullable: true
|
||||
type: string
|
||||
style: simple
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CreateWebhookRequest'
|
||||
required: true
|
||||
responses:
|
||||
"201":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/WebhookResponse'
|
||||
description: Successful Response
|
||||
"422":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/HTTPValidationError'
|
||||
description: Validation Error
|
||||
summary: Register webhook
|
||||
tags:
|
||||
- Webhooks
|
||||
/v1/default/banks/{bank_id}/webhooks/{webhook_id}:
|
||||
delete:
|
||||
description: Remove a registered webhook.
|
||||
operationId: delete_webhook
|
||||
parameters:
|
||||
- explode: false
|
||||
in: path
|
||||
name: bank_id
|
||||
required: true
|
||||
schema:
|
||||
title: Bank Id
|
||||
type: string
|
||||
style: simple
|
||||
- explode: false
|
||||
in: path
|
||||
name: webhook_id
|
||||
required: true
|
||||
schema:
|
||||
title: Webhook Id
|
||||
type: string
|
||||
style: simple
|
||||
- explode: false
|
||||
in: header
|
||||
name: authorization
|
||||
required: false
|
||||
schema:
|
||||
nullable: true
|
||||
type: string
|
||||
style: simple
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/DeleteResponse'
|
||||
description: Successful Response
|
||||
"422":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/HTTPValidationError'
|
||||
description: Validation Error
|
||||
summary: Delete webhook
|
||||
tags:
|
||||
- Webhooks
|
||||
patch:
|
||||
description: Update one or more fields of a registered webhook. Only provided
|
||||
fields are changed.
|
||||
operationId: update_webhook
|
||||
parameters:
|
||||
- explode: false
|
||||
in: path
|
||||
name: bank_id
|
||||
required: true
|
||||
schema:
|
||||
title: Bank Id
|
||||
type: string
|
||||
style: simple
|
||||
- explode: false
|
||||
in: path
|
||||
name: webhook_id
|
||||
required: true
|
||||
schema:
|
||||
title: Webhook Id
|
||||
type: string
|
||||
style: simple
|
||||
- explode: false
|
||||
in: header
|
||||
name: authorization
|
||||
required: false
|
||||
schema:
|
||||
nullable: true
|
||||
type: string
|
||||
style: simple
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/UpdateWebhookRequest'
|
||||
required: true
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/WebhookResponse'
|
||||
description: Successful Response
|
||||
"422":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/HTTPValidationError'
|
||||
description: Validation Error
|
||||
summary: Update webhook
|
||||
tags:
|
||||
- Webhooks
|
||||
/v1/default/banks/{bank_id}/webhooks/{webhook_id}/deliveries:
|
||||
get:
|
||||
description: Inspect delivery history for a webhook (useful for debugging).
|
||||
operationId: list_webhook_deliveries
|
||||
parameters:
|
||||
- explode: false
|
||||
in: path
|
||||
name: bank_id
|
||||
required: true
|
||||
schema:
|
||||
title: Bank Id
|
||||
type: string
|
||||
style: simple
|
||||
- explode: false
|
||||
in: path
|
||||
name: webhook_id
|
||||
required: true
|
||||
schema:
|
||||
title: Webhook Id
|
||||
type: string
|
||||
style: simple
|
||||
- description: Maximum number of deliveries to return
|
||||
explode: true
|
||||
in: query
|
||||
name: limit
|
||||
required: false
|
||||
schema:
|
||||
default: 50
|
||||
description: Maximum number of deliveries to return
|
||||
maximum: 200
|
||||
title: Limit
|
||||
type: integer
|
||||
style: form
|
||||
- description: Pagination cursor (created_at of last item)
|
||||
explode: true
|
||||
in: query
|
||||
name: cursor
|
||||
required: false
|
||||
schema:
|
||||
nullable: true
|
||||
type: string
|
||||
style: form
|
||||
- explode: false
|
||||
in: header
|
||||
name: authorization
|
||||
required: false
|
||||
schema:
|
||||
nullable: true
|
||||
type: string
|
||||
style: simple
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/WebhookDeliveryListResponse'
|
||||
description: Successful Response
|
||||
"422":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/HTTPValidationError'
|
||||
description: Validation Error
|
||||
summary: List webhook deliveries
|
||||
tags:
|
||||
- Webhooks
|
||||
/v1/default/banks/{bank_id}/memories:
|
||||
delete:
|
||||
description: "Delete memory units for a memory bank. Optionally filter by type\
|
||||
|
|
@ -2879,6 +3121,47 @@ components:
|
|||
required:
|
||||
- operation_id
|
||||
title: CreateMentalModelResponse
|
||||
CreateWebhookRequest:
|
||||
description: Request model for registering a webhook.
|
||||
example:
|
||||
event_types:
|
||||
- event_types
|
||||
- event_types
|
||||
secret: secret
|
||||
http_config:
|
||||
headers:
|
||||
key: headers
|
||||
method: POST
|
||||
timeout_seconds: 0
|
||||
params:
|
||||
key: params
|
||||
url: url
|
||||
enabled: true
|
||||
properties:
|
||||
url:
|
||||
description: HTTP(S) endpoint URL to deliver events to
|
||||
title: Url
|
||||
type: string
|
||||
secret:
|
||||
nullable: true
|
||||
type: string
|
||||
event_types:
|
||||
default:
|
||||
- consolidation.completed
|
||||
description: "List of event types to deliver. Currently supported: 'consolidation.completed'"
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
enabled:
|
||||
default: true
|
||||
description: Whether this webhook is active
|
||||
title: Enabled
|
||||
type: boolean
|
||||
http_config:
|
||||
$ref: '#/components/schemas/WebhookHttpConfig'
|
||||
required:
|
||||
- url
|
||||
title: CreateWebhookRequest
|
||||
DeleteDocumentResponse:
|
||||
description: Response model for delete document endpoint.
|
||||
example:
|
||||
|
|
@ -4437,6 +4720,41 @@ components:
|
|||
trigger:
|
||||
$ref: '#/components/schemas/MentalModelTrigger'
|
||||
title: UpdateMentalModelRequest
|
||||
UpdateWebhookRequest:
|
||||
description: Request model for updating a webhook. Only provided fields are
|
||||
updated.
|
||||
example:
|
||||
event_types:
|
||||
- event_types
|
||||
- event_types
|
||||
secret: secret
|
||||
http_config:
|
||||
headers:
|
||||
key: headers
|
||||
method: POST
|
||||
timeout_seconds: 0
|
||||
params:
|
||||
key: params
|
||||
url: url
|
||||
enabled: true
|
||||
properties:
|
||||
url:
|
||||
nullable: true
|
||||
type: string
|
||||
secret:
|
||||
nullable: true
|
||||
type: string
|
||||
event_types:
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
enabled:
|
||||
nullable: true
|
||||
type: boolean
|
||||
http_config:
|
||||
$ref: '#/components/schemas/WebhookHttpConfig'
|
||||
title: UpdateWebhookRequest
|
||||
ValidationError:
|
||||
example:
|
||||
msg: msg
|
||||
|
|
@ -4481,6 +4799,244 @@ components:
|
|||
- api_version
|
||||
- features
|
||||
title: VersionResponse
|
||||
WebhookDeliveryListResponse:
|
||||
description: Response model for listing webhook deliveries.
|
||||
example:
|
||||
next_cursor: next_cursor
|
||||
items:
|
||||
- last_response_body: last_response_body
|
||||
last_attempt_at: last_attempt_at
|
||||
created_at: created_at
|
||||
last_response_status: 6
|
||||
url: url
|
||||
event_type: event_type
|
||||
updated_at: updated_at
|
||||
webhook_id: webhook_id
|
||||
next_retry_at: next_retry_at
|
||||
id: id
|
||||
last_error: last_error
|
||||
status: status
|
||||
attempts: 0
|
||||
- last_response_body: last_response_body
|
||||
last_attempt_at: last_attempt_at
|
||||
created_at: created_at
|
||||
last_response_status: 6
|
||||
url: url
|
||||
event_type: event_type
|
||||
updated_at: updated_at
|
||||
webhook_id: webhook_id
|
||||
next_retry_at: next_retry_at
|
||||
id: id
|
||||
last_error: last_error
|
||||
status: status
|
||||
attempts: 0
|
||||
properties:
|
||||
items:
|
||||
items:
|
||||
$ref: '#/components/schemas/WebhookDeliveryResponse'
|
||||
type: array
|
||||
next_cursor:
|
||||
nullable: true
|
||||
type: string
|
||||
required:
|
||||
- items
|
||||
title: WebhookDeliveryListResponse
|
||||
WebhookDeliveryResponse:
|
||||
description: Response model for a webhook delivery record.
|
||||
example:
|
||||
last_response_body: last_response_body
|
||||
last_attempt_at: last_attempt_at
|
||||
created_at: created_at
|
||||
last_response_status: 6
|
||||
url: url
|
||||
event_type: event_type
|
||||
updated_at: updated_at
|
||||
webhook_id: webhook_id
|
||||
next_retry_at: next_retry_at
|
||||
id: id
|
||||
last_error: last_error
|
||||
status: status
|
||||
attempts: 0
|
||||
properties:
|
||||
id:
|
||||
title: Id
|
||||
type: string
|
||||
webhook_id:
|
||||
nullable: true
|
||||
type: string
|
||||
url:
|
||||
title: Url
|
||||
type: string
|
||||
event_type:
|
||||
title: Event Type
|
||||
type: string
|
||||
status:
|
||||
title: Status
|
||||
type: string
|
||||
attempts:
|
||||
title: Attempts
|
||||
type: integer
|
||||
next_retry_at:
|
||||
nullable: true
|
||||
type: string
|
||||
last_error:
|
||||
nullable: true
|
||||
type: string
|
||||
last_response_status:
|
||||
nullable: true
|
||||
type: integer
|
||||
last_response_body:
|
||||
nullable: true
|
||||
type: string
|
||||
last_attempt_at:
|
||||
nullable: true
|
||||
type: string
|
||||
created_at:
|
||||
nullable: true
|
||||
type: string
|
||||
updated_at:
|
||||
nullable: true
|
||||
type: string
|
||||
required:
|
||||
- attempts
|
||||
- event_type
|
||||
- id
|
||||
- status
|
||||
- url
|
||||
- webhook_id
|
||||
title: WebhookDeliveryResponse
|
||||
WebhookHttpConfig:
|
||||
description: HTTP delivery configuration for a webhook.
|
||||
example:
|
||||
headers:
|
||||
key: headers
|
||||
method: POST
|
||||
timeout_seconds: 0
|
||||
params:
|
||||
key: params
|
||||
properties:
|
||||
method:
|
||||
default: POST
|
||||
description: "HTTP method: GET or POST"
|
||||
title: Method
|
||||
type: string
|
||||
timeout_seconds:
|
||||
default: 30
|
||||
description: HTTP request timeout in seconds
|
||||
title: Timeout Seconds
|
||||
type: integer
|
||||
headers:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: Custom HTTP headers
|
||||
title: Headers
|
||||
params:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: Custom HTTP query parameters
|
||||
title: Params
|
||||
title: WebhookHttpConfig
|
||||
WebhookListResponse:
|
||||
description: Response model for listing webhooks.
|
||||
example:
|
||||
items:
|
||||
- event_types:
|
||||
- event_types
|
||||
- event_types
|
||||
updated_at: updated_at
|
||||
bank_id: bank_id
|
||||
created_at: created_at
|
||||
id: id
|
||||
secret: secret
|
||||
http_config:
|
||||
headers:
|
||||
key: headers
|
||||
method: POST
|
||||
timeout_seconds: 0
|
||||
params:
|
||||
key: params
|
||||
url: url
|
||||
enabled: true
|
||||
- event_types:
|
||||
- event_types
|
||||
- event_types
|
||||
updated_at: updated_at
|
||||
bank_id: bank_id
|
||||
created_at: created_at
|
||||
id: id
|
||||
secret: secret
|
||||
http_config:
|
||||
headers:
|
||||
key: headers
|
||||
method: POST
|
||||
timeout_seconds: 0
|
||||
params:
|
||||
key: params
|
||||
url: url
|
||||
enabled: true
|
||||
properties:
|
||||
items:
|
||||
items:
|
||||
$ref: '#/components/schemas/WebhookResponse'
|
||||
type: array
|
||||
required:
|
||||
- items
|
||||
title: WebhookListResponse
|
||||
WebhookResponse:
|
||||
description: Response model for a webhook.
|
||||
example:
|
||||
event_types:
|
||||
- event_types
|
||||
- event_types
|
||||
updated_at: updated_at
|
||||
bank_id: bank_id
|
||||
created_at: created_at
|
||||
id: id
|
||||
secret: secret
|
||||
http_config:
|
||||
headers:
|
||||
key: headers
|
||||
method: POST
|
||||
timeout_seconds: 0
|
||||
params:
|
||||
key: params
|
||||
url: url
|
||||
enabled: true
|
||||
properties:
|
||||
id:
|
||||
title: Id
|
||||
type: string
|
||||
bank_id:
|
||||
nullable: true
|
||||
type: string
|
||||
url:
|
||||
title: Url
|
||||
type: string
|
||||
secret:
|
||||
nullable: true
|
||||
type: string
|
||||
event_types:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
enabled:
|
||||
title: Enabled
|
||||
type: boolean
|
||||
http_config:
|
||||
$ref: '#/components/schemas/WebhookHttpConfig'
|
||||
created_at:
|
||||
nullable: true
|
||||
type: string
|
||||
updated_at:
|
||||
nullable: true
|
||||
type: string
|
||||
required:
|
||||
- bank_id
|
||||
- enabled
|
||||
- event_types
|
||||
- id
|
||||
- url
|
||||
title: WebhookResponse
|
||||
Timestamp:
|
||||
anyOf:
|
||||
- format: date-time
|
||||
|
|
|
|||
691
hindsight-clients/go/api_webhooks.go
Normal file
691
hindsight-clients/go/api_webhooks.go
Normal file
|
|
@ -0,0 +1,691 @@
|
|||
/*
|
||||
Hindsight HTTP API
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
API version: 0.4.15
|
||||
*/
|
||||
|
||||
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
|
||||
|
||||
package hindsight
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
||||
// WebhooksAPIService WebhooksAPI service
|
||||
type WebhooksAPIService service
|
||||
|
||||
type ApiCreateWebhookRequest struct {
|
||||
ctx context.Context
|
||||
ApiService *WebhooksAPIService
|
||||
bankId string
|
||||
createWebhookRequest *CreateWebhookRequest
|
||||
authorization *string
|
||||
}
|
||||
|
||||
func (r ApiCreateWebhookRequest) CreateWebhookRequest(createWebhookRequest CreateWebhookRequest) ApiCreateWebhookRequest {
|
||||
r.createWebhookRequest = &createWebhookRequest
|
||||
return r
|
||||
}
|
||||
|
||||
func (r ApiCreateWebhookRequest) Authorization(authorization string) ApiCreateWebhookRequest {
|
||||
r.authorization = &authorization
|
||||
return r
|
||||
}
|
||||
|
||||
func (r ApiCreateWebhookRequest) Execute() (*WebhookResponse, *http.Response, error) {
|
||||
return r.ApiService.CreateWebhookExecute(r)
|
||||
}
|
||||
|
||||
/*
|
||||
CreateWebhook Register webhook
|
||||
|
||||
Register a webhook endpoint to receive event notifications for this bank.
|
||||
|
||||
@param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
|
||||
@param bankId
|
||||
@return ApiCreateWebhookRequest
|
||||
*/
|
||||
func (a *WebhooksAPIService) CreateWebhook(ctx context.Context, bankId string) ApiCreateWebhookRequest {
|
||||
return ApiCreateWebhookRequest{
|
||||
ApiService: a,
|
||||
ctx: ctx,
|
||||
bankId: bankId,
|
||||
}
|
||||
}
|
||||
|
||||
// Execute executes the request
|
||||
// @return WebhookResponse
|
||||
func (a *WebhooksAPIService) CreateWebhookExecute(r ApiCreateWebhookRequest) (*WebhookResponse, *http.Response, error) {
|
||||
var (
|
||||
localVarHTTPMethod = http.MethodPost
|
||||
localVarPostBody interface{}
|
||||
formFiles []formFile
|
||||
localVarReturnValue *WebhookResponse
|
||||
)
|
||||
|
||||
localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WebhooksAPIService.CreateWebhook")
|
||||
if err != nil {
|
||||
return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()}
|
||||
}
|
||||
|
||||
localVarPath := localBasePath + "/v1/default/banks/{bank_id}/webhooks"
|
||||
localVarPath = strings.Replace(localVarPath, "{"+"bank_id"+"}", url.PathEscape(parameterValueToString(r.bankId, "bankId")), -1)
|
||||
|
||||
localVarHeaderParams := make(map[string]string)
|
||||
localVarQueryParams := url.Values{}
|
||||
localVarFormParams := url.Values{}
|
||||
if r.createWebhookRequest == nil {
|
||||
return localVarReturnValue, nil, reportError("createWebhookRequest is required and must be specified")
|
||||
}
|
||||
|
||||
// to determine the Content-Type header
|
||||
localVarHTTPContentTypes := []string{"application/json"}
|
||||
|
||||
// set Content-Type header
|
||||
localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes)
|
||||
if localVarHTTPContentType != "" {
|
||||
localVarHeaderParams["Content-Type"] = localVarHTTPContentType
|
||||
}
|
||||
|
||||
// to determine the Accept header
|
||||
localVarHTTPHeaderAccepts := []string{"application/json"}
|
||||
|
||||
// set Accept header
|
||||
localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts)
|
||||
if localVarHTTPHeaderAccept != "" {
|
||||
localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept
|
||||
}
|
||||
if r.authorization != nil {
|
||||
parameterAddToHeaderOrQuery(localVarHeaderParams, "authorization", r.authorization, "simple", "")
|
||||
}
|
||||
// body params
|
||||
localVarPostBody = r.createWebhookRequest
|
||||
req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles)
|
||||
if err != nil {
|
||||
return localVarReturnValue, nil, err
|
||||
}
|
||||
|
||||
localVarHTTPResponse, err := a.client.callAPI(req)
|
||||
if err != nil || localVarHTTPResponse == nil {
|
||||
return localVarReturnValue, localVarHTTPResponse, err
|
||||
}
|
||||
|
||||
localVarBody, err := io.ReadAll(localVarHTTPResponse.Body)
|
||||
localVarHTTPResponse.Body.Close()
|
||||
localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody))
|
||||
if err != nil {
|
||||
return localVarReturnValue, localVarHTTPResponse, err
|
||||
}
|
||||
|
||||
if localVarHTTPResponse.StatusCode >= 300 {
|
||||
newErr := &GenericOpenAPIError{
|
||||
body: localVarBody,
|
||||
error: localVarHTTPResponse.Status,
|
||||
}
|
||||
if localVarHTTPResponse.StatusCode == 422 {
|
||||
var v HTTPValidationError
|
||||
err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
|
||||
if err != nil {
|
||||
newErr.error = err.Error()
|
||||
return localVarReturnValue, localVarHTTPResponse, newErr
|
||||
}
|
||||
newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v)
|
||||
newErr.model = v
|
||||
}
|
||||
return localVarReturnValue, localVarHTTPResponse, newErr
|
||||
}
|
||||
|
||||
err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
|
||||
if err != nil {
|
||||
newErr := &GenericOpenAPIError{
|
||||
body: localVarBody,
|
||||
error: err.Error(),
|
||||
}
|
||||
return localVarReturnValue, localVarHTTPResponse, newErr
|
||||
}
|
||||
|
||||
return localVarReturnValue, localVarHTTPResponse, nil
|
||||
}
|
||||
|
||||
type ApiDeleteWebhookRequest struct {
|
||||
ctx context.Context
|
||||
ApiService *WebhooksAPIService
|
||||
bankId string
|
||||
webhookId string
|
||||
authorization *string
|
||||
}
|
||||
|
||||
func (r ApiDeleteWebhookRequest) Authorization(authorization string) ApiDeleteWebhookRequest {
|
||||
r.authorization = &authorization
|
||||
return r
|
||||
}
|
||||
|
||||
func (r ApiDeleteWebhookRequest) Execute() (*DeleteResponse, *http.Response, error) {
|
||||
return r.ApiService.DeleteWebhookExecute(r)
|
||||
}
|
||||
|
||||
/*
|
||||
DeleteWebhook Delete webhook
|
||||
|
||||
Remove a registered webhook.
|
||||
|
||||
@param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
|
||||
@param bankId
|
||||
@param webhookId
|
||||
@return ApiDeleteWebhookRequest
|
||||
*/
|
||||
func (a *WebhooksAPIService) DeleteWebhook(ctx context.Context, bankId string, webhookId string) ApiDeleteWebhookRequest {
|
||||
return ApiDeleteWebhookRequest{
|
||||
ApiService: a,
|
||||
ctx: ctx,
|
||||
bankId: bankId,
|
||||
webhookId: webhookId,
|
||||
}
|
||||
}
|
||||
|
||||
// Execute executes the request
|
||||
// @return DeleteResponse
|
||||
func (a *WebhooksAPIService) DeleteWebhookExecute(r ApiDeleteWebhookRequest) (*DeleteResponse, *http.Response, error) {
|
||||
var (
|
||||
localVarHTTPMethod = http.MethodDelete
|
||||
localVarPostBody interface{}
|
||||
formFiles []formFile
|
||||
localVarReturnValue *DeleteResponse
|
||||
)
|
||||
|
||||
localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WebhooksAPIService.DeleteWebhook")
|
||||
if err != nil {
|
||||
return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()}
|
||||
}
|
||||
|
||||
localVarPath := localBasePath + "/v1/default/banks/{bank_id}/webhooks/{webhook_id}"
|
||||
localVarPath = strings.Replace(localVarPath, "{"+"bank_id"+"}", url.PathEscape(parameterValueToString(r.bankId, "bankId")), -1)
|
||||
localVarPath = strings.Replace(localVarPath, "{"+"webhook_id"+"}", url.PathEscape(parameterValueToString(r.webhookId, "webhookId")), -1)
|
||||
|
||||
localVarHeaderParams := make(map[string]string)
|
||||
localVarQueryParams := url.Values{}
|
||||
localVarFormParams := url.Values{}
|
||||
|
||||
// to determine the Content-Type header
|
||||
localVarHTTPContentTypes := []string{}
|
||||
|
||||
// set Content-Type header
|
||||
localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes)
|
||||
if localVarHTTPContentType != "" {
|
||||
localVarHeaderParams["Content-Type"] = localVarHTTPContentType
|
||||
}
|
||||
|
||||
// to determine the Accept header
|
||||
localVarHTTPHeaderAccepts := []string{"application/json"}
|
||||
|
||||
// set Accept header
|
||||
localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts)
|
||||
if localVarHTTPHeaderAccept != "" {
|
||||
localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept
|
||||
}
|
||||
if r.authorization != nil {
|
||||
parameterAddToHeaderOrQuery(localVarHeaderParams, "authorization", r.authorization, "simple", "")
|
||||
}
|
||||
req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles)
|
||||
if err != nil {
|
||||
return localVarReturnValue, nil, err
|
||||
}
|
||||
|
||||
localVarHTTPResponse, err := a.client.callAPI(req)
|
||||
if err != nil || localVarHTTPResponse == nil {
|
||||
return localVarReturnValue, localVarHTTPResponse, err
|
||||
}
|
||||
|
||||
localVarBody, err := io.ReadAll(localVarHTTPResponse.Body)
|
||||
localVarHTTPResponse.Body.Close()
|
||||
localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody))
|
||||
if err != nil {
|
||||
return localVarReturnValue, localVarHTTPResponse, err
|
||||
}
|
||||
|
||||
if localVarHTTPResponse.StatusCode >= 300 {
|
||||
newErr := &GenericOpenAPIError{
|
||||
body: localVarBody,
|
||||
error: localVarHTTPResponse.Status,
|
||||
}
|
||||
if localVarHTTPResponse.StatusCode == 422 {
|
||||
var v HTTPValidationError
|
||||
err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
|
||||
if err != nil {
|
||||
newErr.error = err.Error()
|
||||
return localVarReturnValue, localVarHTTPResponse, newErr
|
||||
}
|
||||
newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v)
|
||||
newErr.model = v
|
||||
}
|
||||
return localVarReturnValue, localVarHTTPResponse, newErr
|
||||
}
|
||||
|
||||
err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
|
||||
if err != nil {
|
||||
newErr := &GenericOpenAPIError{
|
||||
body: localVarBody,
|
||||
error: err.Error(),
|
||||
}
|
||||
return localVarReturnValue, localVarHTTPResponse, newErr
|
||||
}
|
||||
|
||||
return localVarReturnValue, localVarHTTPResponse, nil
|
||||
}
|
||||
|
||||
type ApiListWebhookDeliveriesRequest struct {
|
||||
ctx context.Context
|
||||
ApiService *WebhooksAPIService
|
||||
bankId string
|
||||
webhookId string
|
||||
limit *int32
|
||||
cursor *string
|
||||
authorization *string
|
||||
}
|
||||
|
||||
// Maximum number of deliveries to return
|
||||
func (r ApiListWebhookDeliveriesRequest) Limit(limit int32) ApiListWebhookDeliveriesRequest {
|
||||
r.limit = &limit
|
||||
return r
|
||||
}
|
||||
|
||||
// Pagination cursor (created_at of last item)
|
||||
func (r ApiListWebhookDeliveriesRequest) Cursor(cursor string) ApiListWebhookDeliveriesRequest {
|
||||
r.cursor = &cursor
|
||||
return r
|
||||
}
|
||||
|
||||
func (r ApiListWebhookDeliveriesRequest) Authorization(authorization string) ApiListWebhookDeliveriesRequest {
|
||||
r.authorization = &authorization
|
||||
return r
|
||||
}
|
||||
|
||||
func (r ApiListWebhookDeliveriesRequest) Execute() (*WebhookDeliveryListResponse, *http.Response, error) {
|
||||
return r.ApiService.ListWebhookDeliveriesExecute(r)
|
||||
}
|
||||
|
||||
/*
|
||||
ListWebhookDeliveries List webhook deliveries
|
||||
|
||||
Inspect delivery history for a webhook (useful for debugging).
|
||||
|
||||
@param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
|
||||
@param bankId
|
||||
@param webhookId
|
||||
@return ApiListWebhookDeliveriesRequest
|
||||
*/
|
||||
func (a *WebhooksAPIService) ListWebhookDeliveries(ctx context.Context, bankId string, webhookId string) ApiListWebhookDeliveriesRequest {
|
||||
return ApiListWebhookDeliveriesRequest{
|
||||
ApiService: a,
|
||||
ctx: ctx,
|
||||
bankId: bankId,
|
||||
webhookId: webhookId,
|
||||
}
|
||||
}
|
||||
|
||||
// Execute executes the request
|
||||
// @return WebhookDeliveryListResponse
|
||||
func (a *WebhooksAPIService) ListWebhookDeliveriesExecute(r ApiListWebhookDeliveriesRequest) (*WebhookDeliveryListResponse, *http.Response, error) {
|
||||
var (
|
||||
localVarHTTPMethod = http.MethodGet
|
||||
localVarPostBody interface{}
|
||||
formFiles []formFile
|
||||
localVarReturnValue *WebhookDeliveryListResponse
|
||||
)
|
||||
|
||||
localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WebhooksAPIService.ListWebhookDeliveries")
|
||||
if err != nil {
|
||||
return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()}
|
||||
}
|
||||
|
||||
localVarPath := localBasePath + "/v1/default/banks/{bank_id}/webhooks/{webhook_id}/deliveries"
|
||||
localVarPath = strings.Replace(localVarPath, "{"+"bank_id"+"}", url.PathEscape(parameterValueToString(r.bankId, "bankId")), -1)
|
||||
localVarPath = strings.Replace(localVarPath, "{"+"webhook_id"+"}", url.PathEscape(parameterValueToString(r.webhookId, "webhookId")), -1)
|
||||
|
||||
localVarHeaderParams := make(map[string]string)
|
||||
localVarQueryParams := url.Values{}
|
||||
localVarFormParams := url.Values{}
|
||||
|
||||
if r.limit != nil {
|
||||
parameterAddToHeaderOrQuery(localVarQueryParams, "limit", r.limit, "form", "")
|
||||
} else {
|
||||
var defaultValue int32 = 50
|
||||
r.limit = &defaultValue
|
||||
}
|
||||
if r.cursor != nil {
|
||||
parameterAddToHeaderOrQuery(localVarQueryParams, "cursor", r.cursor, "form", "")
|
||||
}
|
||||
// to determine the Content-Type header
|
||||
localVarHTTPContentTypes := []string{}
|
||||
|
||||
// set Content-Type header
|
||||
localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes)
|
||||
if localVarHTTPContentType != "" {
|
||||
localVarHeaderParams["Content-Type"] = localVarHTTPContentType
|
||||
}
|
||||
|
||||
// to determine the Accept header
|
||||
localVarHTTPHeaderAccepts := []string{"application/json"}
|
||||
|
||||
// set Accept header
|
||||
localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts)
|
||||
if localVarHTTPHeaderAccept != "" {
|
||||
localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept
|
||||
}
|
||||
if r.authorization != nil {
|
||||
parameterAddToHeaderOrQuery(localVarHeaderParams, "authorization", r.authorization, "simple", "")
|
||||
}
|
||||
req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles)
|
||||
if err != nil {
|
||||
return localVarReturnValue, nil, err
|
||||
}
|
||||
|
||||
localVarHTTPResponse, err := a.client.callAPI(req)
|
||||
if err != nil || localVarHTTPResponse == nil {
|
||||
return localVarReturnValue, localVarHTTPResponse, err
|
||||
}
|
||||
|
||||
localVarBody, err := io.ReadAll(localVarHTTPResponse.Body)
|
||||
localVarHTTPResponse.Body.Close()
|
||||
localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody))
|
||||
if err != nil {
|
||||
return localVarReturnValue, localVarHTTPResponse, err
|
||||
}
|
||||
|
||||
if localVarHTTPResponse.StatusCode >= 300 {
|
||||
newErr := &GenericOpenAPIError{
|
||||
body: localVarBody,
|
||||
error: localVarHTTPResponse.Status,
|
||||
}
|
||||
if localVarHTTPResponse.StatusCode == 422 {
|
||||
var v HTTPValidationError
|
||||
err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
|
||||
if err != nil {
|
||||
newErr.error = err.Error()
|
||||
return localVarReturnValue, localVarHTTPResponse, newErr
|
||||
}
|
||||
newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v)
|
||||
newErr.model = v
|
||||
}
|
||||
return localVarReturnValue, localVarHTTPResponse, newErr
|
||||
}
|
||||
|
||||
err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
|
||||
if err != nil {
|
||||
newErr := &GenericOpenAPIError{
|
||||
body: localVarBody,
|
||||
error: err.Error(),
|
||||
}
|
||||
return localVarReturnValue, localVarHTTPResponse, newErr
|
||||
}
|
||||
|
||||
return localVarReturnValue, localVarHTTPResponse, nil
|
||||
}
|
||||
|
||||
type ApiListWebhooksRequest struct {
|
||||
ctx context.Context
|
||||
ApiService *WebhooksAPIService
|
||||
bankId string
|
||||
authorization *string
|
||||
}
|
||||
|
||||
func (r ApiListWebhooksRequest) Authorization(authorization string) ApiListWebhooksRequest {
|
||||
r.authorization = &authorization
|
||||
return r
|
||||
}
|
||||
|
||||
func (r ApiListWebhooksRequest) Execute() (*WebhookListResponse, *http.Response, error) {
|
||||
return r.ApiService.ListWebhooksExecute(r)
|
||||
}
|
||||
|
||||
/*
|
||||
ListWebhooks List webhooks
|
||||
|
||||
List all webhooks registered for a bank.
|
||||
|
||||
@param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
|
||||
@param bankId
|
||||
@return ApiListWebhooksRequest
|
||||
*/
|
||||
func (a *WebhooksAPIService) ListWebhooks(ctx context.Context, bankId string) ApiListWebhooksRequest {
|
||||
return ApiListWebhooksRequest{
|
||||
ApiService: a,
|
||||
ctx: ctx,
|
||||
bankId: bankId,
|
||||
}
|
||||
}
|
||||
|
||||
// Execute executes the request
|
||||
// @return WebhookListResponse
|
||||
func (a *WebhooksAPIService) ListWebhooksExecute(r ApiListWebhooksRequest) (*WebhookListResponse, *http.Response, error) {
|
||||
var (
|
||||
localVarHTTPMethod = http.MethodGet
|
||||
localVarPostBody interface{}
|
||||
formFiles []formFile
|
||||
localVarReturnValue *WebhookListResponse
|
||||
)
|
||||
|
||||
localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WebhooksAPIService.ListWebhooks")
|
||||
if err != nil {
|
||||
return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()}
|
||||
}
|
||||
|
||||
localVarPath := localBasePath + "/v1/default/banks/{bank_id}/webhooks"
|
||||
localVarPath = strings.Replace(localVarPath, "{"+"bank_id"+"}", url.PathEscape(parameterValueToString(r.bankId, "bankId")), -1)
|
||||
|
||||
localVarHeaderParams := make(map[string]string)
|
||||
localVarQueryParams := url.Values{}
|
||||
localVarFormParams := url.Values{}
|
||||
|
||||
// to determine the Content-Type header
|
||||
localVarHTTPContentTypes := []string{}
|
||||
|
||||
// set Content-Type header
|
||||
localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes)
|
||||
if localVarHTTPContentType != "" {
|
||||
localVarHeaderParams["Content-Type"] = localVarHTTPContentType
|
||||
}
|
||||
|
||||
// to determine the Accept header
|
||||
localVarHTTPHeaderAccepts := []string{"application/json"}
|
||||
|
||||
// set Accept header
|
||||
localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts)
|
||||
if localVarHTTPHeaderAccept != "" {
|
||||
localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept
|
||||
}
|
||||
if r.authorization != nil {
|
||||
parameterAddToHeaderOrQuery(localVarHeaderParams, "authorization", r.authorization, "simple", "")
|
||||
}
|
||||
req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles)
|
||||
if err != nil {
|
||||
return localVarReturnValue, nil, err
|
||||
}
|
||||
|
||||
localVarHTTPResponse, err := a.client.callAPI(req)
|
||||
if err != nil || localVarHTTPResponse == nil {
|
||||
return localVarReturnValue, localVarHTTPResponse, err
|
||||
}
|
||||
|
||||
localVarBody, err := io.ReadAll(localVarHTTPResponse.Body)
|
||||
localVarHTTPResponse.Body.Close()
|
||||
localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody))
|
||||
if err != nil {
|
||||
return localVarReturnValue, localVarHTTPResponse, err
|
||||
}
|
||||
|
||||
if localVarHTTPResponse.StatusCode >= 300 {
|
||||
newErr := &GenericOpenAPIError{
|
||||
body: localVarBody,
|
||||
error: localVarHTTPResponse.Status,
|
||||
}
|
||||
if localVarHTTPResponse.StatusCode == 422 {
|
||||
var v HTTPValidationError
|
||||
err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
|
||||
if err != nil {
|
||||
newErr.error = err.Error()
|
||||
return localVarReturnValue, localVarHTTPResponse, newErr
|
||||
}
|
||||
newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v)
|
||||
newErr.model = v
|
||||
}
|
||||
return localVarReturnValue, localVarHTTPResponse, newErr
|
||||
}
|
||||
|
||||
err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
|
||||
if err != nil {
|
||||
newErr := &GenericOpenAPIError{
|
||||
body: localVarBody,
|
||||
error: err.Error(),
|
||||
}
|
||||
return localVarReturnValue, localVarHTTPResponse, newErr
|
||||
}
|
||||
|
||||
return localVarReturnValue, localVarHTTPResponse, nil
|
||||
}
|
||||
|
||||
type ApiUpdateWebhookRequest struct {
|
||||
ctx context.Context
|
||||
ApiService *WebhooksAPIService
|
||||
bankId string
|
||||
webhookId string
|
||||
updateWebhookRequest *UpdateWebhookRequest
|
||||
authorization *string
|
||||
}
|
||||
|
||||
func (r ApiUpdateWebhookRequest) UpdateWebhookRequest(updateWebhookRequest UpdateWebhookRequest) ApiUpdateWebhookRequest {
|
||||
r.updateWebhookRequest = &updateWebhookRequest
|
||||
return r
|
||||
}
|
||||
|
||||
func (r ApiUpdateWebhookRequest) Authorization(authorization string) ApiUpdateWebhookRequest {
|
||||
r.authorization = &authorization
|
||||
return r
|
||||
}
|
||||
|
||||
func (r ApiUpdateWebhookRequest) Execute() (*WebhookResponse, *http.Response, error) {
|
||||
return r.ApiService.UpdateWebhookExecute(r)
|
||||
}
|
||||
|
||||
/*
|
||||
UpdateWebhook Update webhook
|
||||
|
||||
Update one or more fields of a registered webhook. Only provided fields are changed.
|
||||
|
||||
@param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background().
|
||||
@param bankId
|
||||
@param webhookId
|
||||
@return ApiUpdateWebhookRequest
|
||||
*/
|
||||
func (a *WebhooksAPIService) UpdateWebhook(ctx context.Context, bankId string, webhookId string) ApiUpdateWebhookRequest {
|
||||
return ApiUpdateWebhookRequest{
|
||||
ApiService: a,
|
||||
ctx: ctx,
|
||||
bankId: bankId,
|
||||
webhookId: webhookId,
|
||||
}
|
||||
}
|
||||
|
||||
// Execute executes the request
|
||||
// @return WebhookResponse
|
||||
func (a *WebhooksAPIService) UpdateWebhookExecute(r ApiUpdateWebhookRequest) (*WebhookResponse, *http.Response, error) {
|
||||
var (
|
||||
localVarHTTPMethod = http.MethodPatch
|
||||
localVarPostBody interface{}
|
||||
formFiles []formFile
|
||||
localVarReturnValue *WebhookResponse
|
||||
)
|
||||
|
||||
localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WebhooksAPIService.UpdateWebhook")
|
||||
if err != nil {
|
||||
return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()}
|
||||
}
|
||||
|
||||
localVarPath := localBasePath + "/v1/default/banks/{bank_id}/webhooks/{webhook_id}"
|
||||
localVarPath = strings.Replace(localVarPath, "{"+"bank_id"+"}", url.PathEscape(parameterValueToString(r.bankId, "bankId")), -1)
|
||||
localVarPath = strings.Replace(localVarPath, "{"+"webhook_id"+"}", url.PathEscape(parameterValueToString(r.webhookId, "webhookId")), -1)
|
||||
|
||||
localVarHeaderParams := make(map[string]string)
|
||||
localVarQueryParams := url.Values{}
|
||||
localVarFormParams := url.Values{}
|
||||
if r.updateWebhookRequest == nil {
|
||||
return localVarReturnValue, nil, reportError("updateWebhookRequest is required and must be specified")
|
||||
}
|
||||
|
||||
// to determine the Content-Type header
|
||||
localVarHTTPContentTypes := []string{"application/json"}
|
||||
|
||||
// set Content-Type header
|
||||
localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes)
|
||||
if localVarHTTPContentType != "" {
|
||||
localVarHeaderParams["Content-Type"] = localVarHTTPContentType
|
||||
}
|
||||
|
||||
// to determine the Accept header
|
||||
localVarHTTPHeaderAccepts := []string{"application/json"}
|
||||
|
||||
// set Accept header
|
||||
localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts)
|
||||
if localVarHTTPHeaderAccept != "" {
|
||||
localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept
|
||||
}
|
||||
if r.authorization != nil {
|
||||
parameterAddToHeaderOrQuery(localVarHeaderParams, "authorization", r.authorization, "simple", "")
|
||||
}
|
||||
// body params
|
||||
localVarPostBody = r.updateWebhookRequest
|
||||
req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles)
|
||||
if err != nil {
|
||||
return localVarReturnValue, nil, err
|
||||
}
|
||||
|
||||
localVarHTTPResponse, err := a.client.callAPI(req)
|
||||
if err != nil || localVarHTTPResponse == nil {
|
||||
return localVarReturnValue, localVarHTTPResponse, err
|
||||
}
|
||||
|
||||
localVarBody, err := io.ReadAll(localVarHTTPResponse.Body)
|
||||
localVarHTTPResponse.Body.Close()
|
||||
localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody))
|
||||
if err != nil {
|
||||
return localVarReturnValue, localVarHTTPResponse, err
|
||||
}
|
||||
|
||||
if localVarHTTPResponse.StatusCode >= 300 {
|
||||
newErr := &GenericOpenAPIError{
|
||||
body: localVarBody,
|
||||
error: localVarHTTPResponse.Status,
|
||||
}
|
||||
if localVarHTTPResponse.StatusCode == 422 {
|
||||
var v HTTPValidationError
|
||||
err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
|
||||
if err != nil {
|
||||
newErr.error = err.Error()
|
||||
return localVarReturnValue, localVarHTTPResponse, newErr
|
||||
}
|
||||
newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v)
|
||||
newErr.model = v
|
||||
}
|
||||
return localVarReturnValue, localVarHTTPResponse, newErr
|
||||
}
|
||||
|
||||
err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type"))
|
||||
if err != nil {
|
||||
newErr := &GenericOpenAPIError{
|
||||
body: localVarBody,
|
||||
error: err.Error(),
|
||||
}
|
||||
return localVarReturnValue, localVarHTTPResponse, newErr
|
||||
}
|
||||
|
||||
return localVarReturnValue, localVarHTTPResponse, nil
|
||||
}
|
||||
|
|
@ -66,6 +66,8 @@ type APIClient struct {
|
|||
MonitoringAPI *MonitoringAPIService
|
||||
|
||||
OperationsAPI *OperationsAPIService
|
||||
|
||||
WebhooksAPI *WebhooksAPIService
|
||||
}
|
||||
|
||||
type service struct {
|
||||
|
|
@ -93,6 +95,7 @@ func NewAPIClient(cfg *Configuration) *APIClient {
|
|||
c.MentalModelsAPI = (*MentalModelsAPIService)(&c.common)
|
||||
c.MonitoringAPI = (*MonitoringAPIService)(&c.common)
|
||||
c.OperationsAPI = (*OperationsAPIService)(&c.common)
|
||||
c.WebhooksAPI = (*WebhooksAPIService)(&c.common)
|
||||
|
||||
return c
|
||||
}
|
||||
|
|
|
|||
320
hindsight-clients/go/model_create_webhook_request.go
Normal file
320
hindsight-clients/go/model_create_webhook_request.go
Normal file
|
|
@ -0,0 +1,320 @@
|
|||
/*
|
||||
Hindsight HTTP API
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
API version: 0.4.15
|
||||
*/
|
||||
|
||||
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
|
||||
|
||||
package hindsight
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// checks if the CreateWebhookRequest type satisfies the MappedNullable interface at compile time
|
||||
var _ MappedNullable = &CreateWebhookRequest{}
|
||||
|
||||
// CreateWebhookRequest Request model for registering a webhook.
|
||||
type CreateWebhookRequest struct {
|
||||
// HTTP(S) endpoint URL to deliver events to
|
||||
Url string `json:"url"`
|
||||
Secret NullableString `json:"secret,omitempty"`
|
||||
// List of event types to deliver. Currently supported: 'consolidation.completed'
|
||||
EventTypes []string `json:"event_types,omitempty"`
|
||||
// Whether this webhook is active
|
||||
Enabled *bool `json:"enabled,omitempty"`
|
||||
// HTTP delivery configuration (method, timeout, headers, params)
|
||||
HttpConfig *WebhookHttpConfig `json:"http_config,omitempty"`
|
||||
}
|
||||
|
||||
type _CreateWebhookRequest CreateWebhookRequest
|
||||
|
||||
// NewCreateWebhookRequest instantiates a new CreateWebhookRequest object
|
||||
// This constructor will assign default values to properties that have it defined,
|
||||
// and makes sure properties required by API are set, but the set of arguments
|
||||
// will change when the set of required properties is changed
|
||||
func NewCreateWebhookRequest(url string) *CreateWebhookRequest {
|
||||
this := CreateWebhookRequest{}
|
||||
this.Url = url
|
||||
var enabled bool = true
|
||||
this.Enabled = &enabled
|
||||
return &this
|
||||
}
|
||||
|
||||
// NewCreateWebhookRequestWithDefaults instantiates a new CreateWebhookRequest object
|
||||
// This constructor will only assign default values to properties that have it defined,
|
||||
// but it doesn't guarantee that properties required by API are set
|
||||
func NewCreateWebhookRequestWithDefaults() *CreateWebhookRequest {
|
||||
this := CreateWebhookRequest{}
|
||||
var enabled bool = true
|
||||
this.Enabled = &enabled
|
||||
return &this
|
||||
}
|
||||
|
||||
// GetUrl returns the Url field value
|
||||
func (o *CreateWebhookRequest) GetUrl() string {
|
||||
if o == nil {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.Url
|
||||
}
|
||||
|
||||
// GetUrlOk returns a tuple with the Url field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *CreateWebhookRequest) GetUrlOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &o.Url, true
|
||||
}
|
||||
|
||||
// SetUrl sets field value
|
||||
func (o *CreateWebhookRequest) SetUrl(v string) {
|
||||
o.Url = v
|
||||
}
|
||||
|
||||
// GetSecret returns the Secret field value if set, zero value otherwise (both if not set or set to explicit null).
|
||||
func (o *CreateWebhookRequest) GetSecret() string {
|
||||
if o == nil || IsNil(o.Secret.Get()) {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
return *o.Secret.Get()
|
||||
}
|
||||
|
||||
// GetSecretOk returns a tuple with the Secret field value if set, nil otherwise
|
||||
// and a boolean to check if the value has been set.
|
||||
// NOTE: If the value is an explicit nil, `nil, true` will be returned
|
||||
func (o *CreateWebhookRequest) GetSecretOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return o.Secret.Get(), o.Secret.IsSet()
|
||||
}
|
||||
|
||||
// HasSecret returns a boolean if a field has been set.
|
||||
func (o *CreateWebhookRequest) HasSecret() bool {
|
||||
if o != nil && o.Secret.IsSet() {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SetSecret gets a reference to the given NullableString and assigns it to the Secret field.
|
||||
func (o *CreateWebhookRequest) SetSecret(v string) {
|
||||
o.Secret.Set(&v)
|
||||
}
|
||||
// SetSecretNil sets the value for Secret to be an explicit nil
|
||||
func (o *CreateWebhookRequest) SetSecretNil() {
|
||||
o.Secret.Set(nil)
|
||||
}
|
||||
|
||||
// UnsetSecret ensures that no value is present for Secret, not even an explicit nil
|
||||
func (o *CreateWebhookRequest) UnsetSecret() {
|
||||
o.Secret.Unset()
|
||||
}
|
||||
|
||||
// GetEventTypes returns the EventTypes field value if set, zero value otherwise.
|
||||
func (o *CreateWebhookRequest) GetEventTypes() []string {
|
||||
if o == nil || IsNil(o.EventTypes) {
|
||||
var ret []string
|
||||
return ret
|
||||
}
|
||||
return o.EventTypes
|
||||
}
|
||||
|
||||
// GetEventTypesOk returns a tuple with the EventTypes field value if set, nil otherwise
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *CreateWebhookRequest) GetEventTypesOk() ([]string, bool) {
|
||||
if o == nil || IsNil(o.EventTypes) {
|
||||
return nil, false
|
||||
}
|
||||
return o.EventTypes, true
|
||||
}
|
||||
|
||||
// HasEventTypes returns a boolean if a field has been set.
|
||||
func (o *CreateWebhookRequest) HasEventTypes() bool {
|
||||
if o != nil && !IsNil(o.EventTypes) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SetEventTypes gets a reference to the given []string and assigns it to the EventTypes field.
|
||||
func (o *CreateWebhookRequest) SetEventTypes(v []string) {
|
||||
o.EventTypes = v
|
||||
}
|
||||
|
||||
// GetEnabled returns the Enabled field value if set, zero value otherwise.
|
||||
func (o *CreateWebhookRequest) GetEnabled() bool {
|
||||
if o == nil || IsNil(o.Enabled) {
|
||||
var ret bool
|
||||
return ret
|
||||
}
|
||||
return *o.Enabled
|
||||
}
|
||||
|
||||
// GetEnabledOk returns a tuple with the Enabled field value if set, nil otherwise
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *CreateWebhookRequest) GetEnabledOk() (*bool, bool) {
|
||||
if o == nil || IsNil(o.Enabled) {
|
||||
return nil, false
|
||||
}
|
||||
return o.Enabled, true
|
||||
}
|
||||
|
||||
// HasEnabled returns a boolean if a field has been set.
|
||||
func (o *CreateWebhookRequest) HasEnabled() bool {
|
||||
if o != nil && !IsNil(o.Enabled) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SetEnabled gets a reference to the given bool and assigns it to the Enabled field.
|
||||
func (o *CreateWebhookRequest) SetEnabled(v bool) {
|
||||
o.Enabled = &v
|
||||
}
|
||||
|
||||
// GetHttpConfig returns the HttpConfig field value if set, zero value otherwise.
|
||||
func (o *CreateWebhookRequest) GetHttpConfig() WebhookHttpConfig {
|
||||
if o == nil || IsNil(o.HttpConfig) {
|
||||
var ret WebhookHttpConfig
|
||||
return ret
|
||||
}
|
||||
return *o.HttpConfig
|
||||
}
|
||||
|
||||
// GetHttpConfigOk returns a tuple with the HttpConfig field value if set, nil otherwise
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *CreateWebhookRequest) GetHttpConfigOk() (*WebhookHttpConfig, bool) {
|
||||
if o == nil || IsNil(o.HttpConfig) {
|
||||
return nil, false
|
||||
}
|
||||
return o.HttpConfig, true
|
||||
}
|
||||
|
||||
// HasHttpConfig returns a boolean if a field has been set.
|
||||
func (o *CreateWebhookRequest) HasHttpConfig() bool {
|
||||
if o != nil && !IsNil(o.HttpConfig) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SetHttpConfig gets a reference to the given WebhookHttpConfig and assigns it to the HttpConfig field.
|
||||
func (o *CreateWebhookRequest) SetHttpConfig(v WebhookHttpConfig) {
|
||||
o.HttpConfig = &v
|
||||
}
|
||||
|
||||
func (o CreateWebhookRequest) MarshalJSON() ([]byte, error) {
|
||||
toSerialize,err := o.ToMap()
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
return json.Marshal(toSerialize)
|
||||
}
|
||||
|
||||
func (o CreateWebhookRequest) ToMap() (map[string]interface{}, error) {
|
||||
toSerialize := map[string]interface{}{}
|
||||
toSerialize["url"] = o.Url
|
||||
if o.Secret.IsSet() {
|
||||
toSerialize["secret"] = o.Secret.Get()
|
||||
}
|
||||
if !IsNil(o.EventTypes) {
|
||||
toSerialize["event_types"] = o.EventTypes
|
||||
}
|
||||
if !IsNil(o.Enabled) {
|
||||
toSerialize["enabled"] = o.Enabled
|
||||
}
|
||||
if !IsNil(o.HttpConfig) {
|
||||
toSerialize["http_config"] = o.HttpConfig
|
||||
}
|
||||
return toSerialize, nil
|
||||
}
|
||||
|
||||
func (o *CreateWebhookRequest) UnmarshalJSON(data []byte) (err error) {
|
||||
// This validates that all required properties are included in the JSON object
|
||||
// by unmarshalling the object into a generic map with string keys and checking
|
||||
// that every required field exists as a key in the generic map.
|
||||
requiredProperties := []string{
|
||||
"url",
|
||||
}
|
||||
|
||||
allProperties := make(map[string]interface{})
|
||||
|
||||
err = json.Unmarshal(data, &allProperties)
|
||||
|
||||
if err != nil {
|
||||
return err;
|
||||
}
|
||||
|
||||
for _, requiredProperty := range(requiredProperties) {
|
||||
if _, exists := allProperties[requiredProperty]; !exists {
|
||||
return fmt.Errorf("no value given for required property %v", requiredProperty)
|
||||
}
|
||||
}
|
||||
|
||||
varCreateWebhookRequest := _CreateWebhookRequest{}
|
||||
|
||||
decoder := json.NewDecoder(bytes.NewReader(data))
|
||||
decoder.DisallowUnknownFields()
|
||||
err = decoder.Decode(&varCreateWebhookRequest)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*o = CreateWebhookRequest(varCreateWebhookRequest)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
type NullableCreateWebhookRequest struct {
|
||||
value *CreateWebhookRequest
|
||||
isSet bool
|
||||
}
|
||||
|
||||
func (v NullableCreateWebhookRequest) Get() *CreateWebhookRequest {
|
||||
return v.value
|
||||
}
|
||||
|
||||
func (v *NullableCreateWebhookRequest) Set(val *CreateWebhookRequest) {
|
||||
v.value = val
|
||||
v.isSet = true
|
||||
}
|
||||
|
||||
func (v NullableCreateWebhookRequest) IsSet() bool {
|
||||
return v.isSet
|
||||
}
|
||||
|
||||
func (v *NullableCreateWebhookRequest) Unset() {
|
||||
v.value = nil
|
||||
v.isSet = false
|
||||
}
|
||||
|
||||
func NewNullableCreateWebhookRequest(val *CreateWebhookRequest) *NullableCreateWebhookRequest {
|
||||
return &NullableCreateWebhookRequest{value: val, isSet: true}
|
||||
}
|
||||
|
||||
func (v NullableCreateWebhookRequest) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(v.value)
|
||||
}
|
||||
|
||||
func (v *NullableCreateWebhookRequest) UnmarshalJSON(src []byte) error {
|
||||
v.isSet = true
|
||||
return json.Unmarshal(src, &v.value)
|
||||
}
|
||||
|
||||
|
||||
311
hindsight-clients/go/model_update_webhook_request.go
Normal file
311
hindsight-clients/go/model_update_webhook_request.go
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
/*
|
||||
Hindsight HTTP API
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
API version: 0.4.15
|
||||
*/
|
||||
|
||||
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
|
||||
|
||||
package hindsight
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// checks if the UpdateWebhookRequest type satisfies the MappedNullable interface at compile time
|
||||
var _ MappedNullable = &UpdateWebhookRequest{}
|
||||
|
||||
// UpdateWebhookRequest Request model for updating a webhook. Only provided fields are updated.
|
||||
type UpdateWebhookRequest struct {
|
||||
Url NullableString `json:"url,omitempty"`
|
||||
Secret NullableString `json:"secret,omitempty"`
|
||||
EventTypes []string `json:"event_types,omitempty"`
|
||||
Enabled NullableBool `json:"enabled,omitempty"`
|
||||
HttpConfig NullableWebhookHttpConfig `json:"http_config,omitempty"`
|
||||
}
|
||||
|
||||
// NewUpdateWebhookRequest instantiates a new UpdateWebhookRequest object
|
||||
// This constructor will assign default values to properties that have it defined,
|
||||
// and makes sure properties required by API are set, but the set of arguments
|
||||
// will change when the set of required properties is changed
|
||||
func NewUpdateWebhookRequest() *UpdateWebhookRequest {
|
||||
this := UpdateWebhookRequest{}
|
||||
return &this
|
||||
}
|
||||
|
||||
// NewUpdateWebhookRequestWithDefaults instantiates a new UpdateWebhookRequest object
|
||||
// This constructor will only assign default values to properties that have it defined,
|
||||
// but it doesn't guarantee that properties required by API are set
|
||||
func NewUpdateWebhookRequestWithDefaults() *UpdateWebhookRequest {
|
||||
this := UpdateWebhookRequest{}
|
||||
return &this
|
||||
}
|
||||
|
||||
// GetUrl returns the Url field value if set, zero value otherwise (both if not set or set to explicit null).
|
||||
func (o *UpdateWebhookRequest) GetUrl() string {
|
||||
if o == nil || IsNil(o.Url.Get()) {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
return *o.Url.Get()
|
||||
}
|
||||
|
||||
// GetUrlOk returns a tuple with the Url field value if set, nil otherwise
|
||||
// and a boolean to check if the value has been set.
|
||||
// NOTE: If the value is an explicit nil, `nil, true` will be returned
|
||||
func (o *UpdateWebhookRequest) GetUrlOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return o.Url.Get(), o.Url.IsSet()
|
||||
}
|
||||
|
||||
// HasUrl returns a boolean if a field has been set.
|
||||
func (o *UpdateWebhookRequest) HasUrl() bool {
|
||||
if o != nil && o.Url.IsSet() {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SetUrl gets a reference to the given NullableString and assigns it to the Url field.
|
||||
func (o *UpdateWebhookRequest) SetUrl(v string) {
|
||||
o.Url.Set(&v)
|
||||
}
|
||||
// SetUrlNil sets the value for Url to be an explicit nil
|
||||
func (o *UpdateWebhookRequest) SetUrlNil() {
|
||||
o.Url.Set(nil)
|
||||
}
|
||||
|
||||
// UnsetUrl ensures that no value is present for Url, not even an explicit nil
|
||||
func (o *UpdateWebhookRequest) UnsetUrl() {
|
||||
o.Url.Unset()
|
||||
}
|
||||
|
||||
// GetSecret returns the Secret field value if set, zero value otherwise (both if not set or set to explicit null).
|
||||
func (o *UpdateWebhookRequest) GetSecret() string {
|
||||
if o == nil || IsNil(o.Secret.Get()) {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
return *o.Secret.Get()
|
||||
}
|
||||
|
||||
// GetSecretOk returns a tuple with the Secret field value if set, nil otherwise
|
||||
// and a boolean to check if the value has been set.
|
||||
// NOTE: If the value is an explicit nil, `nil, true` will be returned
|
||||
func (o *UpdateWebhookRequest) GetSecretOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return o.Secret.Get(), o.Secret.IsSet()
|
||||
}
|
||||
|
||||
// HasSecret returns a boolean if a field has been set.
|
||||
func (o *UpdateWebhookRequest) HasSecret() bool {
|
||||
if o != nil && o.Secret.IsSet() {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SetSecret gets a reference to the given NullableString and assigns it to the Secret field.
|
||||
func (o *UpdateWebhookRequest) SetSecret(v string) {
|
||||
o.Secret.Set(&v)
|
||||
}
|
||||
// SetSecretNil sets the value for Secret to be an explicit nil
|
||||
func (o *UpdateWebhookRequest) SetSecretNil() {
|
||||
o.Secret.Set(nil)
|
||||
}
|
||||
|
||||
// UnsetSecret ensures that no value is present for Secret, not even an explicit nil
|
||||
func (o *UpdateWebhookRequest) UnsetSecret() {
|
||||
o.Secret.Unset()
|
||||
}
|
||||
|
||||
// GetEventTypes returns the EventTypes field value if set, zero value otherwise (both if not set or set to explicit null).
|
||||
func (o *UpdateWebhookRequest) GetEventTypes() []string {
|
||||
if o == nil {
|
||||
var ret []string
|
||||
return ret
|
||||
}
|
||||
return o.EventTypes
|
||||
}
|
||||
|
||||
// GetEventTypesOk returns a tuple with the EventTypes field value if set, nil otherwise
|
||||
// and a boolean to check if the value has been set.
|
||||
// NOTE: If the value is an explicit nil, `nil, true` will be returned
|
||||
func (o *UpdateWebhookRequest) GetEventTypesOk() ([]string, bool) {
|
||||
if o == nil || IsNil(o.EventTypes) {
|
||||
return nil, false
|
||||
}
|
||||
return o.EventTypes, true
|
||||
}
|
||||
|
||||
// HasEventTypes returns a boolean if a field has been set.
|
||||
func (o *UpdateWebhookRequest) HasEventTypes() bool {
|
||||
if o != nil && !IsNil(o.EventTypes) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SetEventTypes gets a reference to the given []string and assigns it to the EventTypes field.
|
||||
func (o *UpdateWebhookRequest) SetEventTypes(v []string) {
|
||||
o.EventTypes = v
|
||||
}
|
||||
|
||||
// GetEnabled returns the Enabled field value if set, zero value otherwise (both if not set or set to explicit null).
|
||||
func (o *UpdateWebhookRequest) GetEnabled() bool {
|
||||
if o == nil || IsNil(o.Enabled.Get()) {
|
||||
var ret bool
|
||||
return ret
|
||||
}
|
||||
return *o.Enabled.Get()
|
||||
}
|
||||
|
||||
// GetEnabledOk returns a tuple with the Enabled field value if set, nil otherwise
|
||||
// and a boolean to check if the value has been set.
|
||||
// NOTE: If the value is an explicit nil, `nil, true` will be returned
|
||||
func (o *UpdateWebhookRequest) GetEnabledOk() (*bool, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return o.Enabled.Get(), o.Enabled.IsSet()
|
||||
}
|
||||
|
||||
// HasEnabled returns a boolean if a field has been set.
|
||||
func (o *UpdateWebhookRequest) HasEnabled() bool {
|
||||
if o != nil && o.Enabled.IsSet() {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SetEnabled gets a reference to the given NullableBool and assigns it to the Enabled field.
|
||||
func (o *UpdateWebhookRequest) SetEnabled(v bool) {
|
||||
o.Enabled.Set(&v)
|
||||
}
|
||||
// SetEnabledNil sets the value for Enabled to be an explicit nil
|
||||
func (o *UpdateWebhookRequest) SetEnabledNil() {
|
||||
o.Enabled.Set(nil)
|
||||
}
|
||||
|
||||
// UnsetEnabled ensures that no value is present for Enabled, not even an explicit nil
|
||||
func (o *UpdateWebhookRequest) UnsetEnabled() {
|
||||
o.Enabled.Unset()
|
||||
}
|
||||
|
||||
// GetHttpConfig returns the HttpConfig field value if set, zero value otherwise (both if not set or set to explicit null).
|
||||
func (o *UpdateWebhookRequest) GetHttpConfig() WebhookHttpConfig {
|
||||
if o == nil || IsNil(o.HttpConfig.Get()) {
|
||||
var ret WebhookHttpConfig
|
||||
return ret
|
||||
}
|
||||
return *o.HttpConfig.Get()
|
||||
}
|
||||
|
||||
// GetHttpConfigOk returns a tuple with the HttpConfig field value if set, nil otherwise
|
||||
// and a boolean to check if the value has been set.
|
||||
// NOTE: If the value is an explicit nil, `nil, true` will be returned
|
||||
func (o *UpdateWebhookRequest) GetHttpConfigOk() (*WebhookHttpConfig, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return o.HttpConfig.Get(), o.HttpConfig.IsSet()
|
||||
}
|
||||
|
||||
// HasHttpConfig returns a boolean if a field has been set.
|
||||
func (o *UpdateWebhookRequest) HasHttpConfig() bool {
|
||||
if o != nil && o.HttpConfig.IsSet() {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SetHttpConfig gets a reference to the given NullableWebhookHttpConfig and assigns it to the HttpConfig field.
|
||||
func (o *UpdateWebhookRequest) SetHttpConfig(v WebhookHttpConfig) {
|
||||
o.HttpConfig.Set(&v)
|
||||
}
|
||||
// SetHttpConfigNil sets the value for HttpConfig to be an explicit nil
|
||||
func (o *UpdateWebhookRequest) SetHttpConfigNil() {
|
||||
o.HttpConfig.Set(nil)
|
||||
}
|
||||
|
||||
// UnsetHttpConfig ensures that no value is present for HttpConfig, not even an explicit nil
|
||||
func (o *UpdateWebhookRequest) UnsetHttpConfig() {
|
||||
o.HttpConfig.Unset()
|
||||
}
|
||||
|
||||
func (o UpdateWebhookRequest) MarshalJSON() ([]byte, error) {
|
||||
toSerialize,err := o.ToMap()
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
return json.Marshal(toSerialize)
|
||||
}
|
||||
|
||||
func (o UpdateWebhookRequest) ToMap() (map[string]interface{}, error) {
|
||||
toSerialize := map[string]interface{}{}
|
||||
if o.Url.IsSet() {
|
||||
toSerialize["url"] = o.Url.Get()
|
||||
}
|
||||
if o.Secret.IsSet() {
|
||||
toSerialize["secret"] = o.Secret.Get()
|
||||
}
|
||||
if o.EventTypes != nil {
|
||||
toSerialize["event_types"] = o.EventTypes
|
||||
}
|
||||
if o.Enabled.IsSet() {
|
||||
toSerialize["enabled"] = o.Enabled.Get()
|
||||
}
|
||||
if o.HttpConfig.IsSet() {
|
||||
toSerialize["http_config"] = o.HttpConfig.Get()
|
||||
}
|
||||
return toSerialize, nil
|
||||
}
|
||||
|
||||
type NullableUpdateWebhookRequest struct {
|
||||
value *UpdateWebhookRequest
|
||||
isSet bool
|
||||
}
|
||||
|
||||
func (v NullableUpdateWebhookRequest) Get() *UpdateWebhookRequest {
|
||||
return v.value
|
||||
}
|
||||
|
||||
func (v *NullableUpdateWebhookRequest) Set(val *UpdateWebhookRequest) {
|
||||
v.value = val
|
||||
v.isSet = true
|
||||
}
|
||||
|
||||
func (v NullableUpdateWebhookRequest) IsSet() bool {
|
||||
return v.isSet
|
||||
}
|
||||
|
||||
func (v *NullableUpdateWebhookRequest) Unset() {
|
||||
v.value = nil
|
||||
v.isSet = false
|
||||
}
|
||||
|
||||
func NewNullableUpdateWebhookRequest(val *UpdateWebhookRequest) *NullableUpdateWebhookRequest {
|
||||
return &NullableUpdateWebhookRequest{value: val, isSet: true}
|
||||
}
|
||||
|
||||
func (v NullableUpdateWebhookRequest) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(v.value)
|
||||
}
|
||||
|
||||
func (v *NullableUpdateWebhookRequest) UnmarshalJSON(src []byte) error {
|
||||
v.isSet = true
|
||||
return json.Unmarshal(src, &v.value)
|
||||
}
|
||||
|
||||
|
||||
204
hindsight-clients/go/model_webhook_delivery_list_response.go
Normal file
204
hindsight-clients/go/model_webhook_delivery_list_response.go
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
Hindsight HTTP API
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
API version: 0.4.15
|
||||
*/
|
||||
|
||||
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
|
||||
|
||||
package hindsight
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// checks if the WebhookDeliveryListResponse type satisfies the MappedNullable interface at compile time
|
||||
var _ MappedNullable = &WebhookDeliveryListResponse{}
|
||||
|
||||
// WebhookDeliveryListResponse Response model for listing webhook deliveries.
|
||||
type WebhookDeliveryListResponse struct {
|
||||
Items []WebhookDeliveryResponse `json:"items"`
|
||||
NextCursor NullableString `json:"next_cursor,omitempty"`
|
||||
}
|
||||
|
||||
type _WebhookDeliveryListResponse WebhookDeliveryListResponse
|
||||
|
||||
// NewWebhookDeliveryListResponse instantiates a new WebhookDeliveryListResponse object
|
||||
// This constructor will assign default values to properties that have it defined,
|
||||
// and makes sure properties required by API are set, but the set of arguments
|
||||
// will change when the set of required properties is changed
|
||||
func NewWebhookDeliveryListResponse(items []WebhookDeliveryResponse) *WebhookDeliveryListResponse {
|
||||
this := WebhookDeliveryListResponse{}
|
||||
this.Items = items
|
||||
return &this
|
||||
}
|
||||
|
||||
// NewWebhookDeliveryListResponseWithDefaults instantiates a new WebhookDeliveryListResponse object
|
||||
// This constructor will only assign default values to properties that have it defined,
|
||||
// but it doesn't guarantee that properties required by API are set
|
||||
func NewWebhookDeliveryListResponseWithDefaults() *WebhookDeliveryListResponse {
|
||||
this := WebhookDeliveryListResponse{}
|
||||
return &this
|
||||
}
|
||||
|
||||
// GetItems returns the Items field value
|
||||
func (o *WebhookDeliveryListResponse) GetItems() []WebhookDeliveryResponse {
|
||||
if o == nil {
|
||||
var ret []WebhookDeliveryResponse
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.Items
|
||||
}
|
||||
|
||||
// GetItemsOk returns a tuple with the Items field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *WebhookDeliveryListResponse) GetItemsOk() ([]WebhookDeliveryResponse, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return o.Items, true
|
||||
}
|
||||
|
||||
// SetItems sets field value
|
||||
func (o *WebhookDeliveryListResponse) SetItems(v []WebhookDeliveryResponse) {
|
||||
o.Items = v
|
||||
}
|
||||
|
||||
// GetNextCursor returns the NextCursor field value if set, zero value otherwise (both if not set or set to explicit null).
|
||||
func (o *WebhookDeliveryListResponse) GetNextCursor() string {
|
||||
if o == nil || IsNil(o.NextCursor.Get()) {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
return *o.NextCursor.Get()
|
||||
}
|
||||
|
||||
// GetNextCursorOk returns a tuple with the NextCursor field value if set, nil otherwise
|
||||
// and a boolean to check if the value has been set.
|
||||
// NOTE: If the value is an explicit nil, `nil, true` will be returned
|
||||
func (o *WebhookDeliveryListResponse) GetNextCursorOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return o.NextCursor.Get(), o.NextCursor.IsSet()
|
||||
}
|
||||
|
||||
// HasNextCursor returns a boolean if a field has been set.
|
||||
func (o *WebhookDeliveryListResponse) HasNextCursor() bool {
|
||||
if o != nil && o.NextCursor.IsSet() {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SetNextCursor gets a reference to the given NullableString and assigns it to the NextCursor field.
|
||||
func (o *WebhookDeliveryListResponse) SetNextCursor(v string) {
|
||||
o.NextCursor.Set(&v)
|
||||
}
|
||||
// SetNextCursorNil sets the value for NextCursor to be an explicit nil
|
||||
func (o *WebhookDeliveryListResponse) SetNextCursorNil() {
|
||||
o.NextCursor.Set(nil)
|
||||
}
|
||||
|
||||
// UnsetNextCursor ensures that no value is present for NextCursor, not even an explicit nil
|
||||
func (o *WebhookDeliveryListResponse) UnsetNextCursor() {
|
||||
o.NextCursor.Unset()
|
||||
}
|
||||
|
||||
func (o WebhookDeliveryListResponse) MarshalJSON() ([]byte, error) {
|
||||
toSerialize,err := o.ToMap()
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
return json.Marshal(toSerialize)
|
||||
}
|
||||
|
||||
func (o WebhookDeliveryListResponse) ToMap() (map[string]interface{}, error) {
|
||||
toSerialize := map[string]interface{}{}
|
||||
toSerialize["items"] = o.Items
|
||||
if o.NextCursor.IsSet() {
|
||||
toSerialize["next_cursor"] = o.NextCursor.Get()
|
||||
}
|
||||
return toSerialize, nil
|
||||
}
|
||||
|
||||
func (o *WebhookDeliveryListResponse) UnmarshalJSON(data []byte) (err error) {
|
||||
// This validates that all required properties are included in the JSON object
|
||||
// by unmarshalling the object into a generic map with string keys and checking
|
||||
// that every required field exists as a key in the generic map.
|
||||
requiredProperties := []string{
|
||||
"items",
|
||||
}
|
||||
|
||||
allProperties := make(map[string]interface{})
|
||||
|
||||
err = json.Unmarshal(data, &allProperties)
|
||||
|
||||
if err != nil {
|
||||
return err;
|
||||
}
|
||||
|
||||
for _, requiredProperty := range(requiredProperties) {
|
||||
if _, exists := allProperties[requiredProperty]; !exists {
|
||||
return fmt.Errorf("no value given for required property %v", requiredProperty)
|
||||
}
|
||||
}
|
||||
|
||||
varWebhookDeliveryListResponse := _WebhookDeliveryListResponse{}
|
||||
|
||||
decoder := json.NewDecoder(bytes.NewReader(data))
|
||||
decoder.DisallowUnknownFields()
|
||||
err = decoder.Decode(&varWebhookDeliveryListResponse)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*o = WebhookDeliveryListResponse(varWebhookDeliveryListResponse)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
type NullableWebhookDeliveryListResponse struct {
|
||||
value *WebhookDeliveryListResponse
|
||||
isSet bool
|
||||
}
|
||||
|
||||
func (v NullableWebhookDeliveryListResponse) Get() *WebhookDeliveryListResponse {
|
||||
return v.value
|
||||
}
|
||||
|
||||
func (v *NullableWebhookDeliveryListResponse) Set(val *WebhookDeliveryListResponse) {
|
||||
v.value = val
|
||||
v.isSet = true
|
||||
}
|
||||
|
||||
func (v NullableWebhookDeliveryListResponse) IsSet() bool {
|
||||
return v.isSet
|
||||
}
|
||||
|
||||
func (v *NullableWebhookDeliveryListResponse) Unset() {
|
||||
v.value = nil
|
||||
v.isSet = false
|
||||
}
|
||||
|
||||
func NewNullableWebhookDeliveryListResponse(val *WebhookDeliveryListResponse) *NullableWebhookDeliveryListResponse {
|
||||
return &NullableWebhookDeliveryListResponse{value: val, isSet: true}
|
||||
}
|
||||
|
||||
func (v NullableWebhookDeliveryListResponse) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(v.value)
|
||||
}
|
||||
|
||||
func (v *NullableWebhookDeliveryListResponse) UnmarshalJSON(src []byte) error {
|
||||
v.isSet = true
|
||||
return json.Unmarshal(src, &v.value)
|
||||
}
|
||||
|
||||
|
||||
622
hindsight-clients/go/model_webhook_delivery_response.go
Normal file
622
hindsight-clients/go/model_webhook_delivery_response.go
Normal file
|
|
@ -0,0 +1,622 @@
|
|||
/*
|
||||
Hindsight HTTP API
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
API version: 0.4.15
|
||||
*/
|
||||
|
||||
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
|
||||
|
||||
package hindsight
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// checks if the WebhookDeliveryResponse type satisfies the MappedNullable interface at compile time
|
||||
var _ MappedNullable = &WebhookDeliveryResponse{}
|
||||
|
||||
// WebhookDeliveryResponse Response model for a webhook delivery record.
|
||||
type WebhookDeliveryResponse struct {
|
||||
Id string `json:"id"`
|
||||
WebhookId NullableString `json:"webhook_id"`
|
||||
Url string `json:"url"`
|
||||
EventType string `json:"event_type"`
|
||||
Status string `json:"status"`
|
||||
Attempts int32 `json:"attempts"`
|
||||
NextRetryAt NullableString `json:"next_retry_at,omitempty"`
|
||||
LastError NullableString `json:"last_error,omitempty"`
|
||||
LastResponseStatus NullableInt32 `json:"last_response_status,omitempty"`
|
||||
LastResponseBody NullableString `json:"last_response_body,omitempty"`
|
||||
LastAttemptAt NullableString `json:"last_attempt_at,omitempty"`
|
||||
CreatedAt NullableString `json:"created_at,omitempty"`
|
||||
UpdatedAt NullableString `json:"updated_at,omitempty"`
|
||||
}
|
||||
|
||||
type _WebhookDeliveryResponse WebhookDeliveryResponse
|
||||
|
||||
// NewWebhookDeliveryResponse instantiates a new WebhookDeliveryResponse object
|
||||
// This constructor will assign default values to properties that have it defined,
|
||||
// and makes sure properties required by API are set, but the set of arguments
|
||||
// will change when the set of required properties is changed
|
||||
func NewWebhookDeliveryResponse(id string, webhookId NullableString, url string, eventType string, status string, attempts int32) *WebhookDeliveryResponse {
|
||||
this := WebhookDeliveryResponse{}
|
||||
this.Id = id
|
||||
this.WebhookId = webhookId
|
||||
this.Url = url
|
||||
this.EventType = eventType
|
||||
this.Status = status
|
||||
this.Attempts = attempts
|
||||
return &this
|
||||
}
|
||||
|
||||
// NewWebhookDeliveryResponseWithDefaults instantiates a new WebhookDeliveryResponse object
|
||||
// This constructor will only assign default values to properties that have it defined,
|
||||
// but it doesn't guarantee that properties required by API are set
|
||||
func NewWebhookDeliveryResponseWithDefaults() *WebhookDeliveryResponse {
|
||||
this := WebhookDeliveryResponse{}
|
||||
return &this
|
||||
}
|
||||
|
||||
// GetId returns the Id field value
|
||||
func (o *WebhookDeliveryResponse) GetId() string {
|
||||
if o == nil {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.Id
|
||||
}
|
||||
|
||||
// GetIdOk returns a tuple with the Id field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *WebhookDeliveryResponse) GetIdOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &o.Id, true
|
||||
}
|
||||
|
||||
// SetId sets field value
|
||||
func (o *WebhookDeliveryResponse) SetId(v string) {
|
||||
o.Id = v
|
||||
}
|
||||
|
||||
// GetWebhookId returns the WebhookId field value
|
||||
// If the value is explicit nil, the zero value for string will be returned
|
||||
func (o *WebhookDeliveryResponse) GetWebhookId() string {
|
||||
if o == nil || o.WebhookId.Get() == nil {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
|
||||
return *o.WebhookId.Get()
|
||||
}
|
||||
|
||||
// GetWebhookIdOk returns a tuple with the WebhookId field value
|
||||
// and a boolean to check if the value has been set.
|
||||
// NOTE: If the value is an explicit nil, `nil, true` will be returned
|
||||
func (o *WebhookDeliveryResponse) GetWebhookIdOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return o.WebhookId.Get(), o.WebhookId.IsSet()
|
||||
}
|
||||
|
||||
// SetWebhookId sets field value
|
||||
func (o *WebhookDeliveryResponse) SetWebhookId(v string) {
|
||||
o.WebhookId.Set(&v)
|
||||
}
|
||||
|
||||
// GetUrl returns the Url field value
|
||||
func (o *WebhookDeliveryResponse) GetUrl() string {
|
||||
if o == nil {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.Url
|
||||
}
|
||||
|
||||
// GetUrlOk returns a tuple with the Url field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *WebhookDeliveryResponse) GetUrlOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &o.Url, true
|
||||
}
|
||||
|
||||
// SetUrl sets field value
|
||||
func (o *WebhookDeliveryResponse) SetUrl(v string) {
|
||||
o.Url = v
|
||||
}
|
||||
|
||||
// GetEventType returns the EventType field value
|
||||
func (o *WebhookDeliveryResponse) GetEventType() string {
|
||||
if o == nil {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.EventType
|
||||
}
|
||||
|
||||
// GetEventTypeOk returns a tuple with the EventType field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *WebhookDeliveryResponse) GetEventTypeOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &o.EventType, true
|
||||
}
|
||||
|
||||
// SetEventType sets field value
|
||||
func (o *WebhookDeliveryResponse) SetEventType(v string) {
|
||||
o.EventType = v
|
||||
}
|
||||
|
||||
// GetStatus returns the Status field value
|
||||
func (o *WebhookDeliveryResponse) GetStatus() string {
|
||||
if o == nil {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.Status
|
||||
}
|
||||
|
||||
// GetStatusOk returns a tuple with the Status field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *WebhookDeliveryResponse) GetStatusOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &o.Status, true
|
||||
}
|
||||
|
||||
// SetStatus sets field value
|
||||
func (o *WebhookDeliveryResponse) SetStatus(v string) {
|
||||
o.Status = v
|
||||
}
|
||||
|
||||
// GetAttempts returns the Attempts field value
|
||||
func (o *WebhookDeliveryResponse) GetAttempts() int32 {
|
||||
if o == nil {
|
||||
var ret int32
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.Attempts
|
||||
}
|
||||
|
||||
// GetAttemptsOk returns a tuple with the Attempts field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *WebhookDeliveryResponse) GetAttemptsOk() (*int32, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &o.Attempts, true
|
||||
}
|
||||
|
||||
// SetAttempts sets field value
|
||||
func (o *WebhookDeliveryResponse) SetAttempts(v int32) {
|
||||
o.Attempts = v
|
||||
}
|
||||
|
||||
// GetNextRetryAt returns the NextRetryAt field value if set, zero value otherwise (both if not set or set to explicit null).
|
||||
func (o *WebhookDeliveryResponse) GetNextRetryAt() string {
|
||||
if o == nil || IsNil(o.NextRetryAt.Get()) {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
return *o.NextRetryAt.Get()
|
||||
}
|
||||
|
||||
// GetNextRetryAtOk returns a tuple with the NextRetryAt field value if set, nil otherwise
|
||||
// and a boolean to check if the value has been set.
|
||||
// NOTE: If the value is an explicit nil, `nil, true` will be returned
|
||||
func (o *WebhookDeliveryResponse) GetNextRetryAtOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return o.NextRetryAt.Get(), o.NextRetryAt.IsSet()
|
||||
}
|
||||
|
||||
// HasNextRetryAt returns a boolean if a field has been set.
|
||||
func (o *WebhookDeliveryResponse) HasNextRetryAt() bool {
|
||||
if o != nil && o.NextRetryAt.IsSet() {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SetNextRetryAt gets a reference to the given NullableString and assigns it to the NextRetryAt field.
|
||||
func (o *WebhookDeliveryResponse) SetNextRetryAt(v string) {
|
||||
o.NextRetryAt.Set(&v)
|
||||
}
|
||||
// SetNextRetryAtNil sets the value for NextRetryAt to be an explicit nil
|
||||
func (o *WebhookDeliveryResponse) SetNextRetryAtNil() {
|
||||
o.NextRetryAt.Set(nil)
|
||||
}
|
||||
|
||||
// UnsetNextRetryAt ensures that no value is present for NextRetryAt, not even an explicit nil
|
||||
func (o *WebhookDeliveryResponse) UnsetNextRetryAt() {
|
||||
o.NextRetryAt.Unset()
|
||||
}
|
||||
|
||||
// GetLastError returns the LastError field value if set, zero value otherwise (both if not set or set to explicit null).
|
||||
func (o *WebhookDeliveryResponse) GetLastError() string {
|
||||
if o == nil || IsNil(o.LastError.Get()) {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
return *o.LastError.Get()
|
||||
}
|
||||
|
||||
// GetLastErrorOk returns a tuple with the LastError field value if set, nil otherwise
|
||||
// and a boolean to check if the value has been set.
|
||||
// NOTE: If the value is an explicit nil, `nil, true` will be returned
|
||||
func (o *WebhookDeliveryResponse) GetLastErrorOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return o.LastError.Get(), o.LastError.IsSet()
|
||||
}
|
||||
|
||||
// HasLastError returns a boolean if a field has been set.
|
||||
func (o *WebhookDeliveryResponse) HasLastError() bool {
|
||||
if o != nil && o.LastError.IsSet() {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SetLastError gets a reference to the given NullableString and assigns it to the LastError field.
|
||||
func (o *WebhookDeliveryResponse) SetLastError(v string) {
|
||||
o.LastError.Set(&v)
|
||||
}
|
||||
// SetLastErrorNil sets the value for LastError to be an explicit nil
|
||||
func (o *WebhookDeliveryResponse) SetLastErrorNil() {
|
||||
o.LastError.Set(nil)
|
||||
}
|
||||
|
||||
// UnsetLastError ensures that no value is present for LastError, not even an explicit nil
|
||||
func (o *WebhookDeliveryResponse) UnsetLastError() {
|
||||
o.LastError.Unset()
|
||||
}
|
||||
|
||||
// GetLastResponseStatus returns the LastResponseStatus field value if set, zero value otherwise (both if not set or set to explicit null).
|
||||
func (o *WebhookDeliveryResponse) GetLastResponseStatus() int32 {
|
||||
if o == nil || IsNil(o.LastResponseStatus.Get()) {
|
||||
var ret int32
|
||||
return ret
|
||||
}
|
||||
return *o.LastResponseStatus.Get()
|
||||
}
|
||||
|
||||
// GetLastResponseStatusOk returns a tuple with the LastResponseStatus field value if set, nil otherwise
|
||||
// and a boolean to check if the value has been set.
|
||||
// NOTE: If the value is an explicit nil, `nil, true` will be returned
|
||||
func (o *WebhookDeliveryResponse) GetLastResponseStatusOk() (*int32, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return o.LastResponseStatus.Get(), o.LastResponseStatus.IsSet()
|
||||
}
|
||||
|
||||
// HasLastResponseStatus returns a boolean if a field has been set.
|
||||
func (o *WebhookDeliveryResponse) HasLastResponseStatus() bool {
|
||||
if o != nil && o.LastResponseStatus.IsSet() {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SetLastResponseStatus gets a reference to the given NullableInt32 and assigns it to the LastResponseStatus field.
|
||||
func (o *WebhookDeliveryResponse) SetLastResponseStatus(v int32) {
|
||||
o.LastResponseStatus.Set(&v)
|
||||
}
|
||||
// SetLastResponseStatusNil sets the value for LastResponseStatus to be an explicit nil
|
||||
func (o *WebhookDeliveryResponse) SetLastResponseStatusNil() {
|
||||
o.LastResponseStatus.Set(nil)
|
||||
}
|
||||
|
||||
// UnsetLastResponseStatus ensures that no value is present for LastResponseStatus, not even an explicit nil
|
||||
func (o *WebhookDeliveryResponse) UnsetLastResponseStatus() {
|
||||
o.LastResponseStatus.Unset()
|
||||
}
|
||||
|
||||
// GetLastResponseBody returns the LastResponseBody field value if set, zero value otherwise (both if not set or set to explicit null).
|
||||
func (o *WebhookDeliveryResponse) GetLastResponseBody() string {
|
||||
if o == nil || IsNil(o.LastResponseBody.Get()) {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
return *o.LastResponseBody.Get()
|
||||
}
|
||||
|
||||
// GetLastResponseBodyOk returns a tuple with the LastResponseBody field value if set, nil otherwise
|
||||
// and a boolean to check if the value has been set.
|
||||
// NOTE: If the value is an explicit nil, `nil, true` will be returned
|
||||
func (o *WebhookDeliveryResponse) GetLastResponseBodyOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return o.LastResponseBody.Get(), o.LastResponseBody.IsSet()
|
||||
}
|
||||
|
||||
// HasLastResponseBody returns a boolean if a field has been set.
|
||||
func (o *WebhookDeliveryResponse) HasLastResponseBody() bool {
|
||||
if o != nil && o.LastResponseBody.IsSet() {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SetLastResponseBody gets a reference to the given NullableString and assigns it to the LastResponseBody field.
|
||||
func (o *WebhookDeliveryResponse) SetLastResponseBody(v string) {
|
||||
o.LastResponseBody.Set(&v)
|
||||
}
|
||||
// SetLastResponseBodyNil sets the value for LastResponseBody to be an explicit nil
|
||||
func (o *WebhookDeliveryResponse) SetLastResponseBodyNil() {
|
||||
o.LastResponseBody.Set(nil)
|
||||
}
|
||||
|
||||
// UnsetLastResponseBody ensures that no value is present for LastResponseBody, not even an explicit nil
|
||||
func (o *WebhookDeliveryResponse) UnsetLastResponseBody() {
|
||||
o.LastResponseBody.Unset()
|
||||
}
|
||||
|
||||
// GetLastAttemptAt returns the LastAttemptAt field value if set, zero value otherwise (both if not set or set to explicit null).
|
||||
func (o *WebhookDeliveryResponse) GetLastAttemptAt() string {
|
||||
if o == nil || IsNil(o.LastAttemptAt.Get()) {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
return *o.LastAttemptAt.Get()
|
||||
}
|
||||
|
||||
// GetLastAttemptAtOk returns a tuple with the LastAttemptAt field value if set, nil otherwise
|
||||
// and a boolean to check if the value has been set.
|
||||
// NOTE: If the value is an explicit nil, `nil, true` will be returned
|
||||
func (o *WebhookDeliveryResponse) GetLastAttemptAtOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return o.LastAttemptAt.Get(), o.LastAttemptAt.IsSet()
|
||||
}
|
||||
|
||||
// HasLastAttemptAt returns a boolean if a field has been set.
|
||||
func (o *WebhookDeliveryResponse) HasLastAttemptAt() bool {
|
||||
if o != nil && o.LastAttemptAt.IsSet() {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SetLastAttemptAt gets a reference to the given NullableString and assigns it to the LastAttemptAt field.
|
||||
func (o *WebhookDeliveryResponse) SetLastAttemptAt(v string) {
|
||||
o.LastAttemptAt.Set(&v)
|
||||
}
|
||||
// SetLastAttemptAtNil sets the value for LastAttemptAt to be an explicit nil
|
||||
func (o *WebhookDeliveryResponse) SetLastAttemptAtNil() {
|
||||
o.LastAttemptAt.Set(nil)
|
||||
}
|
||||
|
||||
// UnsetLastAttemptAt ensures that no value is present for LastAttemptAt, not even an explicit nil
|
||||
func (o *WebhookDeliveryResponse) UnsetLastAttemptAt() {
|
||||
o.LastAttemptAt.Unset()
|
||||
}
|
||||
|
||||
// GetCreatedAt returns the CreatedAt field value if set, zero value otherwise (both if not set or set to explicit null).
|
||||
func (o *WebhookDeliveryResponse) GetCreatedAt() string {
|
||||
if o == nil || IsNil(o.CreatedAt.Get()) {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
return *o.CreatedAt.Get()
|
||||
}
|
||||
|
||||
// GetCreatedAtOk returns a tuple with the CreatedAt field value if set, nil otherwise
|
||||
// and a boolean to check if the value has been set.
|
||||
// NOTE: If the value is an explicit nil, `nil, true` will be returned
|
||||
func (o *WebhookDeliveryResponse) GetCreatedAtOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return o.CreatedAt.Get(), o.CreatedAt.IsSet()
|
||||
}
|
||||
|
||||
// HasCreatedAt returns a boolean if a field has been set.
|
||||
func (o *WebhookDeliveryResponse) HasCreatedAt() bool {
|
||||
if o != nil && o.CreatedAt.IsSet() {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SetCreatedAt gets a reference to the given NullableString and assigns it to the CreatedAt field.
|
||||
func (o *WebhookDeliveryResponse) SetCreatedAt(v string) {
|
||||
o.CreatedAt.Set(&v)
|
||||
}
|
||||
// SetCreatedAtNil sets the value for CreatedAt to be an explicit nil
|
||||
func (o *WebhookDeliveryResponse) SetCreatedAtNil() {
|
||||
o.CreatedAt.Set(nil)
|
||||
}
|
||||
|
||||
// UnsetCreatedAt ensures that no value is present for CreatedAt, not even an explicit nil
|
||||
func (o *WebhookDeliveryResponse) UnsetCreatedAt() {
|
||||
o.CreatedAt.Unset()
|
||||
}
|
||||
|
||||
// GetUpdatedAt returns the UpdatedAt field value if set, zero value otherwise (both if not set or set to explicit null).
|
||||
func (o *WebhookDeliveryResponse) GetUpdatedAt() string {
|
||||
if o == nil || IsNil(o.UpdatedAt.Get()) {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
return *o.UpdatedAt.Get()
|
||||
}
|
||||
|
||||
// GetUpdatedAtOk returns a tuple with the UpdatedAt field value if set, nil otherwise
|
||||
// and a boolean to check if the value has been set.
|
||||
// NOTE: If the value is an explicit nil, `nil, true` will be returned
|
||||
func (o *WebhookDeliveryResponse) GetUpdatedAtOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return o.UpdatedAt.Get(), o.UpdatedAt.IsSet()
|
||||
}
|
||||
|
||||
// HasUpdatedAt returns a boolean if a field has been set.
|
||||
func (o *WebhookDeliveryResponse) HasUpdatedAt() bool {
|
||||
if o != nil && o.UpdatedAt.IsSet() {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SetUpdatedAt gets a reference to the given NullableString and assigns it to the UpdatedAt field.
|
||||
func (o *WebhookDeliveryResponse) SetUpdatedAt(v string) {
|
||||
o.UpdatedAt.Set(&v)
|
||||
}
|
||||
// SetUpdatedAtNil sets the value for UpdatedAt to be an explicit nil
|
||||
func (o *WebhookDeliveryResponse) SetUpdatedAtNil() {
|
||||
o.UpdatedAt.Set(nil)
|
||||
}
|
||||
|
||||
// UnsetUpdatedAt ensures that no value is present for UpdatedAt, not even an explicit nil
|
||||
func (o *WebhookDeliveryResponse) UnsetUpdatedAt() {
|
||||
o.UpdatedAt.Unset()
|
||||
}
|
||||
|
||||
func (o WebhookDeliveryResponse) MarshalJSON() ([]byte, error) {
|
||||
toSerialize,err := o.ToMap()
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
return json.Marshal(toSerialize)
|
||||
}
|
||||
|
||||
func (o WebhookDeliveryResponse) ToMap() (map[string]interface{}, error) {
|
||||
toSerialize := map[string]interface{}{}
|
||||
toSerialize["id"] = o.Id
|
||||
toSerialize["webhook_id"] = o.WebhookId.Get()
|
||||
toSerialize["url"] = o.Url
|
||||
toSerialize["event_type"] = o.EventType
|
||||
toSerialize["status"] = o.Status
|
||||
toSerialize["attempts"] = o.Attempts
|
||||
if o.NextRetryAt.IsSet() {
|
||||
toSerialize["next_retry_at"] = o.NextRetryAt.Get()
|
||||
}
|
||||
if o.LastError.IsSet() {
|
||||
toSerialize["last_error"] = o.LastError.Get()
|
||||
}
|
||||
if o.LastResponseStatus.IsSet() {
|
||||
toSerialize["last_response_status"] = o.LastResponseStatus.Get()
|
||||
}
|
||||
if o.LastResponseBody.IsSet() {
|
||||
toSerialize["last_response_body"] = o.LastResponseBody.Get()
|
||||
}
|
||||
if o.LastAttemptAt.IsSet() {
|
||||
toSerialize["last_attempt_at"] = o.LastAttemptAt.Get()
|
||||
}
|
||||
if o.CreatedAt.IsSet() {
|
||||
toSerialize["created_at"] = o.CreatedAt.Get()
|
||||
}
|
||||
if o.UpdatedAt.IsSet() {
|
||||
toSerialize["updated_at"] = o.UpdatedAt.Get()
|
||||
}
|
||||
return toSerialize, nil
|
||||
}
|
||||
|
||||
func (o *WebhookDeliveryResponse) UnmarshalJSON(data []byte) (err error) {
|
||||
// This validates that all required properties are included in the JSON object
|
||||
// by unmarshalling the object into a generic map with string keys and checking
|
||||
// that every required field exists as a key in the generic map.
|
||||
requiredProperties := []string{
|
||||
"id",
|
||||
"webhook_id",
|
||||
"url",
|
||||
"event_type",
|
||||
"status",
|
||||
"attempts",
|
||||
}
|
||||
|
||||
allProperties := make(map[string]interface{})
|
||||
|
||||
err = json.Unmarshal(data, &allProperties)
|
||||
|
||||
if err != nil {
|
||||
return err;
|
||||
}
|
||||
|
||||
for _, requiredProperty := range(requiredProperties) {
|
||||
if _, exists := allProperties[requiredProperty]; !exists {
|
||||
return fmt.Errorf("no value given for required property %v", requiredProperty)
|
||||
}
|
||||
}
|
||||
|
||||
varWebhookDeliveryResponse := _WebhookDeliveryResponse{}
|
||||
|
||||
decoder := json.NewDecoder(bytes.NewReader(data))
|
||||
decoder.DisallowUnknownFields()
|
||||
err = decoder.Decode(&varWebhookDeliveryResponse)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*o = WebhookDeliveryResponse(varWebhookDeliveryResponse)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
type NullableWebhookDeliveryResponse struct {
|
||||
value *WebhookDeliveryResponse
|
||||
isSet bool
|
||||
}
|
||||
|
||||
func (v NullableWebhookDeliveryResponse) Get() *WebhookDeliveryResponse {
|
||||
return v.value
|
||||
}
|
||||
|
||||
func (v *NullableWebhookDeliveryResponse) Set(val *WebhookDeliveryResponse) {
|
||||
v.value = val
|
||||
v.isSet = true
|
||||
}
|
||||
|
||||
func (v NullableWebhookDeliveryResponse) IsSet() bool {
|
||||
return v.isSet
|
||||
}
|
||||
|
||||
func (v *NullableWebhookDeliveryResponse) Unset() {
|
||||
v.value = nil
|
||||
v.isSet = false
|
||||
}
|
||||
|
||||
func NewNullableWebhookDeliveryResponse(val *WebhookDeliveryResponse) *NullableWebhookDeliveryResponse {
|
||||
return &NullableWebhookDeliveryResponse{value: val, isSet: true}
|
||||
}
|
||||
|
||||
func (v NullableWebhookDeliveryResponse) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(v.value)
|
||||
}
|
||||
|
||||
func (v *NullableWebhookDeliveryResponse) UnmarshalJSON(src []byte) error {
|
||||
v.isSet = true
|
||||
return json.Unmarshal(src, &v.value)
|
||||
}
|
||||
|
||||
|
||||
246
hindsight-clients/go/model_webhook_http_config.go
Normal file
246
hindsight-clients/go/model_webhook_http_config.go
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
Hindsight HTTP API
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
API version: 0.4.15
|
||||
*/
|
||||
|
||||
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
|
||||
|
||||
package hindsight
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// checks if the WebhookHttpConfig type satisfies the MappedNullable interface at compile time
|
||||
var _ MappedNullable = &WebhookHttpConfig{}
|
||||
|
||||
// WebhookHttpConfig HTTP delivery configuration for a webhook.
|
||||
type WebhookHttpConfig struct {
|
||||
// HTTP method: GET or POST
|
||||
Method *string `json:"method,omitempty"`
|
||||
// HTTP request timeout in seconds
|
||||
TimeoutSeconds *int32 `json:"timeout_seconds,omitempty"`
|
||||
// Custom HTTP headers
|
||||
Headers map[string]string `json:"headers,omitempty"`
|
||||
// Custom HTTP query parameters
|
||||
Params map[string]string `json:"params,omitempty"`
|
||||
}
|
||||
|
||||
// NewWebhookHttpConfig instantiates a new WebhookHttpConfig object
|
||||
// This constructor will assign default values to properties that have it defined,
|
||||
// and makes sure properties required by API are set, but the set of arguments
|
||||
// will change when the set of required properties is changed
|
||||
func NewWebhookHttpConfig() *WebhookHttpConfig {
|
||||
this := WebhookHttpConfig{}
|
||||
var method string = "POST"
|
||||
this.Method = &method
|
||||
var timeoutSeconds int32 = 30
|
||||
this.TimeoutSeconds = &timeoutSeconds
|
||||
return &this
|
||||
}
|
||||
|
||||
// NewWebhookHttpConfigWithDefaults instantiates a new WebhookHttpConfig object
|
||||
// This constructor will only assign default values to properties that have it defined,
|
||||
// but it doesn't guarantee that properties required by API are set
|
||||
func NewWebhookHttpConfigWithDefaults() *WebhookHttpConfig {
|
||||
this := WebhookHttpConfig{}
|
||||
var method string = "POST"
|
||||
this.Method = &method
|
||||
var timeoutSeconds int32 = 30
|
||||
this.TimeoutSeconds = &timeoutSeconds
|
||||
return &this
|
||||
}
|
||||
|
||||
// GetMethod returns the Method field value if set, zero value otherwise.
|
||||
func (o *WebhookHttpConfig) GetMethod() string {
|
||||
if o == nil || IsNil(o.Method) {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
return *o.Method
|
||||
}
|
||||
|
||||
// GetMethodOk returns a tuple with the Method field value if set, nil otherwise
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *WebhookHttpConfig) GetMethodOk() (*string, bool) {
|
||||
if o == nil || IsNil(o.Method) {
|
||||
return nil, false
|
||||
}
|
||||
return o.Method, true
|
||||
}
|
||||
|
||||
// HasMethod returns a boolean if a field has been set.
|
||||
func (o *WebhookHttpConfig) HasMethod() bool {
|
||||
if o != nil && !IsNil(o.Method) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SetMethod gets a reference to the given string and assigns it to the Method field.
|
||||
func (o *WebhookHttpConfig) SetMethod(v string) {
|
||||
o.Method = &v
|
||||
}
|
||||
|
||||
// GetTimeoutSeconds returns the TimeoutSeconds field value if set, zero value otherwise.
|
||||
func (o *WebhookHttpConfig) GetTimeoutSeconds() int32 {
|
||||
if o == nil || IsNil(o.TimeoutSeconds) {
|
||||
var ret int32
|
||||
return ret
|
||||
}
|
||||
return *o.TimeoutSeconds
|
||||
}
|
||||
|
||||
// GetTimeoutSecondsOk returns a tuple with the TimeoutSeconds field value if set, nil otherwise
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *WebhookHttpConfig) GetTimeoutSecondsOk() (*int32, bool) {
|
||||
if o == nil || IsNil(o.TimeoutSeconds) {
|
||||
return nil, false
|
||||
}
|
||||
return o.TimeoutSeconds, true
|
||||
}
|
||||
|
||||
// HasTimeoutSeconds returns a boolean if a field has been set.
|
||||
func (o *WebhookHttpConfig) HasTimeoutSeconds() bool {
|
||||
if o != nil && !IsNil(o.TimeoutSeconds) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SetTimeoutSeconds gets a reference to the given int32 and assigns it to the TimeoutSeconds field.
|
||||
func (o *WebhookHttpConfig) SetTimeoutSeconds(v int32) {
|
||||
o.TimeoutSeconds = &v
|
||||
}
|
||||
|
||||
// GetHeaders returns the Headers field value if set, zero value otherwise.
|
||||
func (o *WebhookHttpConfig) GetHeaders() map[string]string {
|
||||
if o == nil || IsNil(o.Headers) {
|
||||
var ret map[string]string
|
||||
return ret
|
||||
}
|
||||
return o.Headers
|
||||
}
|
||||
|
||||
// GetHeadersOk returns a tuple with the Headers field value if set, nil otherwise
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *WebhookHttpConfig) GetHeadersOk() (map[string]string, bool) {
|
||||
if o == nil || IsNil(o.Headers) {
|
||||
return map[string]string{}, false
|
||||
}
|
||||
return o.Headers, true
|
||||
}
|
||||
|
||||
// HasHeaders returns a boolean if a field has been set.
|
||||
func (o *WebhookHttpConfig) HasHeaders() bool {
|
||||
if o != nil && !IsNil(o.Headers) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SetHeaders gets a reference to the given map[string]string and assigns it to the Headers field.
|
||||
func (o *WebhookHttpConfig) SetHeaders(v map[string]string) {
|
||||
o.Headers = v
|
||||
}
|
||||
|
||||
// GetParams returns the Params field value if set, zero value otherwise.
|
||||
func (o *WebhookHttpConfig) GetParams() map[string]string {
|
||||
if o == nil || IsNil(o.Params) {
|
||||
var ret map[string]string
|
||||
return ret
|
||||
}
|
||||
return o.Params
|
||||
}
|
||||
|
||||
// GetParamsOk returns a tuple with the Params field value if set, nil otherwise
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *WebhookHttpConfig) GetParamsOk() (map[string]string, bool) {
|
||||
if o == nil || IsNil(o.Params) {
|
||||
return map[string]string{}, false
|
||||
}
|
||||
return o.Params, true
|
||||
}
|
||||
|
||||
// HasParams returns a boolean if a field has been set.
|
||||
func (o *WebhookHttpConfig) HasParams() bool {
|
||||
if o != nil && !IsNil(o.Params) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SetParams gets a reference to the given map[string]string and assigns it to the Params field.
|
||||
func (o *WebhookHttpConfig) SetParams(v map[string]string) {
|
||||
o.Params = v
|
||||
}
|
||||
|
||||
func (o WebhookHttpConfig) MarshalJSON() ([]byte, error) {
|
||||
toSerialize,err := o.ToMap()
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
return json.Marshal(toSerialize)
|
||||
}
|
||||
|
||||
func (o WebhookHttpConfig) ToMap() (map[string]interface{}, error) {
|
||||
toSerialize := map[string]interface{}{}
|
||||
if !IsNil(o.Method) {
|
||||
toSerialize["method"] = o.Method
|
||||
}
|
||||
if !IsNil(o.TimeoutSeconds) {
|
||||
toSerialize["timeout_seconds"] = o.TimeoutSeconds
|
||||
}
|
||||
if !IsNil(o.Headers) {
|
||||
toSerialize["headers"] = o.Headers
|
||||
}
|
||||
if !IsNil(o.Params) {
|
||||
toSerialize["params"] = o.Params
|
||||
}
|
||||
return toSerialize, nil
|
||||
}
|
||||
|
||||
type NullableWebhookHttpConfig struct {
|
||||
value *WebhookHttpConfig
|
||||
isSet bool
|
||||
}
|
||||
|
||||
func (v NullableWebhookHttpConfig) Get() *WebhookHttpConfig {
|
||||
return v.value
|
||||
}
|
||||
|
||||
func (v *NullableWebhookHttpConfig) Set(val *WebhookHttpConfig) {
|
||||
v.value = val
|
||||
v.isSet = true
|
||||
}
|
||||
|
||||
func (v NullableWebhookHttpConfig) IsSet() bool {
|
||||
return v.isSet
|
||||
}
|
||||
|
||||
func (v *NullableWebhookHttpConfig) Unset() {
|
||||
v.value = nil
|
||||
v.isSet = false
|
||||
}
|
||||
|
||||
func NewNullableWebhookHttpConfig(val *WebhookHttpConfig) *NullableWebhookHttpConfig {
|
||||
return &NullableWebhookHttpConfig{value: val, isSet: true}
|
||||
}
|
||||
|
||||
func (v NullableWebhookHttpConfig) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(v.value)
|
||||
}
|
||||
|
||||
func (v *NullableWebhookHttpConfig) UnmarshalJSON(src []byte) error {
|
||||
v.isSet = true
|
||||
return json.Unmarshal(src, &v.value)
|
||||
}
|
||||
|
||||
|
||||
158
hindsight-clients/go/model_webhook_list_response.go
Normal file
158
hindsight-clients/go/model_webhook_list_response.go
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
Hindsight HTTP API
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
API version: 0.4.15
|
||||
*/
|
||||
|
||||
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
|
||||
|
||||
package hindsight
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// checks if the WebhookListResponse type satisfies the MappedNullable interface at compile time
|
||||
var _ MappedNullable = &WebhookListResponse{}
|
||||
|
||||
// WebhookListResponse Response model for listing webhooks.
|
||||
type WebhookListResponse struct {
|
||||
Items []WebhookResponse `json:"items"`
|
||||
}
|
||||
|
||||
type _WebhookListResponse WebhookListResponse
|
||||
|
||||
// NewWebhookListResponse instantiates a new WebhookListResponse object
|
||||
// This constructor will assign default values to properties that have it defined,
|
||||
// and makes sure properties required by API are set, but the set of arguments
|
||||
// will change when the set of required properties is changed
|
||||
func NewWebhookListResponse(items []WebhookResponse) *WebhookListResponse {
|
||||
this := WebhookListResponse{}
|
||||
this.Items = items
|
||||
return &this
|
||||
}
|
||||
|
||||
// NewWebhookListResponseWithDefaults instantiates a new WebhookListResponse object
|
||||
// This constructor will only assign default values to properties that have it defined,
|
||||
// but it doesn't guarantee that properties required by API are set
|
||||
func NewWebhookListResponseWithDefaults() *WebhookListResponse {
|
||||
this := WebhookListResponse{}
|
||||
return &this
|
||||
}
|
||||
|
||||
// GetItems returns the Items field value
|
||||
func (o *WebhookListResponse) GetItems() []WebhookResponse {
|
||||
if o == nil {
|
||||
var ret []WebhookResponse
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.Items
|
||||
}
|
||||
|
||||
// GetItemsOk returns a tuple with the Items field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *WebhookListResponse) GetItemsOk() ([]WebhookResponse, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return o.Items, true
|
||||
}
|
||||
|
||||
// SetItems sets field value
|
||||
func (o *WebhookListResponse) SetItems(v []WebhookResponse) {
|
||||
o.Items = v
|
||||
}
|
||||
|
||||
func (o WebhookListResponse) MarshalJSON() ([]byte, error) {
|
||||
toSerialize,err := o.ToMap()
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
return json.Marshal(toSerialize)
|
||||
}
|
||||
|
||||
func (o WebhookListResponse) ToMap() (map[string]interface{}, error) {
|
||||
toSerialize := map[string]interface{}{}
|
||||
toSerialize["items"] = o.Items
|
||||
return toSerialize, nil
|
||||
}
|
||||
|
||||
func (o *WebhookListResponse) UnmarshalJSON(data []byte) (err error) {
|
||||
// This validates that all required properties are included in the JSON object
|
||||
// by unmarshalling the object into a generic map with string keys and checking
|
||||
// that every required field exists as a key in the generic map.
|
||||
requiredProperties := []string{
|
||||
"items",
|
||||
}
|
||||
|
||||
allProperties := make(map[string]interface{})
|
||||
|
||||
err = json.Unmarshal(data, &allProperties)
|
||||
|
||||
if err != nil {
|
||||
return err;
|
||||
}
|
||||
|
||||
for _, requiredProperty := range(requiredProperties) {
|
||||
if _, exists := allProperties[requiredProperty]; !exists {
|
||||
return fmt.Errorf("no value given for required property %v", requiredProperty)
|
||||
}
|
||||
}
|
||||
|
||||
varWebhookListResponse := _WebhookListResponse{}
|
||||
|
||||
decoder := json.NewDecoder(bytes.NewReader(data))
|
||||
decoder.DisallowUnknownFields()
|
||||
err = decoder.Decode(&varWebhookListResponse)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*o = WebhookListResponse(varWebhookListResponse)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
type NullableWebhookListResponse struct {
|
||||
value *WebhookListResponse
|
||||
isSet bool
|
||||
}
|
||||
|
||||
func (v NullableWebhookListResponse) Get() *WebhookListResponse {
|
||||
return v.value
|
||||
}
|
||||
|
||||
func (v *NullableWebhookListResponse) Set(val *WebhookListResponse) {
|
||||
v.value = val
|
||||
v.isSet = true
|
||||
}
|
||||
|
||||
func (v NullableWebhookListResponse) IsSet() bool {
|
||||
return v.isSet
|
||||
}
|
||||
|
||||
func (v *NullableWebhookListResponse) Unset() {
|
||||
v.value = nil
|
||||
v.isSet = false
|
||||
}
|
||||
|
||||
func NewNullableWebhookListResponse(val *WebhookListResponse) *NullableWebhookListResponse {
|
||||
return &NullableWebhookListResponse{value: val, isSet: true}
|
||||
}
|
||||
|
||||
func (v NullableWebhookListResponse) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(v.value)
|
||||
}
|
||||
|
||||
func (v *NullableWebhookListResponse) UnmarshalJSON(src []byte) error {
|
||||
v.isSet = true
|
||||
return json.Unmarshal(src, &v.value)
|
||||
}
|
||||
|
||||
|
||||
446
hindsight-clients/go/model_webhook_response.go
Normal file
446
hindsight-clients/go/model_webhook_response.go
Normal file
|
|
@ -0,0 +1,446 @@
|
|||
/*
|
||||
Hindsight HTTP API
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
API version: 0.4.15
|
||||
*/
|
||||
|
||||
// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
|
||||
|
||||
package hindsight
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// checks if the WebhookResponse type satisfies the MappedNullable interface at compile time
|
||||
var _ MappedNullable = &WebhookResponse{}
|
||||
|
||||
// WebhookResponse Response model for a webhook.
|
||||
type WebhookResponse struct {
|
||||
Id string `json:"id"`
|
||||
BankId NullableString `json:"bank_id"`
|
||||
Url string `json:"url"`
|
||||
Secret NullableString `json:"secret,omitempty"`
|
||||
EventTypes []string `json:"event_types"`
|
||||
Enabled bool `json:"enabled"`
|
||||
HttpConfig *WebhookHttpConfig `json:"http_config,omitempty"`
|
||||
CreatedAt NullableString `json:"created_at,omitempty"`
|
||||
UpdatedAt NullableString `json:"updated_at,omitempty"`
|
||||
}
|
||||
|
||||
type _WebhookResponse WebhookResponse
|
||||
|
||||
// NewWebhookResponse instantiates a new WebhookResponse object
|
||||
// This constructor will assign default values to properties that have it defined,
|
||||
// and makes sure properties required by API are set, but the set of arguments
|
||||
// will change when the set of required properties is changed
|
||||
func NewWebhookResponse(id string, bankId NullableString, url string, eventTypes []string, enabled bool) *WebhookResponse {
|
||||
this := WebhookResponse{}
|
||||
this.Id = id
|
||||
this.BankId = bankId
|
||||
this.Url = url
|
||||
this.EventTypes = eventTypes
|
||||
this.Enabled = enabled
|
||||
return &this
|
||||
}
|
||||
|
||||
// NewWebhookResponseWithDefaults instantiates a new WebhookResponse object
|
||||
// This constructor will only assign default values to properties that have it defined,
|
||||
// but it doesn't guarantee that properties required by API are set
|
||||
func NewWebhookResponseWithDefaults() *WebhookResponse {
|
||||
this := WebhookResponse{}
|
||||
return &this
|
||||
}
|
||||
|
||||
// GetId returns the Id field value
|
||||
func (o *WebhookResponse) GetId() string {
|
||||
if o == nil {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.Id
|
||||
}
|
||||
|
||||
// GetIdOk returns a tuple with the Id field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *WebhookResponse) GetIdOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &o.Id, true
|
||||
}
|
||||
|
||||
// SetId sets field value
|
||||
func (o *WebhookResponse) SetId(v string) {
|
||||
o.Id = v
|
||||
}
|
||||
|
||||
// GetBankId returns the BankId field value
|
||||
// If the value is explicit nil, the zero value for string will be returned
|
||||
func (o *WebhookResponse) GetBankId() string {
|
||||
if o == nil || o.BankId.Get() == nil {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
|
||||
return *o.BankId.Get()
|
||||
}
|
||||
|
||||
// GetBankIdOk returns a tuple with the BankId field value
|
||||
// and a boolean to check if the value has been set.
|
||||
// NOTE: If the value is an explicit nil, `nil, true` will be returned
|
||||
func (o *WebhookResponse) GetBankIdOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return o.BankId.Get(), o.BankId.IsSet()
|
||||
}
|
||||
|
||||
// SetBankId sets field value
|
||||
func (o *WebhookResponse) SetBankId(v string) {
|
||||
o.BankId.Set(&v)
|
||||
}
|
||||
|
||||
// GetUrl returns the Url field value
|
||||
func (o *WebhookResponse) GetUrl() string {
|
||||
if o == nil {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.Url
|
||||
}
|
||||
|
||||
// GetUrlOk returns a tuple with the Url field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *WebhookResponse) GetUrlOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &o.Url, true
|
||||
}
|
||||
|
||||
// SetUrl sets field value
|
||||
func (o *WebhookResponse) SetUrl(v string) {
|
||||
o.Url = v
|
||||
}
|
||||
|
||||
// GetSecret returns the Secret field value if set, zero value otherwise (both if not set or set to explicit null).
|
||||
func (o *WebhookResponse) GetSecret() string {
|
||||
if o == nil || IsNil(o.Secret.Get()) {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
return *o.Secret.Get()
|
||||
}
|
||||
|
||||
// GetSecretOk returns a tuple with the Secret field value if set, nil otherwise
|
||||
// and a boolean to check if the value has been set.
|
||||
// NOTE: If the value is an explicit nil, `nil, true` will be returned
|
||||
func (o *WebhookResponse) GetSecretOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return o.Secret.Get(), o.Secret.IsSet()
|
||||
}
|
||||
|
||||
// HasSecret returns a boolean if a field has been set.
|
||||
func (o *WebhookResponse) HasSecret() bool {
|
||||
if o != nil && o.Secret.IsSet() {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SetSecret gets a reference to the given NullableString and assigns it to the Secret field.
|
||||
func (o *WebhookResponse) SetSecret(v string) {
|
||||
o.Secret.Set(&v)
|
||||
}
|
||||
// SetSecretNil sets the value for Secret to be an explicit nil
|
||||
func (o *WebhookResponse) SetSecretNil() {
|
||||
o.Secret.Set(nil)
|
||||
}
|
||||
|
||||
// UnsetSecret ensures that no value is present for Secret, not even an explicit nil
|
||||
func (o *WebhookResponse) UnsetSecret() {
|
||||
o.Secret.Unset()
|
||||
}
|
||||
|
||||
// GetEventTypes returns the EventTypes field value
|
||||
func (o *WebhookResponse) GetEventTypes() []string {
|
||||
if o == nil {
|
||||
var ret []string
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.EventTypes
|
||||
}
|
||||
|
||||
// GetEventTypesOk returns a tuple with the EventTypes field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *WebhookResponse) GetEventTypesOk() ([]string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return o.EventTypes, true
|
||||
}
|
||||
|
||||
// SetEventTypes sets field value
|
||||
func (o *WebhookResponse) SetEventTypes(v []string) {
|
||||
o.EventTypes = v
|
||||
}
|
||||
|
||||
// GetEnabled returns the Enabled field value
|
||||
func (o *WebhookResponse) GetEnabled() bool {
|
||||
if o == nil {
|
||||
var ret bool
|
||||
return ret
|
||||
}
|
||||
|
||||
return o.Enabled
|
||||
}
|
||||
|
||||
// GetEnabledOk returns a tuple with the Enabled field value
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *WebhookResponse) GetEnabledOk() (*bool, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &o.Enabled, true
|
||||
}
|
||||
|
||||
// SetEnabled sets field value
|
||||
func (o *WebhookResponse) SetEnabled(v bool) {
|
||||
o.Enabled = v
|
||||
}
|
||||
|
||||
// GetHttpConfig returns the HttpConfig field value if set, zero value otherwise.
|
||||
func (o *WebhookResponse) GetHttpConfig() WebhookHttpConfig {
|
||||
if o == nil || IsNil(o.HttpConfig) {
|
||||
var ret WebhookHttpConfig
|
||||
return ret
|
||||
}
|
||||
return *o.HttpConfig
|
||||
}
|
||||
|
||||
// GetHttpConfigOk returns a tuple with the HttpConfig field value if set, nil otherwise
|
||||
// and a boolean to check if the value has been set.
|
||||
func (o *WebhookResponse) GetHttpConfigOk() (*WebhookHttpConfig, bool) {
|
||||
if o == nil || IsNil(o.HttpConfig) {
|
||||
return nil, false
|
||||
}
|
||||
return o.HttpConfig, true
|
||||
}
|
||||
|
||||
// HasHttpConfig returns a boolean if a field has been set.
|
||||
func (o *WebhookResponse) HasHttpConfig() bool {
|
||||
if o != nil && !IsNil(o.HttpConfig) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SetHttpConfig gets a reference to the given WebhookHttpConfig and assigns it to the HttpConfig field.
|
||||
func (o *WebhookResponse) SetHttpConfig(v WebhookHttpConfig) {
|
||||
o.HttpConfig = &v
|
||||
}
|
||||
|
||||
// GetCreatedAt returns the CreatedAt field value if set, zero value otherwise (both if not set or set to explicit null).
|
||||
func (o *WebhookResponse) GetCreatedAt() string {
|
||||
if o == nil || IsNil(o.CreatedAt.Get()) {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
return *o.CreatedAt.Get()
|
||||
}
|
||||
|
||||
// GetCreatedAtOk returns a tuple with the CreatedAt field value if set, nil otherwise
|
||||
// and a boolean to check if the value has been set.
|
||||
// NOTE: If the value is an explicit nil, `nil, true` will be returned
|
||||
func (o *WebhookResponse) GetCreatedAtOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return o.CreatedAt.Get(), o.CreatedAt.IsSet()
|
||||
}
|
||||
|
||||
// HasCreatedAt returns a boolean if a field has been set.
|
||||
func (o *WebhookResponse) HasCreatedAt() bool {
|
||||
if o != nil && o.CreatedAt.IsSet() {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SetCreatedAt gets a reference to the given NullableString and assigns it to the CreatedAt field.
|
||||
func (o *WebhookResponse) SetCreatedAt(v string) {
|
||||
o.CreatedAt.Set(&v)
|
||||
}
|
||||
// SetCreatedAtNil sets the value for CreatedAt to be an explicit nil
|
||||
func (o *WebhookResponse) SetCreatedAtNil() {
|
||||
o.CreatedAt.Set(nil)
|
||||
}
|
||||
|
||||
// UnsetCreatedAt ensures that no value is present for CreatedAt, not even an explicit nil
|
||||
func (o *WebhookResponse) UnsetCreatedAt() {
|
||||
o.CreatedAt.Unset()
|
||||
}
|
||||
|
||||
// GetUpdatedAt returns the UpdatedAt field value if set, zero value otherwise (both if not set or set to explicit null).
|
||||
func (o *WebhookResponse) GetUpdatedAt() string {
|
||||
if o == nil || IsNil(o.UpdatedAt.Get()) {
|
||||
var ret string
|
||||
return ret
|
||||
}
|
||||
return *o.UpdatedAt.Get()
|
||||
}
|
||||
|
||||
// GetUpdatedAtOk returns a tuple with the UpdatedAt field value if set, nil otherwise
|
||||
// and a boolean to check if the value has been set.
|
||||
// NOTE: If the value is an explicit nil, `nil, true` will be returned
|
||||
func (o *WebhookResponse) GetUpdatedAtOk() (*string, bool) {
|
||||
if o == nil {
|
||||
return nil, false
|
||||
}
|
||||
return o.UpdatedAt.Get(), o.UpdatedAt.IsSet()
|
||||
}
|
||||
|
||||
// HasUpdatedAt returns a boolean if a field has been set.
|
||||
func (o *WebhookResponse) HasUpdatedAt() bool {
|
||||
if o != nil && o.UpdatedAt.IsSet() {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// SetUpdatedAt gets a reference to the given NullableString and assigns it to the UpdatedAt field.
|
||||
func (o *WebhookResponse) SetUpdatedAt(v string) {
|
||||
o.UpdatedAt.Set(&v)
|
||||
}
|
||||
// SetUpdatedAtNil sets the value for UpdatedAt to be an explicit nil
|
||||
func (o *WebhookResponse) SetUpdatedAtNil() {
|
||||
o.UpdatedAt.Set(nil)
|
||||
}
|
||||
|
||||
// UnsetUpdatedAt ensures that no value is present for UpdatedAt, not even an explicit nil
|
||||
func (o *WebhookResponse) UnsetUpdatedAt() {
|
||||
o.UpdatedAt.Unset()
|
||||
}
|
||||
|
||||
func (o WebhookResponse) MarshalJSON() ([]byte, error) {
|
||||
toSerialize,err := o.ToMap()
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
return json.Marshal(toSerialize)
|
||||
}
|
||||
|
||||
func (o WebhookResponse) ToMap() (map[string]interface{}, error) {
|
||||
toSerialize := map[string]interface{}{}
|
||||
toSerialize["id"] = o.Id
|
||||
toSerialize["bank_id"] = o.BankId.Get()
|
||||
toSerialize["url"] = o.Url
|
||||
if o.Secret.IsSet() {
|
||||
toSerialize["secret"] = o.Secret.Get()
|
||||
}
|
||||
toSerialize["event_types"] = o.EventTypes
|
||||
toSerialize["enabled"] = o.Enabled
|
||||
if !IsNil(o.HttpConfig) {
|
||||
toSerialize["http_config"] = o.HttpConfig
|
||||
}
|
||||
if o.CreatedAt.IsSet() {
|
||||
toSerialize["created_at"] = o.CreatedAt.Get()
|
||||
}
|
||||
if o.UpdatedAt.IsSet() {
|
||||
toSerialize["updated_at"] = o.UpdatedAt.Get()
|
||||
}
|
||||
return toSerialize, nil
|
||||
}
|
||||
|
||||
func (o *WebhookResponse) UnmarshalJSON(data []byte) (err error) {
|
||||
// This validates that all required properties are included in the JSON object
|
||||
// by unmarshalling the object into a generic map with string keys and checking
|
||||
// that every required field exists as a key in the generic map.
|
||||
requiredProperties := []string{
|
||||
"id",
|
||||
"bank_id",
|
||||
"url",
|
||||
"event_types",
|
||||
"enabled",
|
||||
}
|
||||
|
||||
allProperties := make(map[string]interface{})
|
||||
|
||||
err = json.Unmarshal(data, &allProperties)
|
||||
|
||||
if err != nil {
|
||||
return err;
|
||||
}
|
||||
|
||||
for _, requiredProperty := range(requiredProperties) {
|
||||
if _, exists := allProperties[requiredProperty]; !exists {
|
||||
return fmt.Errorf("no value given for required property %v", requiredProperty)
|
||||
}
|
||||
}
|
||||
|
||||
varWebhookResponse := _WebhookResponse{}
|
||||
|
||||
decoder := json.NewDecoder(bytes.NewReader(data))
|
||||
decoder.DisallowUnknownFields()
|
||||
err = decoder.Decode(&varWebhookResponse)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*o = WebhookResponse(varWebhookResponse)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
type NullableWebhookResponse struct {
|
||||
value *WebhookResponse
|
||||
isSet bool
|
||||
}
|
||||
|
||||
func (v NullableWebhookResponse) Get() *WebhookResponse {
|
||||
return v.value
|
||||
}
|
||||
|
||||
func (v *NullableWebhookResponse) Set(val *WebhookResponse) {
|
||||
v.value = val
|
||||
v.isSet = true
|
||||
}
|
||||
|
||||
func (v NullableWebhookResponse) IsSet() bool {
|
||||
return v.isSet
|
||||
}
|
||||
|
||||
func (v *NullableWebhookResponse) Unset() {
|
||||
v.value = nil
|
||||
v.isSet = false
|
||||
}
|
||||
|
||||
func NewNullableWebhookResponse(val *WebhookResponse) *NullableWebhookResponse {
|
||||
return &NullableWebhookResponse{value: val, isSet: true}
|
||||
}
|
||||
|
||||
func (v NullableWebhookResponse) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(v.value)
|
||||
}
|
||||
|
||||
func (v *NullableWebhookResponse) UnmarshalJSON(src []byte) error {
|
||||
v.isSet = true
|
||||
return json.Unmarshal(src, &v.value)
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -9,6 +9,7 @@ hindsight_client_api/api/memory_api.py
|
|||
hindsight_client_api/api/mental_models_api.py
|
||||
hindsight_client_api/api/monitoring_api.py
|
||||
hindsight_client_api/api/operations_api.py
|
||||
hindsight_client_api/api/webhooks_api.py
|
||||
hindsight_client_api/api_client.py
|
||||
hindsight_client_api/api_response.py
|
||||
hindsight_client_api/configuration.py
|
||||
|
|
@ -35,6 +36,7 @@ hindsight_client_api/models/create_bank_request.py
|
|||
hindsight_client_api/models/create_directive_request.py
|
||||
hindsight_client_api/models/create_mental_model_request.py
|
||||
hindsight_client_api/models/create_mental_model_response.py
|
||||
hindsight_client_api/models/create_webhook_request.py
|
||||
hindsight_client_api/models/delete_document_response.py
|
||||
hindsight_client_api/models/delete_response.py
|
||||
hindsight_client_api/models/directive_list_response.py
|
||||
|
|
@ -87,8 +89,14 @@ hindsight_client_api/models/tool_calls_include_options.py
|
|||
hindsight_client_api/models/update_directive_request.py
|
||||
hindsight_client_api/models/update_disposition_request.py
|
||||
hindsight_client_api/models/update_mental_model_request.py
|
||||
hindsight_client_api/models/update_webhook_request.py
|
||||
hindsight_client_api/models/validation_error.py
|
||||
hindsight_client_api/models/validation_error_loc_inner.py
|
||||
hindsight_client_api/models/version_response.py
|
||||
hindsight_client_api/models/webhook_delivery_list_response.py
|
||||
hindsight_client_api/models/webhook_delivery_response.py
|
||||
hindsight_client_api/models/webhook_http_config.py
|
||||
hindsight_client_api/models/webhook_list_response.py
|
||||
hindsight_client_api/models/webhook_response.py
|
||||
hindsight_client_api/rest.py
|
||||
hindsight_client_api_README.md
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ from hindsight_client_api.api.memory_api import MemoryApi
|
|||
from hindsight_client_api.api.mental_models_api import MentalModelsApi
|
||||
from hindsight_client_api.api.monitoring_api import MonitoringApi
|
||||
from hindsight_client_api.api.operations_api import OperationsApi
|
||||
from hindsight_client_api.api.webhooks_api import WebhooksApi
|
||||
|
||||
# import ApiClient
|
||||
from hindsight_client_api.api_response import ApiResponse
|
||||
|
|
@ -60,6 +61,7 @@ from hindsight_client_api.models.create_bank_request import CreateBankRequest
|
|||
from hindsight_client_api.models.create_directive_request import CreateDirectiveRequest
|
||||
from hindsight_client_api.models.create_mental_model_request import CreateMentalModelRequest
|
||||
from hindsight_client_api.models.create_mental_model_response import CreateMentalModelResponse
|
||||
from hindsight_client_api.models.create_webhook_request import CreateWebhookRequest
|
||||
from hindsight_client_api.models.delete_document_response import DeleteDocumentResponse
|
||||
from hindsight_client_api.models.delete_response import DeleteResponse
|
||||
from hindsight_client_api.models.directive_list_response import DirectiveListResponse
|
||||
|
|
@ -112,6 +114,12 @@ from hindsight_client_api.models.tool_calls_include_options import ToolCallsIncl
|
|||
from hindsight_client_api.models.update_directive_request import UpdateDirectiveRequest
|
||||
from hindsight_client_api.models.update_disposition_request import UpdateDispositionRequest
|
||||
from hindsight_client_api.models.update_mental_model_request import UpdateMentalModelRequest
|
||||
from hindsight_client_api.models.update_webhook_request import UpdateWebhookRequest
|
||||
from hindsight_client_api.models.validation_error import ValidationError
|
||||
from hindsight_client_api.models.validation_error_loc_inner import ValidationErrorLocInner
|
||||
from hindsight_client_api.models.version_response import VersionResponse
|
||||
from hindsight_client_api.models.webhook_delivery_list_response import WebhookDeliveryListResponse
|
||||
from hindsight_client_api.models.webhook_delivery_response import WebhookDeliveryResponse
|
||||
from hindsight_client_api.models.webhook_http_config import WebhookHttpConfig
|
||||
from hindsight_client_api.models.webhook_list_response import WebhookListResponse
|
||||
from hindsight_client_api.models.webhook_response import WebhookResponse
|
||||
|
|
|
|||
|
|
@ -10,4 +10,5 @@ from hindsight_client_api.api.memory_api import MemoryApi
|
|||
from hindsight_client_api.api.mental_models_api import MentalModelsApi
|
||||
from hindsight_client_api.api.monitoring_api import MonitoringApi
|
||||
from hindsight_client_api.api.operations_api import OperationsApi
|
||||
from hindsight_client_api.api.webhooks_api import WebhooksApi
|
||||
|
||||
|
|
|
|||
1569
hindsight-clients/python/hindsight_client_api/api/webhooks_api.py
Normal file
1569
hindsight-clients/python/hindsight_client_api/api/webhooks_api.py
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -35,6 +35,7 @@ from hindsight_client_api.models.create_bank_request import CreateBankRequest
|
|||
from hindsight_client_api.models.create_directive_request import CreateDirectiveRequest
|
||||
from hindsight_client_api.models.create_mental_model_request import CreateMentalModelRequest
|
||||
from hindsight_client_api.models.create_mental_model_response import CreateMentalModelResponse
|
||||
from hindsight_client_api.models.create_webhook_request import CreateWebhookRequest
|
||||
from hindsight_client_api.models.delete_document_response import DeleteDocumentResponse
|
||||
from hindsight_client_api.models.delete_response import DeleteResponse
|
||||
from hindsight_client_api.models.directive_list_response import DirectiveListResponse
|
||||
|
|
@ -87,6 +88,12 @@ from hindsight_client_api.models.tool_calls_include_options import ToolCallsIncl
|
|||
from hindsight_client_api.models.update_directive_request import UpdateDirectiveRequest
|
||||
from hindsight_client_api.models.update_disposition_request import UpdateDispositionRequest
|
||||
from hindsight_client_api.models.update_mental_model_request import UpdateMentalModelRequest
|
||||
from hindsight_client_api.models.update_webhook_request import UpdateWebhookRequest
|
||||
from hindsight_client_api.models.validation_error import ValidationError
|
||||
from hindsight_client_api.models.validation_error_loc_inner import ValidationErrorLocInner
|
||||
from hindsight_client_api.models.version_response import VersionResponse
|
||||
from hindsight_client_api.models.webhook_delivery_list_response import WebhookDeliveryListResponse
|
||||
from hindsight_client_api.models.webhook_delivery_response import WebhookDeliveryResponse
|
||||
from hindsight_client_api.models.webhook_http_config import WebhookHttpConfig
|
||||
from hindsight_client_api.models.webhook_list_response import WebhookListResponse
|
||||
from hindsight_client_api.models.webhook_response import WebhookResponse
|
||||
|
|
|
|||
|
|
@ -0,0 +1,104 @@
|
|||
# coding: utf-8
|
||||
|
||||
"""
|
||||
Hindsight HTTP API
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.4.15
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
""" # noqa: E501
|
||||
|
||||
|
||||
from __future__ import annotations
|
||||
import pprint
|
||||
import re # noqa: F401
|
||||
import json
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr
|
||||
from typing import Any, ClassVar, Dict, List, Optional
|
||||
from hindsight_client_api.models.webhook_http_config import WebhookHttpConfig
|
||||
from typing import Optional, Set
|
||||
from typing_extensions import Self
|
||||
|
||||
class CreateWebhookRequest(BaseModel):
|
||||
"""
|
||||
Request model for registering a webhook.
|
||||
""" # noqa: E501
|
||||
url: StrictStr = Field(description="HTTP(S) endpoint URL to deliver events to")
|
||||
secret: Optional[StrictStr] = None
|
||||
event_types: Optional[List[StrictStr]] = Field(default=None, description="List of event types to deliver. Currently supported: 'consolidation.completed'")
|
||||
enabled: Optional[StrictBool] = Field(default=True, description="Whether this webhook is active")
|
||||
http_config: Optional[WebhookHttpConfig] = Field(default=None, description="HTTP delivery configuration (method, timeout, headers, params)")
|
||||
__properties: ClassVar[List[str]] = ["url", "secret", "event_types", "enabled", "http_config"]
|
||||
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
validate_assignment=True,
|
||||
protected_namespaces=(),
|
||||
)
|
||||
|
||||
|
||||
def to_str(self) -> str:
|
||||
"""Returns the string representation of the model using alias"""
|
||||
return pprint.pformat(self.model_dump(by_alias=True))
|
||||
|
||||
def to_json(self) -> str:
|
||||
"""Returns the JSON representation of the model using alias"""
|
||||
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
|
||||
return json.dumps(self.to_dict())
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json_str: str) -> Optional[Self]:
|
||||
"""Create an instance of CreateWebhookRequest from a JSON string"""
|
||||
return cls.from_dict(json.loads(json_str))
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
"""Return the dictionary representation of the model using alias.
|
||||
|
||||
This has the following differences from calling pydantic's
|
||||
`self.model_dump(by_alias=True)`:
|
||||
|
||||
* `None` is only added to the output dict for nullable fields that
|
||||
were set at model initialization. Other fields with value `None`
|
||||
are ignored.
|
||||
"""
|
||||
excluded_fields: Set[str] = set([
|
||||
])
|
||||
|
||||
_dict = self.model_dump(
|
||||
by_alias=True,
|
||||
exclude=excluded_fields,
|
||||
exclude_none=True,
|
||||
)
|
||||
# override the default output from pydantic by calling `to_dict()` of http_config
|
||||
if self.http_config:
|
||||
_dict['http_config'] = self.http_config.to_dict()
|
||||
# set to None if secret (nullable) is None
|
||||
# and model_fields_set contains the field
|
||||
if self.secret is None and "secret" in self.model_fields_set:
|
||||
_dict['secret'] = None
|
||||
|
||||
return _dict
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
|
||||
"""Create an instance of CreateWebhookRequest from a dict"""
|
||||
if obj is None:
|
||||
return None
|
||||
|
||||
if not isinstance(obj, dict):
|
||||
return cls.model_validate(obj)
|
||||
|
||||
_obj = cls.model_validate({
|
||||
"url": obj.get("url"),
|
||||
"secret": obj.get("secret"),
|
||||
"event_types": obj.get("event_types"),
|
||||
"enabled": obj.get("enabled") if obj.get("enabled") is not None else True,
|
||||
"http_config": WebhookHttpConfig.from_dict(obj["http_config"]) if obj.get("http_config") is not None else None
|
||||
})
|
||||
return _obj
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
# coding: utf-8
|
||||
|
||||
"""
|
||||
Hindsight HTTP API
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.4.15
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
""" # noqa: E501
|
||||
|
||||
|
||||
from __future__ import annotations
|
||||
import pprint
|
||||
import re # noqa: F401
|
||||
import json
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, StrictBool, StrictStr
|
||||
from typing import Any, ClassVar, Dict, List, Optional
|
||||
from hindsight_client_api.models.webhook_http_config import WebhookHttpConfig
|
||||
from typing import Optional, Set
|
||||
from typing_extensions import Self
|
||||
|
||||
class UpdateWebhookRequest(BaseModel):
|
||||
"""
|
||||
Request model for updating a webhook. Only provided fields are updated.
|
||||
""" # noqa: E501
|
||||
url: Optional[StrictStr] = None
|
||||
secret: Optional[StrictStr] = None
|
||||
event_types: Optional[List[StrictStr]] = None
|
||||
enabled: Optional[StrictBool] = None
|
||||
http_config: Optional[WebhookHttpConfig] = None
|
||||
__properties: ClassVar[List[str]] = ["url", "secret", "event_types", "enabled", "http_config"]
|
||||
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
validate_assignment=True,
|
||||
protected_namespaces=(),
|
||||
)
|
||||
|
||||
|
||||
def to_str(self) -> str:
|
||||
"""Returns the string representation of the model using alias"""
|
||||
return pprint.pformat(self.model_dump(by_alias=True))
|
||||
|
||||
def to_json(self) -> str:
|
||||
"""Returns the JSON representation of the model using alias"""
|
||||
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
|
||||
return json.dumps(self.to_dict())
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json_str: str) -> Optional[Self]:
|
||||
"""Create an instance of UpdateWebhookRequest from a JSON string"""
|
||||
return cls.from_dict(json.loads(json_str))
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
"""Return the dictionary representation of the model using alias.
|
||||
|
||||
This has the following differences from calling pydantic's
|
||||
`self.model_dump(by_alias=True)`:
|
||||
|
||||
* `None` is only added to the output dict for nullable fields that
|
||||
were set at model initialization. Other fields with value `None`
|
||||
are ignored.
|
||||
"""
|
||||
excluded_fields: Set[str] = set([
|
||||
])
|
||||
|
||||
_dict = self.model_dump(
|
||||
by_alias=True,
|
||||
exclude=excluded_fields,
|
||||
exclude_none=True,
|
||||
)
|
||||
# override the default output from pydantic by calling `to_dict()` of http_config
|
||||
if self.http_config:
|
||||
_dict['http_config'] = self.http_config.to_dict()
|
||||
# set to None if url (nullable) is None
|
||||
# and model_fields_set contains the field
|
||||
if self.url is None and "url" in self.model_fields_set:
|
||||
_dict['url'] = None
|
||||
|
||||
# set to None if secret (nullable) is None
|
||||
# and model_fields_set contains the field
|
||||
if self.secret is None and "secret" in self.model_fields_set:
|
||||
_dict['secret'] = None
|
||||
|
||||
# set to None if event_types (nullable) is None
|
||||
# and model_fields_set contains the field
|
||||
if self.event_types is None and "event_types" in self.model_fields_set:
|
||||
_dict['event_types'] = None
|
||||
|
||||
# set to None if enabled (nullable) is None
|
||||
# and model_fields_set contains the field
|
||||
if self.enabled is None and "enabled" in self.model_fields_set:
|
||||
_dict['enabled'] = None
|
||||
|
||||
# set to None if http_config (nullable) is None
|
||||
# and model_fields_set contains the field
|
||||
if self.http_config is None and "http_config" in self.model_fields_set:
|
||||
_dict['http_config'] = None
|
||||
|
||||
return _dict
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
|
||||
"""Create an instance of UpdateWebhookRequest from a dict"""
|
||||
if obj is None:
|
||||
return None
|
||||
|
||||
if not isinstance(obj, dict):
|
||||
return cls.model_validate(obj)
|
||||
|
||||
_obj = cls.model_validate({
|
||||
"url": obj.get("url"),
|
||||
"secret": obj.get("secret"),
|
||||
"event_types": obj.get("event_types"),
|
||||
"enabled": obj.get("enabled"),
|
||||
"http_config": WebhookHttpConfig.from_dict(obj["http_config"]) if obj.get("http_config") is not None else None
|
||||
})
|
||||
return _obj
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
# coding: utf-8
|
||||
|
||||
"""
|
||||
Hindsight HTTP API
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.4.15
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
""" # noqa: E501
|
||||
|
||||
|
||||
from __future__ import annotations
|
||||
import pprint
|
||||
import re # noqa: F401
|
||||
import json
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, StrictStr
|
||||
from typing import Any, ClassVar, Dict, List, Optional
|
||||
from hindsight_client_api.models.webhook_delivery_response import WebhookDeliveryResponse
|
||||
from typing import Optional, Set
|
||||
from typing_extensions import Self
|
||||
|
||||
class WebhookDeliveryListResponse(BaseModel):
|
||||
"""
|
||||
Response model for listing webhook deliveries.
|
||||
""" # noqa: E501
|
||||
items: List[WebhookDeliveryResponse]
|
||||
next_cursor: Optional[StrictStr] = None
|
||||
__properties: ClassVar[List[str]] = ["items", "next_cursor"]
|
||||
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
validate_assignment=True,
|
||||
protected_namespaces=(),
|
||||
)
|
||||
|
||||
|
||||
def to_str(self) -> str:
|
||||
"""Returns the string representation of the model using alias"""
|
||||
return pprint.pformat(self.model_dump(by_alias=True))
|
||||
|
||||
def to_json(self) -> str:
|
||||
"""Returns the JSON representation of the model using alias"""
|
||||
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
|
||||
return json.dumps(self.to_dict())
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json_str: str) -> Optional[Self]:
|
||||
"""Create an instance of WebhookDeliveryListResponse from a JSON string"""
|
||||
return cls.from_dict(json.loads(json_str))
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
"""Return the dictionary representation of the model using alias.
|
||||
|
||||
This has the following differences from calling pydantic's
|
||||
`self.model_dump(by_alias=True)`:
|
||||
|
||||
* `None` is only added to the output dict for nullable fields that
|
||||
were set at model initialization. Other fields with value `None`
|
||||
are ignored.
|
||||
"""
|
||||
excluded_fields: Set[str] = set([
|
||||
])
|
||||
|
||||
_dict = self.model_dump(
|
||||
by_alias=True,
|
||||
exclude=excluded_fields,
|
||||
exclude_none=True,
|
||||
)
|
||||
# override the default output from pydantic by calling `to_dict()` of each item in items (list)
|
||||
_items = []
|
||||
if self.items:
|
||||
for _item_items in self.items:
|
||||
if _item_items:
|
||||
_items.append(_item_items.to_dict())
|
||||
_dict['items'] = _items
|
||||
# set to None if next_cursor (nullable) is None
|
||||
# and model_fields_set contains the field
|
||||
if self.next_cursor is None and "next_cursor" in self.model_fields_set:
|
||||
_dict['next_cursor'] = None
|
||||
|
||||
return _dict
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
|
||||
"""Create an instance of WebhookDeliveryListResponse from a dict"""
|
||||
if obj is None:
|
||||
return None
|
||||
|
||||
if not isinstance(obj, dict):
|
||||
return cls.model_validate(obj)
|
||||
|
||||
_obj = cls.model_validate({
|
||||
"items": [WebhookDeliveryResponse.from_dict(_item) for _item in obj["items"]] if obj.get("items") is not None else None,
|
||||
"next_cursor": obj.get("next_cursor")
|
||||
})
|
||||
return _obj
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
# coding: utf-8
|
||||
|
||||
"""
|
||||
Hindsight HTTP API
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.4.15
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
""" # noqa: E501
|
||||
|
||||
|
||||
from __future__ import annotations
|
||||
import pprint
|
||||
import re # noqa: F401
|
||||
import json
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, StrictInt, StrictStr
|
||||
from typing import Any, ClassVar, Dict, List, Optional
|
||||
from typing import Optional, Set
|
||||
from typing_extensions import Self
|
||||
|
||||
class WebhookDeliveryResponse(BaseModel):
|
||||
"""
|
||||
Response model for a webhook delivery record.
|
||||
""" # noqa: E501
|
||||
id: StrictStr
|
||||
webhook_id: Optional[StrictStr]
|
||||
url: StrictStr
|
||||
event_type: StrictStr
|
||||
status: StrictStr
|
||||
attempts: StrictInt
|
||||
next_retry_at: Optional[StrictStr] = None
|
||||
last_error: Optional[StrictStr] = None
|
||||
last_response_status: Optional[StrictInt] = None
|
||||
last_response_body: Optional[StrictStr] = None
|
||||
last_attempt_at: Optional[StrictStr] = None
|
||||
created_at: Optional[StrictStr] = None
|
||||
updated_at: Optional[StrictStr] = None
|
||||
__properties: ClassVar[List[str]] = ["id", "webhook_id", "url", "event_type", "status", "attempts", "next_retry_at", "last_error", "last_response_status", "last_response_body", "last_attempt_at", "created_at", "updated_at"]
|
||||
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
validate_assignment=True,
|
||||
protected_namespaces=(),
|
||||
)
|
||||
|
||||
|
||||
def to_str(self) -> str:
|
||||
"""Returns the string representation of the model using alias"""
|
||||
return pprint.pformat(self.model_dump(by_alias=True))
|
||||
|
||||
def to_json(self) -> str:
|
||||
"""Returns the JSON representation of the model using alias"""
|
||||
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
|
||||
return json.dumps(self.to_dict())
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json_str: str) -> Optional[Self]:
|
||||
"""Create an instance of WebhookDeliveryResponse from a JSON string"""
|
||||
return cls.from_dict(json.loads(json_str))
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
"""Return the dictionary representation of the model using alias.
|
||||
|
||||
This has the following differences from calling pydantic's
|
||||
`self.model_dump(by_alias=True)`:
|
||||
|
||||
* `None` is only added to the output dict for nullable fields that
|
||||
were set at model initialization. Other fields with value `None`
|
||||
are ignored.
|
||||
"""
|
||||
excluded_fields: Set[str] = set([
|
||||
])
|
||||
|
||||
_dict = self.model_dump(
|
||||
by_alias=True,
|
||||
exclude=excluded_fields,
|
||||
exclude_none=True,
|
||||
)
|
||||
# set to None if webhook_id (nullable) is None
|
||||
# and model_fields_set contains the field
|
||||
if self.webhook_id is None and "webhook_id" in self.model_fields_set:
|
||||
_dict['webhook_id'] = None
|
||||
|
||||
# set to None if next_retry_at (nullable) is None
|
||||
# and model_fields_set contains the field
|
||||
if self.next_retry_at is None and "next_retry_at" in self.model_fields_set:
|
||||
_dict['next_retry_at'] = None
|
||||
|
||||
# set to None if last_error (nullable) is None
|
||||
# and model_fields_set contains the field
|
||||
if self.last_error is None and "last_error" in self.model_fields_set:
|
||||
_dict['last_error'] = None
|
||||
|
||||
# set to None if last_response_status (nullable) is None
|
||||
# and model_fields_set contains the field
|
||||
if self.last_response_status is None and "last_response_status" in self.model_fields_set:
|
||||
_dict['last_response_status'] = None
|
||||
|
||||
# set to None if last_response_body (nullable) is None
|
||||
# and model_fields_set contains the field
|
||||
if self.last_response_body is None and "last_response_body" in self.model_fields_set:
|
||||
_dict['last_response_body'] = None
|
||||
|
||||
# set to None if last_attempt_at (nullable) is None
|
||||
# and model_fields_set contains the field
|
||||
if self.last_attempt_at is None and "last_attempt_at" in self.model_fields_set:
|
||||
_dict['last_attempt_at'] = None
|
||||
|
||||
# set to None if created_at (nullable) is None
|
||||
# and model_fields_set contains the field
|
||||
if self.created_at is None and "created_at" in self.model_fields_set:
|
||||
_dict['created_at'] = None
|
||||
|
||||
# set to None if updated_at (nullable) is None
|
||||
# and model_fields_set contains the field
|
||||
if self.updated_at is None and "updated_at" in self.model_fields_set:
|
||||
_dict['updated_at'] = None
|
||||
|
||||
return _dict
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
|
||||
"""Create an instance of WebhookDeliveryResponse from a dict"""
|
||||
if obj is None:
|
||||
return None
|
||||
|
||||
if not isinstance(obj, dict):
|
||||
return cls.model_validate(obj)
|
||||
|
||||
_obj = cls.model_validate({
|
||||
"id": obj.get("id"),
|
||||
"webhook_id": obj.get("webhook_id"),
|
||||
"url": obj.get("url"),
|
||||
"event_type": obj.get("event_type"),
|
||||
"status": obj.get("status"),
|
||||
"attempts": obj.get("attempts"),
|
||||
"next_retry_at": obj.get("next_retry_at"),
|
||||
"last_error": obj.get("last_error"),
|
||||
"last_response_status": obj.get("last_response_status"),
|
||||
"last_response_body": obj.get("last_response_body"),
|
||||
"last_attempt_at": obj.get("last_attempt_at"),
|
||||
"created_at": obj.get("created_at"),
|
||||
"updated_at": obj.get("updated_at")
|
||||
})
|
||||
return _obj
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
# coding: utf-8
|
||||
|
||||
"""
|
||||
Hindsight HTTP API
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.4.15
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
""" # noqa: E501
|
||||
|
||||
|
||||
from __future__ import annotations
|
||||
import pprint
|
||||
import re # noqa: F401
|
||||
import json
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, StrictInt, StrictStr
|
||||
from typing import Any, ClassVar, Dict, List, Optional
|
||||
from typing import Optional, Set
|
||||
from typing_extensions import Self
|
||||
|
||||
class WebhookHttpConfig(BaseModel):
|
||||
"""
|
||||
HTTP delivery configuration for a webhook.
|
||||
""" # noqa: E501
|
||||
method: Optional[StrictStr] = Field(default='POST', description="HTTP method: GET or POST")
|
||||
timeout_seconds: Optional[StrictInt] = Field(default=30, description="HTTP request timeout in seconds")
|
||||
headers: Optional[Dict[str, StrictStr]] = Field(default=None, description="Custom HTTP headers")
|
||||
params: Optional[Dict[str, StrictStr]] = Field(default=None, description="Custom HTTP query parameters")
|
||||
__properties: ClassVar[List[str]] = ["method", "timeout_seconds", "headers", "params"]
|
||||
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
validate_assignment=True,
|
||||
protected_namespaces=(),
|
||||
)
|
||||
|
||||
|
||||
def to_str(self) -> str:
|
||||
"""Returns the string representation of the model using alias"""
|
||||
return pprint.pformat(self.model_dump(by_alias=True))
|
||||
|
||||
def to_json(self) -> str:
|
||||
"""Returns the JSON representation of the model using alias"""
|
||||
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
|
||||
return json.dumps(self.to_dict())
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json_str: str) -> Optional[Self]:
|
||||
"""Create an instance of WebhookHttpConfig from a JSON string"""
|
||||
return cls.from_dict(json.loads(json_str))
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
"""Return the dictionary representation of the model using alias.
|
||||
|
||||
This has the following differences from calling pydantic's
|
||||
`self.model_dump(by_alias=True)`:
|
||||
|
||||
* `None` is only added to the output dict for nullable fields that
|
||||
were set at model initialization. Other fields with value `None`
|
||||
are ignored.
|
||||
"""
|
||||
excluded_fields: Set[str] = set([
|
||||
])
|
||||
|
||||
_dict = self.model_dump(
|
||||
by_alias=True,
|
||||
exclude=excluded_fields,
|
||||
exclude_none=True,
|
||||
)
|
||||
return _dict
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
|
||||
"""Create an instance of WebhookHttpConfig from a dict"""
|
||||
if obj is None:
|
||||
return None
|
||||
|
||||
if not isinstance(obj, dict):
|
||||
return cls.model_validate(obj)
|
||||
|
||||
_obj = cls.model_validate({
|
||||
"method": obj.get("method") if obj.get("method") is not None else 'POST',
|
||||
"timeout_seconds": obj.get("timeout_seconds") if obj.get("timeout_seconds") is not None else 30,
|
||||
"headers": obj.get("headers"),
|
||||
"params": obj.get("params")
|
||||
})
|
||||
return _obj
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
# coding: utf-8
|
||||
|
||||
"""
|
||||
Hindsight HTTP API
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.4.15
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
""" # noqa: E501
|
||||
|
||||
|
||||
from __future__ import annotations
|
||||
import pprint
|
||||
import re # noqa: F401
|
||||
import json
|
||||
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from typing import Any, ClassVar, Dict, List
|
||||
from hindsight_client_api.models.webhook_response import WebhookResponse
|
||||
from typing import Optional, Set
|
||||
from typing_extensions import Self
|
||||
|
||||
class WebhookListResponse(BaseModel):
|
||||
"""
|
||||
Response model for listing webhooks.
|
||||
""" # noqa: E501
|
||||
items: List[WebhookResponse]
|
||||
__properties: ClassVar[List[str]] = ["items"]
|
||||
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
validate_assignment=True,
|
||||
protected_namespaces=(),
|
||||
)
|
||||
|
||||
|
||||
def to_str(self) -> str:
|
||||
"""Returns the string representation of the model using alias"""
|
||||
return pprint.pformat(self.model_dump(by_alias=True))
|
||||
|
||||
def to_json(self) -> str:
|
||||
"""Returns the JSON representation of the model using alias"""
|
||||
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
|
||||
return json.dumps(self.to_dict())
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json_str: str) -> Optional[Self]:
|
||||
"""Create an instance of WebhookListResponse from a JSON string"""
|
||||
return cls.from_dict(json.loads(json_str))
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
"""Return the dictionary representation of the model using alias.
|
||||
|
||||
This has the following differences from calling pydantic's
|
||||
`self.model_dump(by_alias=True)`:
|
||||
|
||||
* `None` is only added to the output dict for nullable fields that
|
||||
were set at model initialization. Other fields with value `None`
|
||||
are ignored.
|
||||
"""
|
||||
excluded_fields: Set[str] = set([
|
||||
])
|
||||
|
||||
_dict = self.model_dump(
|
||||
by_alias=True,
|
||||
exclude=excluded_fields,
|
||||
exclude_none=True,
|
||||
)
|
||||
# override the default output from pydantic by calling `to_dict()` of each item in items (list)
|
||||
_items = []
|
||||
if self.items:
|
||||
for _item_items in self.items:
|
||||
if _item_items:
|
||||
_items.append(_item_items.to_dict())
|
||||
_dict['items'] = _items
|
||||
return _dict
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
|
||||
"""Create an instance of WebhookListResponse from a dict"""
|
||||
if obj is None:
|
||||
return None
|
||||
|
||||
if not isinstance(obj, dict):
|
||||
return cls.model_validate(obj)
|
||||
|
||||
_obj = cls.model_validate({
|
||||
"items": [WebhookResponse.from_dict(_item) for _item in obj["items"]] if obj.get("items") is not None else None
|
||||
})
|
||||
return _obj
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
# coding: utf-8
|
||||
|
||||
"""
|
||||
Hindsight HTTP API
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.4.15
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
""" # noqa: E501
|
||||
|
||||
|
||||
from __future__ import annotations
|
||||
import pprint
|
||||
import re # noqa: F401
|
||||
import json
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, StrictBool, StrictStr
|
||||
from typing import Any, ClassVar, Dict, List, Optional
|
||||
from hindsight_client_api.models.webhook_http_config import WebhookHttpConfig
|
||||
from typing import Optional, Set
|
||||
from typing_extensions import Self
|
||||
|
||||
class WebhookResponse(BaseModel):
|
||||
"""
|
||||
Response model for a webhook.
|
||||
""" # noqa: E501
|
||||
id: StrictStr
|
||||
bank_id: Optional[StrictStr]
|
||||
url: StrictStr
|
||||
secret: Optional[StrictStr] = None
|
||||
event_types: List[StrictStr]
|
||||
enabled: StrictBool
|
||||
http_config: Optional[WebhookHttpConfig] = None
|
||||
created_at: Optional[StrictStr] = None
|
||||
updated_at: Optional[StrictStr] = None
|
||||
__properties: ClassVar[List[str]] = ["id", "bank_id", "url", "secret", "event_types", "enabled", "http_config", "created_at", "updated_at"]
|
||||
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
validate_assignment=True,
|
||||
protected_namespaces=(),
|
||||
)
|
||||
|
||||
|
||||
def to_str(self) -> str:
|
||||
"""Returns the string representation of the model using alias"""
|
||||
return pprint.pformat(self.model_dump(by_alias=True))
|
||||
|
||||
def to_json(self) -> str:
|
||||
"""Returns the JSON representation of the model using alias"""
|
||||
# TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
|
||||
return json.dumps(self.to_dict())
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, json_str: str) -> Optional[Self]:
|
||||
"""Create an instance of WebhookResponse from a JSON string"""
|
||||
return cls.from_dict(json.loads(json_str))
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
"""Return the dictionary representation of the model using alias.
|
||||
|
||||
This has the following differences from calling pydantic's
|
||||
`self.model_dump(by_alias=True)`:
|
||||
|
||||
* `None` is only added to the output dict for nullable fields that
|
||||
were set at model initialization. Other fields with value `None`
|
||||
are ignored.
|
||||
"""
|
||||
excluded_fields: Set[str] = set([
|
||||
])
|
||||
|
||||
_dict = self.model_dump(
|
||||
by_alias=True,
|
||||
exclude=excluded_fields,
|
||||
exclude_none=True,
|
||||
)
|
||||
# override the default output from pydantic by calling `to_dict()` of http_config
|
||||
if self.http_config:
|
||||
_dict['http_config'] = self.http_config.to_dict()
|
||||
# set to None if bank_id (nullable) is None
|
||||
# and model_fields_set contains the field
|
||||
if self.bank_id is None and "bank_id" in self.model_fields_set:
|
||||
_dict['bank_id'] = None
|
||||
|
||||
# set to None if secret (nullable) is None
|
||||
# and model_fields_set contains the field
|
||||
if self.secret is None and "secret" in self.model_fields_set:
|
||||
_dict['secret'] = None
|
||||
|
||||
# set to None if created_at (nullable) is None
|
||||
# and model_fields_set contains the field
|
||||
if self.created_at is None and "created_at" in self.model_fields_set:
|
||||
_dict['created_at'] = None
|
||||
|
||||
# set to None if updated_at (nullable) is None
|
||||
# and model_fields_set contains the field
|
||||
if self.updated_at is None and "updated_at" in self.model_fields_set:
|
||||
_dict['updated_at'] = None
|
||||
|
||||
return _dict
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
|
||||
"""Create an instance of WebhookResponse from a dict"""
|
||||
if obj is None:
|
||||
return None
|
||||
|
||||
if not isinstance(obj, dict):
|
||||
return cls.model_validate(obj)
|
||||
|
||||
_obj = cls.model_validate({
|
||||
"id": obj.get("id"),
|
||||
"bank_id": obj.get("bank_id"),
|
||||
"url": obj.get("url"),
|
||||
"secret": obj.get("secret"),
|
||||
"event_types": obj.get("event_types"),
|
||||
"enabled": obj.get("enabled"),
|
||||
"http_config": WebhookHttpConfig.from_dict(obj["http_config"]) if obj.get("http_config") is not None else None,
|
||||
"created_at": obj.get("created_at"),
|
||||
"updated_at": obj.get("updated_at")
|
||||
})
|
||||
return _obj
|
||||
|
||||
|
||||
|
|
@ -32,6 +32,9 @@ import type {
|
|||
CreateOrUpdateBankData,
|
||||
CreateOrUpdateBankErrors,
|
||||
CreateOrUpdateBankResponses,
|
||||
CreateWebhookData,
|
||||
CreateWebhookErrors,
|
||||
CreateWebhookResponses,
|
||||
DeleteBankData,
|
||||
DeleteBankErrors,
|
||||
DeleteBankResponses,
|
||||
|
|
@ -44,6 +47,9 @@ import type {
|
|||
DeleteMentalModelData,
|
||||
DeleteMentalModelErrors,
|
||||
DeleteMentalModelResponses,
|
||||
DeleteWebhookData,
|
||||
DeleteWebhookErrors,
|
||||
DeleteWebhookResponses,
|
||||
FileRetainData,
|
||||
FileRetainErrors,
|
||||
FileRetainResponses,
|
||||
|
|
@ -108,6 +114,12 @@ import type {
|
|||
ListTagsData,
|
||||
ListTagsErrors,
|
||||
ListTagsResponses,
|
||||
ListWebhookDeliveriesData,
|
||||
ListWebhookDeliveriesErrors,
|
||||
ListWebhookDeliveriesResponses,
|
||||
ListWebhooksData,
|
||||
ListWebhooksErrors,
|
||||
ListWebhooksResponses,
|
||||
MetricsEndpointMetricsGetData,
|
||||
MetricsEndpointMetricsGetResponses,
|
||||
RecallMemoriesData,
|
||||
|
|
@ -146,6 +158,9 @@ import type {
|
|||
UpdateMentalModelData,
|
||||
UpdateMentalModelErrors,
|
||||
UpdateMentalModelResponses,
|
||||
UpdateWebhookData,
|
||||
UpdateWebhookErrors,
|
||||
UpdateWebhookResponses,
|
||||
} from "./types.gen";
|
||||
|
||||
export type Options<
|
||||
|
|
@ -912,6 +927,93 @@ export const triggerConsolidation = <ThrowOnError extends boolean = false>(
|
|||
ThrowOnError
|
||||
>({ url: "/v1/default/banks/{bank_id}/consolidate", ...options });
|
||||
|
||||
/**
|
||||
* List webhooks
|
||||
*
|
||||
* List all webhooks registered for a bank.
|
||||
*/
|
||||
export const listWebhooks = <ThrowOnError extends boolean = false>(
|
||||
options: Options<ListWebhooksData, ThrowOnError>,
|
||||
) =>
|
||||
(options.client ?? client).get<
|
||||
ListWebhooksResponses,
|
||||
ListWebhooksErrors,
|
||||
ThrowOnError
|
||||
>({ url: "/v1/default/banks/{bank_id}/webhooks", ...options });
|
||||
|
||||
/**
|
||||
* Register webhook
|
||||
*
|
||||
* Register a webhook endpoint to receive event notifications for this bank.
|
||||
*/
|
||||
export const createWebhook = <ThrowOnError extends boolean = false>(
|
||||
options: Options<CreateWebhookData, ThrowOnError>,
|
||||
) =>
|
||||
(options.client ?? client).post<
|
||||
CreateWebhookResponses,
|
||||
CreateWebhookErrors,
|
||||
ThrowOnError
|
||||
>({
|
||||
url: "/v1/default/banks/{bank_id}/webhooks",
|
||||
...options,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...options.headers,
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Delete webhook
|
||||
*
|
||||
* Remove a registered webhook.
|
||||
*/
|
||||
export const deleteWebhook = <ThrowOnError extends boolean = false>(
|
||||
options: Options<DeleteWebhookData, ThrowOnError>,
|
||||
) =>
|
||||
(options.client ?? client).delete<
|
||||
DeleteWebhookResponses,
|
||||
DeleteWebhookErrors,
|
||||
ThrowOnError
|
||||
>({ url: "/v1/default/banks/{bank_id}/webhooks/{webhook_id}", ...options });
|
||||
|
||||
/**
|
||||
* Update webhook
|
||||
*
|
||||
* Update one or more fields of a registered webhook. Only provided fields are changed.
|
||||
*/
|
||||
export const updateWebhook = <ThrowOnError extends boolean = false>(
|
||||
options: Options<UpdateWebhookData, ThrowOnError>,
|
||||
) =>
|
||||
(options.client ?? client).patch<
|
||||
UpdateWebhookResponses,
|
||||
UpdateWebhookErrors,
|
||||
ThrowOnError
|
||||
>({
|
||||
url: "/v1/default/banks/{bank_id}/webhooks/{webhook_id}",
|
||||
...options,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...options.headers,
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* List webhook deliveries
|
||||
*
|
||||
* Inspect delivery history for a webhook (useful for debugging).
|
||||
*/
|
||||
export const listWebhookDeliveries = <ThrowOnError extends boolean = false>(
|
||||
options: Options<ListWebhookDeliveriesData, ThrowOnError>,
|
||||
) =>
|
||||
(options.client ?? client).get<
|
||||
ListWebhookDeliveriesResponses,
|
||||
ListWebhookDeliveriesErrors,
|
||||
ThrowOnError
|
||||
>({
|
||||
url: "/v1/default/banks/{bank_id}/webhooks/{webhook_id}/deliveries",
|
||||
...options,
|
||||
});
|
||||
|
||||
/**
|
||||
* Clear memory bank memories
|
||||
*
|
||||
|
|
|
|||
|
|
@ -618,6 +618,42 @@ export type CreateMentalModelResponse = {
|
|||
operation_id: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* CreateWebhookRequest
|
||||
*
|
||||
* Request model for registering a webhook.
|
||||
*/
|
||||
export type CreateWebhookRequest = {
|
||||
/**
|
||||
* Url
|
||||
*
|
||||
* HTTP(S) endpoint URL to deliver events to
|
||||
*/
|
||||
url: string;
|
||||
/**
|
||||
* Secret
|
||||
*
|
||||
* HMAC-SHA256 signing secret (optional)
|
||||
*/
|
||||
secret?: string | null;
|
||||
/**
|
||||
* Event Types
|
||||
*
|
||||
* List of event types to deliver. Currently supported: 'consolidation.completed'
|
||||
*/
|
||||
event_types?: Array<string>;
|
||||
/**
|
||||
* Enabled
|
||||
*
|
||||
* Whether this webhook is active
|
||||
*/
|
||||
enabled?: boolean;
|
||||
/**
|
||||
* HTTP delivery configuration (method, timeout, headers, params)
|
||||
*/
|
||||
http_config?: WebhookHttpConfig;
|
||||
};
|
||||
|
||||
/**
|
||||
* DeleteDocumentResponse
|
||||
*
|
||||
|
|
@ -2075,6 +2111,42 @@ export type UpdateMentalModelRequest = {
|
|||
trigger?: MentalModelTrigger | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* UpdateWebhookRequest
|
||||
*
|
||||
* Request model for updating a webhook. Only provided fields are updated.
|
||||
*/
|
||||
export type UpdateWebhookRequest = {
|
||||
/**
|
||||
* Url
|
||||
*
|
||||
* HTTP(S) endpoint URL
|
||||
*/
|
||||
url?: string | null;
|
||||
/**
|
||||
* Secret
|
||||
*
|
||||
* HMAC-SHA256 signing secret. Omit to keep existing; send null to clear.
|
||||
*/
|
||||
secret?: string | null;
|
||||
/**
|
||||
* Event Types
|
||||
*
|
||||
* List of event types
|
||||
*/
|
||||
event_types?: Array<string> | null;
|
||||
/**
|
||||
* Enabled
|
||||
*
|
||||
* Whether this webhook is active
|
||||
*/
|
||||
enabled?: boolean | null;
|
||||
/**
|
||||
* HTTP delivery configuration
|
||||
*/
|
||||
http_config?: WebhookHttpConfig | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* ValidationError
|
||||
*/
|
||||
|
|
@ -2111,6 +2183,173 @@ export type VersionResponse = {
|
|||
features: FeaturesInfo;
|
||||
};
|
||||
|
||||
/**
|
||||
* WebhookDeliveryListResponse
|
||||
*
|
||||
* Response model for listing webhook deliveries.
|
||||
*/
|
||||
export type WebhookDeliveryListResponse = {
|
||||
/**
|
||||
* Items
|
||||
*/
|
||||
items: Array<WebhookDeliveryResponse>;
|
||||
/**
|
||||
* Next Cursor
|
||||
*/
|
||||
next_cursor?: string | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* WebhookDeliveryResponse
|
||||
*
|
||||
* Response model for a webhook delivery record.
|
||||
*/
|
||||
export type WebhookDeliveryResponse = {
|
||||
/**
|
||||
* Id
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* Webhook Id
|
||||
*/
|
||||
webhook_id: string | null;
|
||||
/**
|
||||
* Url
|
||||
*/
|
||||
url: string;
|
||||
/**
|
||||
* Event Type
|
||||
*/
|
||||
event_type: string;
|
||||
/**
|
||||
* Status
|
||||
*/
|
||||
status: string;
|
||||
/**
|
||||
* Attempts
|
||||
*/
|
||||
attempts: number;
|
||||
/**
|
||||
* Next Retry At
|
||||
*/
|
||||
next_retry_at?: string | null;
|
||||
/**
|
||||
* Last Error
|
||||
*/
|
||||
last_error?: string | null;
|
||||
/**
|
||||
* Last Response Status
|
||||
*/
|
||||
last_response_status?: number | null;
|
||||
/**
|
||||
* Last Response Body
|
||||
*/
|
||||
last_response_body?: string | null;
|
||||
/**
|
||||
* Last Attempt At
|
||||
*/
|
||||
last_attempt_at?: string | null;
|
||||
/**
|
||||
* Created At
|
||||
*/
|
||||
created_at?: string | null;
|
||||
/**
|
||||
* Updated At
|
||||
*/
|
||||
updated_at?: string | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* WebhookHttpConfig
|
||||
*
|
||||
* HTTP delivery configuration for a webhook.
|
||||
*/
|
||||
export type WebhookHttpConfig = {
|
||||
/**
|
||||
* Method
|
||||
*
|
||||
* HTTP method: GET or POST
|
||||
*/
|
||||
method?: string;
|
||||
/**
|
||||
* Timeout Seconds
|
||||
*
|
||||
* HTTP request timeout in seconds
|
||||
*/
|
||||
timeout_seconds?: number;
|
||||
/**
|
||||
* Headers
|
||||
*
|
||||
* Custom HTTP headers
|
||||
*/
|
||||
headers?: {
|
||||
[key: string]: string;
|
||||
};
|
||||
/**
|
||||
* Params
|
||||
*
|
||||
* Custom HTTP query parameters
|
||||
*/
|
||||
params?: {
|
||||
[key: string]: string;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* WebhookListResponse
|
||||
*
|
||||
* Response model for listing webhooks.
|
||||
*/
|
||||
export type WebhookListResponse = {
|
||||
/**
|
||||
* Items
|
||||
*/
|
||||
items: Array<WebhookResponse>;
|
||||
};
|
||||
|
||||
/**
|
||||
* WebhookResponse
|
||||
*
|
||||
* Response model for a webhook.
|
||||
*/
|
||||
export type WebhookResponse = {
|
||||
/**
|
||||
* Id
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* Bank Id
|
||||
*/
|
||||
bank_id: string | null;
|
||||
/**
|
||||
* Url
|
||||
*/
|
||||
url: string;
|
||||
/**
|
||||
* Secret
|
||||
*
|
||||
* Signing secret (redacted in responses)
|
||||
*/
|
||||
secret?: string | null;
|
||||
/**
|
||||
* Event Types
|
||||
*/
|
||||
event_types: Array<string>;
|
||||
/**
|
||||
* Enabled
|
||||
*/
|
||||
enabled: boolean;
|
||||
http_config?: WebhookHttpConfig;
|
||||
/**
|
||||
* Created At
|
||||
*/
|
||||
created_at?: string | null;
|
||||
/**
|
||||
* Updated At
|
||||
*/
|
||||
updated_at?: string | null;
|
||||
};
|
||||
|
||||
export type HealthEndpointHealthGetData = {
|
||||
body?: never;
|
||||
path?: never;
|
||||
|
|
@ -3899,6 +4138,217 @@ export type TriggerConsolidationResponses = {
|
|||
export type TriggerConsolidationResponse =
|
||||
TriggerConsolidationResponses[keyof TriggerConsolidationResponses];
|
||||
|
||||
export type ListWebhooksData = {
|
||||
body?: never;
|
||||
headers?: {
|
||||
/**
|
||||
* Authorization
|
||||
*/
|
||||
authorization?: string | null;
|
||||
};
|
||||
path: {
|
||||
/**
|
||||
* Bank Id
|
||||
*/
|
||||
bank_id: string;
|
||||
};
|
||||
query?: never;
|
||||
url: "/v1/default/banks/{bank_id}/webhooks";
|
||||
};
|
||||
|
||||
export type ListWebhooksErrors = {
|
||||
/**
|
||||
* Validation Error
|
||||
*/
|
||||
422: HttpValidationError;
|
||||
};
|
||||
|
||||
export type ListWebhooksError = ListWebhooksErrors[keyof ListWebhooksErrors];
|
||||
|
||||
export type ListWebhooksResponses = {
|
||||
/**
|
||||
* Successful Response
|
||||
*/
|
||||
200: WebhookListResponse;
|
||||
};
|
||||
|
||||
export type ListWebhooksResponse =
|
||||
ListWebhooksResponses[keyof ListWebhooksResponses];
|
||||
|
||||
export type CreateWebhookData = {
|
||||
body: CreateWebhookRequest;
|
||||
headers?: {
|
||||
/**
|
||||
* Authorization
|
||||
*/
|
||||
authorization?: string | null;
|
||||
};
|
||||
path: {
|
||||
/**
|
||||
* Bank Id
|
||||
*/
|
||||
bank_id: string;
|
||||
};
|
||||
query?: never;
|
||||
url: "/v1/default/banks/{bank_id}/webhooks";
|
||||
};
|
||||
|
||||
export type CreateWebhookErrors = {
|
||||
/**
|
||||
* Validation Error
|
||||
*/
|
||||
422: HttpValidationError;
|
||||
};
|
||||
|
||||
export type CreateWebhookError = CreateWebhookErrors[keyof CreateWebhookErrors];
|
||||
|
||||
export type CreateWebhookResponses = {
|
||||
/**
|
||||
* Successful Response
|
||||
*/
|
||||
201: WebhookResponse;
|
||||
};
|
||||
|
||||
export type CreateWebhookResponse =
|
||||
CreateWebhookResponses[keyof CreateWebhookResponses];
|
||||
|
||||
export type DeleteWebhookData = {
|
||||
body?: never;
|
||||
headers?: {
|
||||
/**
|
||||
* Authorization
|
||||
*/
|
||||
authorization?: string | null;
|
||||
};
|
||||
path: {
|
||||
/**
|
||||
* Bank Id
|
||||
*/
|
||||
bank_id: string;
|
||||
/**
|
||||
* Webhook Id
|
||||
*/
|
||||
webhook_id: string;
|
||||
};
|
||||
query?: never;
|
||||
url: "/v1/default/banks/{bank_id}/webhooks/{webhook_id}";
|
||||
};
|
||||
|
||||
export type DeleteWebhookErrors = {
|
||||
/**
|
||||
* Validation Error
|
||||
*/
|
||||
422: HttpValidationError;
|
||||
};
|
||||
|
||||
export type DeleteWebhookError = DeleteWebhookErrors[keyof DeleteWebhookErrors];
|
||||
|
||||
export type DeleteWebhookResponses = {
|
||||
/**
|
||||
* Successful Response
|
||||
*/
|
||||
200: DeleteResponse;
|
||||
};
|
||||
|
||||
export type DeleteWebhookResponse =
|
||||
DeleteWebhookResponses[keyof DeleteWebhookResponses];
|
||||
|
||||
export type UpdateWebhookData = {
|
||||
body: UpdateWebhookRequest;
|
||||
headers?: {
|
||||
/**
|
||||
* Authorization
|
||||
*/
|
||||
authorization?: string | null;
|
||||
};
|
||||
path: {
|
||||
/**
|
||||
* Bank Id
|
||||
*/
|
||||
bank_id: string;
|
||||
/**
|
||||
* Webhook Id
|
||||
*/
|
||||
webhook_id: string;
|
||||
};
|
||||
query?: never;
|
||||
url: "/v1/default/banks/{bank_id}/webhooks/{webhook_id}";
|
||||
};
|
||||
|
||||
export type UpdateWebhookErrors = {
|
||||
/**
|
||||
* Validation Error
|
||||
*/
|
||||
422: HttpValidationError;
|
||||
};
|
||||
|
||||
export type UpdateWebhookError = UpdateWebhookErrors[keyof UpdateWebhookErrors];
|
||||
|
||||
export type UpdateWebhookResponses = {
|
||||
/**
|
||||
* Successful Response
|
||||
*/
|
||||
200: WebhookResponse;
|
||||
};
|
||||
|
||||
export type UpdateWebhookResponse =
|
||||
UpdateWebhookResponses[keyof UpdateWebhookResponses];
|
||||
|
||||
export type ListWebhookDeliveriesData = {
|
||||
body?: never;
|
||||
headers?: {
|
||||
/**
|
||||
* Authorization
|
||||
*/
|
||||
authorization?: string | null;
|
||||
};
|
||||
path: {
|
||||
/**
|
||||
* Bank Id
|
||||
*/
|
||||
bank_id: string;
|
||||
/**
|
||||
* Webhook Id
|
||||
*/
|
||||
webhook_id: string;
|
||||
};
|
||||
query?: {
|
||||
/**
|
||||
* Limit
|
||||
*
|
||||
* Maximum number of deliveries to return
|
||||
*/
|
||||
limit?: number;
|
||||
/**
|
||||
* Cursor
|
||||
*
|
||||
* Pagination cursor (created_at of last item)
|
||||
*/
|
||||
cursor?: string | null;
|
||||
};
|
||||
url: "/v1/default/banks/{bank_id}/webhooks/{webhook_id}/deliveries";
|
||||
};
|
||||
|
||||
export type ListWebhookDeliveriesErrors = {
|
||||
/**
|
||||
* Validation Error
|
||||
*/
|
||||
422: HttpValidationError;
|
||||
};
|
||||
|
||||
export type ListWebhookDeliveriesError =
|
||||
ListWebhookDeliveriesErrors[keyof ListWebhookDeliveriesErrors];
|
||||
|
||||
export type ListWebhookDeliveriesResponses = {
|
||||
/**
|
||||
* Successful Response
|
||||
*/
|
||||
200: WebhookDeliveryListResponse;
|
||||
};
|
||||
|
||||
export type ListWebhookDeliveriesResponse =
|
||||
ListWebhookDeliveriesResponses[keyof ListWebhookDeliveriesResponses];
|
||||
|
||||
export type ClearBankMemoriesData = {
|
||||
body?: never;
|
||||
headers?: {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
import { NextResponse } from "next/server";
|
||||
import { DATAPLANE_URL, getDataplaneHeaders } from "@/lib/hindsight-client";
|
||||
|
||||
export async function GET(
|
||||
request: Request,
|
||||
{ params }: { params: Promise<{ bankId: string; webhookId: string }> }
|
||||
) {
|
||||
const { bankId, webhookId } = await params;
|
||||
const { searchParams } = new URL(request.url);
|
||||
const limit = searchParams.get("limit") || "50";
|
||||
const cursor = searchParams.get("cursor");
|
||||
const qs = new URLSearchParams({ limit });
|
||||
if (cursor) qs.set("cursor", cursor);
|
||||
const res = await fetch(
|
||||
`${DATAPLANE_URL}/v1/default/banks/${bankId}/webhooks/${webhookId}/deliveries?${qs}`,
|
||||
{
|
||||
headers: getDataplaneHeaders({ "Content-Type": "application/json" }),
|
||||
}
|
||||
);
|
||||
const data = await res.json();
|
||||
if (!res.ok) return NextResponse.json({ error: data.detail || "Failed" }, { status: res.status });
|
||||
return NextResponse.json(data);
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
import { NextResponse } from "next/server";
|
||||
import { DATAPLANE_URL, getDataplaneHeaders } from "@/lib/hindsight-client";
|
||||
|
||||
export async function PATCH(
|
||||
request: Request,
|
||||
{ params }: { params: Promise<{ bankId: string; webhookId: string }> }
|
||||
) {
|
||||
const { bankId, webhookId } = await params;
|
||||
const body = await request.json();
|
||||
const res = await fetch(`${DATAPLANE_URL}/v1/default/banks/${bankId}/webhooks/${webhookId}`, {
|
||||
method: "PATCH",
|
||||
headers: getDataplaneHeaders({ "Content-Type": "application/json" }),
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
const data = await res.json();
|
||||
if (!res.ok) return NextResponse.json({ error: data.detail || "Failed" }, { status: res.status });
|
||||
return NextResponse.json(data);
|
||||
}
|
||||
|
||||
export async function DELETE(
|
||||
request: Request,
|
||||
{ params }: { params: Promise<{ bankId: string; webhookId: string }> }
|
||||
) {
|
||||
const { bankId, webhookId } = await params;
|
||||
const res = await fetch(`${DATAPLANE_URL}/v1/default/banks/${bankId}/webhooks/${webhookId}`, {
|
||||
method: "DELETE",
|
||||
headers: getDataplaneHeaders({ "Content-Type": "application/json" }),
|
||||
});
|
||||
const data = await res.json();
|
||||
if (!res.ok) return NextResponse.json({ error: data.detail || "Failed" }, { status: res.status });
|
||||
return NextResponse.json(data);
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import { NextResponse } from "next/server";
|
||||
import { DATAPLANE_URL, getDataplaneHeaders } from "@/lib/hindsight-client";
|
||||
|
||||
export async function GET(request: Request, { params }: { params: Promise<{ bankId: string }> }) {
|
||||
const { bankId } = await params;
|
||||
const res = await fetch(`${DATAPLANE_URL}/v1/default/banks/${bankId}/webhooks`, {
|
||||
headers: getDataplaneHeaders({ "Content-Type": "application/json" }),
|
||||
});
|
||||
const data = await res.json();
|
||||
if (!res.ok) return NextResponse.json({ error: data.detail || "Failed" }, { status: res.status });
|
||||
return NextResponse.json(data);
|
||||
}
|
||||
|
||||
export async function POST(request: Request, { params }: { params: Promise<{ bankId: string }> }) {
|
||||
const { bankId } = await params;
|
||||
const body = await request.json();
|
||||
const res = await fetch(`${DATAPLANE_URL}/v1/default/banks/${bankId}/webhooks`, {
|
||||
method: "POST",
|
||||
headers: getDataplaneHeaders({ "Content-Type": "application/json" }),
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
const data = await res.json();
|
||||
if (!res.ok) return NextResponse.json({ error: data.detail || "Failed" }, { status: res.status });
|
||||
return NextResponse.json(data, { status: 201 });
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@ import { BankConfigView } from "@/components/bank-config-view";
|
|||
import { BankStatsView } from "@/components/bank-stats-view";
|
||||
import { BankOperationsView } from "@/components/bank-operations-view";
|
||||
import { MentalModelsView } from "@/components/mental-models-view";
|
||||
import { WebhooksView } from "@/components/webhooks-view";
|
||||
import { useFeatures } from "@/lib/features-context";
|
||||
import { useBank } from "@/lib/bank-context";
|
||||
import { client } from "@/lib/api";
|
||||
|
|
@ -40,7 +41,7 @@ import { Brain, Trash2, Loader2, MoreVertical, Pencil, RotateCcw } from "lucide-
|
|||
|
||||
type NavItem = "recall" | "reflect" | "data" | "documents" | "entities" | "profile";
|
||||
type DataSubTab = "world" | "experience" | "observations" | "mental-models";
|
||||
type BankConfigTab = "general" | "configuration";
|
||||
type BankConfigTab = "general" | "configuration" | "webhooks";
|
||||
|
||||
export default function BankPage() {
|
||||
const params = useParams();
|
||||
|
|
@ -250,6 +251,19 @@ export default function BankPage() {
|
|||
)}
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={() => handleBankConfigTabChange("webhooks")}
|
||||
className={`px-6 py-3 font-semibold text-sm transition-all relative ${
|
||||
bankConfigTab === "webhooks"
|
||||
? "text-primary"
|
||||
: "text-muted-foreground hover:text-foreground"
|
||||
}`}
|
||||
>
|
||||
Webhooks
|
||||
{bankConfigTab === "webhooks" && (
|
||||
<div className="absolute bottom-0 left-0 right-0 h-0.5 bg-primary" />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -272,6 +286,15 @@ export default function BankPage() {
|
|||
<BankConfigView />
|
||||
</div>
|
||||
)}
|
||||
{bankConfigTab === "webhooks" && (
|
||||
<div>
|
||||
<p className="text-sm text-muted-foreground mb-4">
|
||||
Manage webhook endpoints to receive event notifications from this memory
|
||||
bank.
|
||||
</p>
|
||||
<WebhooksView />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import {
|
|||
Users,
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
Box,
|
||||
Settings,
|
||||
} from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
|
|
|||
1110
hindsight-control-plane/src/components/webhooks-view.tsx
Normal file
1110
hindsight-control-plane/src/components/webhooks-view.tsx
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -5,6 +5,40 @@
|
|||
|
||||
import { toast } from "sonner";
|
||||
|
||||
export interface WebhookHttpConfig {
|
||||
method: string;
|
||||
timeout_seconds: number;
|
||||
headers: Record<string, string>;
|
||||
params: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface Webhook {
|
||||
id: string;
|
||||
bank_id: string | null;
|
||||
url: string;
|
||||
event_types: string[];
|
||||
enabled: boolean;
|
||||
http_config: WebhookHttpConfig;
|
||||
created_at: string | null;
|
||||
updated_at: string | null;
|
||||
}
|
||||
|
||||
export interface WebhookDelivery {
|
||||
id: string;
|
||||
webhook_id: string | null;
|
||||
url: string;
|
||||
event_type: string;
|
||||
status: string;
|
||||
attempts: number;
|
||||
next_retry_at: string | null;
|
||||
last_error: string | null;
|
||||
last_response_status: number | null;
|
||||
last_response_body: string | null;
|
||||
last_attempt_at: string | null;
|
||||
created_at: string | null;
|
||||
updated_at: string | null;
|
||||
}
|
||||
|
||||
export interface MentalModel {
|
||||
id: string;
|
||||
bank_id: string;
|
||||
|
|
@ -858,6 +892,79 @@ export class ControlPlaneClient {
|
|||
method: "DELETE",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* List webhooks for a bank
|
||||
*/
|
||||
async listWebhooks(bankId: string): Promise<{ items: Webhook[] }> {
|
||||
return this.fetchApi<{ items: Webhook[] }>(`/api/banks/${bankId}/webhooks`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a webhook
|
||||
*/
|
||||
async createWebhook(
|
||||
bankId: string,
|
||||
params: {
|
||||
url: string;
|
||||
secret?: string;
|
||||
event_types?: string[];
|
||||
enabled?: boolean;
|
||||
http_config?: WebhookHttpConfig;
|
||||
}
|
||||
): Promise<Webhook> {
|
||||
return this.fetchApi<Webhook>(`/api/banks/${bankId}/webhooks`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify(params),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a webhook (PATCH — only provided fields are changed)
|
||||
*/
|
||||
async updateWebhook(
|
||||
bankId: string,
|
||||
webhookId: string,
|
||||
params: {
|
||||
url?: string;
|
||||
secret?: string | null;
|
||||
event_types?: string[];
|
||||
enabled?: boolean;
|
||||
http_config?: WebhookHttpConfig;
|
||||
}
|
||||
): Promise<Webhook> {
|
||||
return this.fetchApi<Webhook>(`/api/banks/${bankId}/webhooks/${webhookId}`, {
|
||||
method: "PATCH",
|
||||
body: JSON.stringify(params),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a webhook
|
||||
*/
|
||||
async deleteWebhook(bankId: string, webhookId: string): Promise<{ success: boolean }> {
|
||||
return this.fetchApi<{ success: boolean }>(`/api/banks/${bankId}/webhooks/${webhookId}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* List webhook deliveries
|
||||
*/
|
||||
async listWebhookDeliveries(
|
||||
bankId: string,
|
||||
webhookId: string,
|
||||
limit?: number,
|
||||
cursor?: string
|
||||
): Promise<{ items: WebhookDelivery[]; next_cursor: string | null }> {
|
||||
const params = new URLSearchParams();
|
||||
if (limit) params.append("limit", limit.toString());
|
||||
if (cursor) params.append("cursor", cursor);
|
||||
const query = params.toString();
|
||||
return this.fetchApi<{ items: WebhookDelivery[]; next_cursor: string | null }>(
|
||||
`/api/banks/${bankId}/webhooks/${webhookId}/deliveries${query ? `?${query}` : ""}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Export singleton instance
|
||||
|
|
|
|||
|
|
@ -654,7 +654,6 @@ async def cmd_generate(bank_id: str, scale: str, workers: int = 16) -> None:
|
|||
poll_interval_ms=200,
|
||||
max_slots=workers,
|
||||
consolidation_max_slots=0,
|
||||
max_retries=20,
|
||||
)
|
||||
poller_task = asyncio.create_task(poller.run())
|
||||
console.print(" Worker : started\n")
|
||||
|
|
|
|||
96
hindsight-docs/docs/developer/api/webhooks.mdx
Normal file
96
hindsight-docs/docs/developer/api/webhooks.mdx
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
---
|
||||
sidebar_position: 10
|
||||
---
|
||||
|
||||
# Webhooks
|
||||
|
||||
Hindsight can notify your application in real-time when memory events occur by sending HTTP POST requests to a URL you configure.
|
||||
|
||||
## Delivery and Retries
|
||||
|
||||
Webhooks are registered per memory bank and fire automatically when matching events occur. Each delivery attempt is tracked, and failed deliveries are retried with exponential backoff:
|
||||
|
||||
| Attempt | Delay after failure |
|
||||
|---------|---------------------|
|
||||
| 1 | 5 seconds |
|
||||
| 2 | 5 minutes |
|
||||
| 3 | 30 minutes |
|
||||
| 4 | 2 hours |
|
||||
| 5 | 5 hours |
|
||||
| 6 | Permanent failure |
|
||||
|
||||
A delivery is considered failed if your endpoint returns a non-2xx status code or does not respond within the configured timeout (default 30 seconds). After 6 failed attempts, the delivery is marked as permanently failed and no further retries are made.
|
||||
|
||||
:::info At-least-once delivery
|
||||
Webhook delivery tasks are queued in the same database transaction as the primary operation (e.g. the retain or consolidation write). This means if the server crashes after committing but before sending, the delivery task survives and will be retried. As a result, **your endpoint may receive the same event more than once** — use the `operation_id` field to deduplicate if needed.
|
||||
:::
|
||||
|
||||
## Event Types
|
||||
|
||||
### `consolidation.completed`
|
||||
|
||||
Fired after Hindsight finishes consolidating new memories into observations for a bank.
|
||||
|
||||
**Payload:**
|
||||
|
||||
```json
|
||||
{
|
||||
"event": "consolidation.completed",
|
||||
"bank_id": "my-bank",
|
||||
"operation_id": "a1b2c3d4e5f6",
|
||||
"status": "completed",
|
||||
"timestamp": "2026-03-04T12:00:00Z",
|
||||
"data": {
|
||||
"observations_created": 3,
|
||||
"observations_updated": 1,
|
||||
"observations_deleted": null,
|
||||
"error_message": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**`data` fields:**
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `observations_created` | `integer \| null` | Number of new observations created |
|
||||
| `observations_updated` | `integer \| null` | Number of existing observations updated |
|
||||
| `observations_deleted` | `integer \| null` | Number of observations deleted |
|
||||
| `error_message` | `string \| null` | Set when `status` is `"failed"` |
|
||||
|
||||
**`status` values:** `"completed"` or `"failed"`
|
||||
|
||||
---
|
||||
|
||||
### `retain.completed`
|
||||
|
||||
Fired once per document after a retain operation completes (both synchronous and asynchronous). When retaining a batch of N documents, N separate events are fired.
|
||||
|
||||
**Payload:**
|
||||
|
||||
```json
|
||||
{
|
||||
"event": "retain.completed",
|
||||
"bank_id": "my-bank",
|
||||
"operation_id": "a1b2c3d4e5f6",
|
||||
"status": "completed",
|
||||
"timestamp": "2026-03-04T12:00:01Z",
|
||||
"data": {
|
||||
"document_id": "doc-abc123",
|
||||
"tags": ["meeting", "q1-2026"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**`data` fields:**
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `document_id` | `string \| null` | The document ID if one was provided in the retain request |
|
||||
| `tags` | `string[] \| null` | Document-level tags applied during retain |
|
||||
|
||||
**Notes:**
|
||||
- For async retain (`async: true`), `operation_id` matches the `operation_id` returned by the retain API.
|
||||
- For sync retain, `operation_id` is a generated identifier for tracing purposes.
|
||||
- One event is fired per content item in the retain request.
|
||||
|
||||
|
|
@ -99,6 +99,11 @@ const sidebars: SidebarsConfig = {
|
|||
id: 'developer/api/operations',
|
||||
label: 'Operations',
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'developer/api/webhooks',
|
||||
label: 'Webhooks',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3141,6 +3141,375 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/v1/default/banks/{bank_id}/webhooks": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Webhooks"
|
||||
],
|
||||
"summary": "Register webhook",
|
||||
"description": "Register a webhook endpoint to receive event notifications for this bank.",
|
||||
"operationId": "create_webhook",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "bank_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"title": "Bank Id"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "authorization",
|
||||
"in": "header",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Authorization"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/CreateWebhookRequest"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/WebhookResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"get": {
|
||||
"tags": [
|
||||
"Webhooks"
|
||||
],
|
||||
"summary": "List webhooks",
|
||||
"description": "List all webhooks registered for a bank.",
|
||||
"operationId": "list_webhooks",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "bank_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"title": "Bank Id"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "authorization",
|
||||
"in": "header",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Authorization"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/WebhookListResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/default/banks/{bank_id}/webhooks/{webhook_id}": {
|
||||
"delete": {
|
||||
"tags": [
|
||||
"Webhooks"
|
||||
],
|
||||
"summary": "Delete webhook",
|
||||
"description": "Remove a registered webhook.",
|
||||
"operationId": "delete_webhook",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "bank_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"title": "Bank Id"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "webhook_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"title": "Webhook Id"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "authorization",
|
||||
"in": "header",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Authorization"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/DeleteResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"patch": {
|
||||
"tags": [
|
||||
"Webhooks"
|
||||
],
|
||||
"summary": "Update webhook",
|
||||
"description": "Update one or more fields of a registered webhook. Only provided fields are changed.",
|
||||
"operationId": "update_webhook",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "bank_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"title": "Bank Id"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "webhook_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"title": "Webhook Id"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "authorization",
|
||||
"in": "header",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Authorization"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UpdateWebhookRequest"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/WebhookResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/default/banks/{bank_id}/webhooks/{webhook_id}/deliveries": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Webhooks"
|
||||
],
|
||||
"summary": "List webhook deliveries",
|
||||
"description": "Inspect delivery history for a webhook (useful for debugging).",
|
||||
"operationId": "list_webhook_deliveries",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "bank_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"title": "Bank Id"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "webhook_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"title": "Webhook Id"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "limit",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"maximum": 200,
|
||||
"description": "Maximum number of deliveries to return",
|
||||
"default": 50,
|
||||
"title": "Limit"
|
||||
},
|
||||
"description": "Maximum number of deliveries to return"
|
||||
},
|
||||
{
|
||||
"name": "cursor",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Pagination cursor (created_at of last item)",
|
||||
"title": "Cursor"
|
||||
},
|
||||
"description": "Pagination cursor (created_at of last item)"
|
||||
},
|
||||
{
|
||||
"name": "authorization",
|
||||
"in": "header",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Authorization"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/WebhookDeliveryListResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/default/banks/{bank_id}/memories": {
|
||||
"post": {
|
||||
"tags": [
|
||||
|
|
@ -4348,6 +4717,54 @@
|
|||
"title": "CreateMentalModelResponse",
|
||||
"description": "Response model for mental model creation."
|
||||
},
|
||||
"CreateWebhookRequest": {
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string",
|
||||
"title": "Url",
|
||||
"description": "HTTP(S) endpoint URL to deliver events to"
|
||||
},
|
||||
"secret": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Secret",
|
||||
"description": "HMAC-SHA256 signing secret (optional)"
|
||||
},
|
||||
"event_types": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"title": "Event Types",
|
||||
"description": "List of event types to deliver. Currently supported: 'consolidation.completed'",
|
||||
"default": [
|
||||
"consolidation.completed"
|
||||
]
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"title": "Enabled",
|
||||
"description": "Whether this webhook is active",
|
||||
"default": true
|
||||
},
|
||||
"http_config": {
|
||||
"$ref": "#/components/schemas/WebhookHttpConfig",
|
||||
"description": "HTTP delivery configuration (method, timeout, headers, params)"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"url"
|
||||
],
|
||||
"title": "CreateWebhookRequest",
|
||||
"description": "Request model for registering a webhook."
|
||||
},
|
||||
"DeleteDocumentResponse": {
|
||||
"properties": {
|
||||
"success": {
|
||||
|
|
@ -7031,6 +7448,75 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"UpdateWebhookRequest": {
|
||||
"properties": {
|
||||
"url": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Url",
|
||||
"description": "HTTP(S) endpoint URL"
|
||||
},
|
||||
"secret": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Secret",
|
||||
"description": "HMAC-SHA256 signing secret. Omit to keep existing; send null to clear."
|
||||
},
|
||||
"event_types": {
|
||||
"anyOf": [
|
||||
{
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Event Types",
|
||||
"description": "List of event types"
|
||||
},
|
||||
"enabled": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Enabled",
|
||||
"description": "Whether this webhook is active"
|
||||
},
|
||||
"http_config": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/WebhookHttpConfig"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "HTTP delivery configuration"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"title": "UpdateWebhookRequest",
|
||||
"description": "Request model for updating a webhook. Only provided fields are updated."
|
||||
},
|
||||
"ValidationError": {
|
||||
"properties": {
|
||||
"loc": {
|
||||
|
|
@ -7093,6 +7579,290 @@
|
|||
"worker": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"WebhookDeliveryListResponse": {
|
||||
"properties": {
|
||||
"items": {
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/WebhookDeliveryResponse"
|
||||
},
|
||||
"type": "array",
|
||||
"title": "Items"
|
||||
},
|
||||
"next_cursor": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Next Cursor"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"items"
|
||||
],
|
||||
"title": "WebhookDeliveryListResponse",
|
||||
"description": "Response model for listing webhook deliveries."
|
||||
},
|
||||
"WebhookDeliveryResponse": {
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"title": "Id"
|
||||
},
|
||||
"webhook_id": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Webhook Id"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"title": "Url"
|
||||
},
|
||||
"event_type": {
|
||||
"type": "string",
|
||||
"title": "Event Type"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"title": "Status"
|
||||
},
|
||||
"attempts": {
|
||||
"type": "integer",
|
||||
"title": "Attempts"
|
||||
},
|
||||
"next_retry_at": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Next Retry At"
|
||||
},
|
||||
"last_error": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Last Error"
|
||||
},
|
||||
"last_response_status": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Last Response Status"
|
||||
},
|
||||
"last_response_body": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Last Response Body"
|
||||
},
|
||||
"last_attempt_at": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Last Attempt At"
|
||||
},
|
||||
"created_at": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Created At"
|
||||
},
|
||||
"updated_at": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Updated At"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"webhook_id",
|
||||
"url",
|
||||
"event_type",
|
||||
"status",
|
||||
"attempts"
|
||||
],
|
||||
"title": "WebhookDeliveryResponse",
|
||||
"description": "Response model for a webhook delivery record."
|
||||
},
|
||||
"WebhookHttpConfig": {
|
||||
"properties": {
|
||||
"method": {
|
||||
"type": "string",
|
||||
"title": "Method",
|
||||
"description": "HTTP method: GET or POST",
|
||||
"default": "POST"
|
||||
},
|
||||
"timeout_seconds": {
|
||||
"type": "integer",
|
||||
"title": "Timeout Seconds",
|
||||
"description": "HTTP request timeout in seconds",
|
||||
"default": 30
|
||||
},
|
||||
"headers": {
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "object",
|
||||
"title": "Headers",
|
||||
"description": "Custom HTTP headers"
|
||||
},
|
||||
"params": {
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "object",
|
||||
"title": "Params",
|
||||
"description": "Custom HTTP query parameters"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"title": "WebhookHttpConfig",
|
||||
"description": "HTTP delivery configuration for a webhook."
|
||||
},
|
||||
"WebhookListResponse": {
|
||||
"properties": {
|
||||
"items": {
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/WebhookResponse"
|
||||
},
|
||||
"type": "array",
|
||||
"title": "Items"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"items"
|
||||
],
|
||||
"title": "WebhookListResponse",
|
||||
"description": "Response model for listing webhooks."
|
||||
},
|
||||
"WebhookResponse": {
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"title": "Id"
|
||||
},
|
||||
"bank_id": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Bank Id"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"title": "Url"
|
||||
},
|
||||
"secret": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Secret",
|
||||
"description": "Signing secret (redacted in responses)"
|
||||
},
|
||||
"event_types": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array",
|
||||
"title": "Event Types"
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"title": "Enabled"
|
||||
},
|
||||
"http_config": {
|
||||
"$ref": "#/components/schemas/WebhookHttpConfig"
|
||||
},
|
||||
"created_at": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Created At"
|
||||
},
|
||||
"updated_at": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"title": "Updated At"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"bank_id",
|
||||
"url",
|
||||
"event_types",
|
||||
"enabled"
|
||||
],
|
||||
"title": "WebhookResponse",
|
||||
"description": "Response model for a webhook."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue