-- name: LockPluginPackageKey :exec -- Serializes publish, install and delete for one (workspace, plugin key). -- -- Relationships are application-owned by repository policy, so there are no -- foreign keys to make "this version still exists" true across statements. -- Without this lock the interleaving `delete counts 0 installs` → `install -- reads the version` → `delete commits` → `install commits` leaves an -- installation pointing at a version that no longer exists, and its panel 404s -- forever with nothing in the product able to explain why. -- -- Keyed on the plugin key rather than the package id because publish has no -- package id yet — the row it would lock is the one it may be about to create. SELECT pg_advisory_xact_lock(hashtextextended($1::text, 0)); -- name: CreatePluginPackage :one INSERT INTO plugin_package (workspace_id, plugin_key, name, created_by) VALUES ($1, $2, $3, $4) RETURNING *; -- name: UpdatePluginPackageName :one -- The display name follows the newest published version. The key never moves: -- it is the identity an installation was consented under. UPDATE plugin_package SET name = $2, updated_at = now() WHERE id = $1 RETURNING *; -- name: GetWorkspacePluginPackageByKey :one SELECT * FROM plugin_package WHERE workspace_id = $1 AND plugin_key = $2; -- name: GetWorkspacePluginPackage :one SELECT * FROM plugin_package WHERE workspace_id = $1 AND id = $2; -- name: ListWorkspacePluginPackages :many SELECT * FROM plugin_package WHERE workspace_id = $1 ORDER BY name ASC; -- name: DeletePluginPackage :exec DELETE FROM plugin_package WHERE id = $1; -- name: CreatePluginPackageVersion :one -- Published versions are only ever inserted. Nothing updates one, and the -- (package_id, version) unique index is what makes a second publish of the same -- version a conflict instead of a silent overwrite. INSERT INTO plugin_package_version ( package_id, workspace_id, version, manifest, digest, size_bytes, published_by ) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING *; -- name: ListPluginPackageVersions :many SELECT * FROM plugin_package_version WHERE package_id = $1 ORDER BY created_at DESC; -- name: GetWorkspacePluginPackageVersion :one SELECT * FROM plugin_package_version WHERE workspace_id = $1 AND id = $2; -- name: DeletePluginPackageVersionsByPackage :exec DELETE FROM plugin_package_version WHERE package_id = $1; -- name: CountInstallationsOfPackageVersions :one -- Whether any workspace still runs a version of this package. Publishing is -- workspace-private, so this is scoped to the same workspace by construction. SELECT count(*) FROM plugin_installation WHERE package_version_id IN ( SELECT id FROM plugin_package_version WHERE package_id = $1 ); -- name: CreatePluginPackageFile :exec INSERT INTO plugin_package_file (version_id, path, content, size_bytes, sha256) VALUES ($1, $2, $3, $4, $5); -- name: GetPluginPackageFile :one SELECT * FROM plugin_package_file WHERE version_id = $1 AND path = $2; -- name: ListPluginPackageFilePaths :many -- Paths and sizes only: the publisher's file list never needs the bytes. SELECT path, size_bytes, sha256 FROM plugin_package_file WHERE version_id = $1 ORDER BY path ASC; -- name: DeletePluginPackageFilesByPackage :exec DELETE FROM plugin_package_file WHERE version_id IN (SELECT id FROM plugin_package_version WHERE package_id = $1); -- name: CreatePluginInstallation :one INSERT INTO plugin_installation ( workspace_id, plugin_key, package_version_id, version, manifest, granted_scopes, installed_by ) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING *; -- name: UpdatePluginInstallationManifest :one -- Upgrade path: the installation is re-pointed at another published version and -- takes that version's consented manifest snapshot. Config values survive on -- purpose; fields the new manifest dropped are pruned by the service before this -- runs. UPDATE plugin_installation SET package_version_id = $2, version = $3, manifest = $4, granted_scopes = $5, config = $6, updated_at = now() WHERE id = $1 RETURNING *; -- name: UpdatePluginInstallationConfig :one UPDATE plugin_installation SET config = $2, updated_at = now() WHERE id = $1 RETURNING *; -- name: SetPluginInstallationEnabled :one UPDATE plugin_installation SET enabled = $2, updated_at = now() WHERE id = $1 RETURNING *; -- name: GetPluginInstallation :one SELECT * FROM plugin_installation WHERE id = $1; -- name: GetWorkspacePluginInstallation :one SELECT * FROM plugin_installation WHERE workspace_id = $1 AND id = $2; -- name: GetWorkspacePluginInstallationByKey :one SELECT * FROM plugin_installation WHERE workspace_id = $1 AND plugin_key = $2; -- name: ListWorkspacePluginInstallations :many SELECT * FROM plugin_installation WHERE workspace_id = $1 ORDER BY created_at ASC; -- name: DeletePluginInstallation :exec DELETE FROM plugin_installation WHERE id = $1; -- name: CreatePluginHookSchedule :one INSERT INTO plugin_hook_schedule ( installation_id, workspace_id, hook_key, cron_expression, timezone, next_run_at, enabled ) VALUES ($1, $2, $3, $4, $5, sqlc.narg(next_run_at), $6) RETURNING *; -- name: GetPluginHookSchedule :one SELECT * FROM plugin_hook_schedule WHERE id = $1; -- name: ListPluginHookSchedulesByInstallation :many SELECT * FROM plugin_hook_schedule WHERE installation_id = $1 ORDER BY hook_key ASC; -- name: ListEnabledPluginHookSchedules :many -- Do not filter by next_run_at: it is display-only, while retries and recovery -- derive eligibility from cron + activated_at + sys_cron_executions. SELECT * FROM plugin_hook_schedule WHERE enabled ORDER BY id ASC; -- name: UpdatePluginHookScheduleDefinition :one -- A cron/timezone change creates a new scheduler generation. The old -- sys_cron_executions rows remain immutable history under the prior scope id. UPDATE plugin_hook_schedule SET cron_expression = $2, timezone = $3, generation = gen_random_uuid(), activated_at = now(), next_run_at = sqlc.narg(next_run_at), enabled = $4, updated_at = now() WHERE id = $1 RETURNING *; -- name: DisablePluginHookSchedules :exec UPDATE plugin_hook_schedule SET enabled = FALSE, next_run_at = NULL, updated_at = now() WHERE installation_id = $1; -- name: ReactivatePluginHookSchedule :one -- Re-enable starts a new epoch so occurrences while the installation was off -- are never caught up. An already-sent request from the old generation may -- finish, but no unstarted old plan survives the generation check. UPDATE plugin_hook_schedule SET enabled = TRUE, generation = gen_random_uuid(), activated_at = now(), next_run_at = sqlc.narg(next_run_at), updated_at = now() WHERE id = $1 RETURNING *; -- name: UpdatePluginHookScheduleNextRun :execrows UPDATE plugin_hook_schedule SET next_run_at = sqlc.narg(next_run_at), updated_at = now() WHERE id = $1 AND generation = $2 AND enabled; -- name: DeletePluginHookSchedule :exec DELETE FROM plugin_hook_schedule WHERE id = $1; -- name: DeletePluginHookSchedulesByInstallation :exec DELETE FROM plugin_hook_schedule WHERE installation_id = $1; -- name: UpsertPluginStorageValue :one INSERT INTO plugin_storage (installation_id, scope_type, scope_id, key, value) VALUES ($1, $2, $3, $4, $5) ON CONFLICT (installation_id, scope_type, scope_id, key) DO UPDATE SET value = EXCLUDED.value, updated_at = now() RETURNING *; -- name: GetPluginStorageValue :one SELECT * FROM plugin_storage WHERE installation_id = $1 AND scope_type = $2 AND scope_id = $3 AND key = $4; -- name: ListPluginStorageKeys :many SELECT key, octet_length(value)::bigint AS size_bytes, updated_at FROM plugin_storage WHERE installation_id = $1 AND scope_type = $2 AND scope_id = $3 ORDER BY key ASC; -- name: DeletePluginStorageValue :execrows DELETE FROM plugin_storage WHERE installation_id = $1 AND scope_type = $2 AND scope_id = $3 AND key = $4; -- name: GetPluginStorageUsage :one -- Quota accounting for one (installation, scope) pair. The candidate key is -- excluded so overwriting an existing key is measured as a replacement rather -- than an addition. octet_length, not char_length: the service compares these -- against byte budgets, and a UTF-8 character is up to 4 bytes. SELECT COUNT(*)::bigint AS key_count, COALESCE(SUM(octet_length(value)), 0)::bigint AS total_bytes FROM plugin_storage WHERE installation_id = $1 AND scope_type = $2 AND scope_id = $3 AND key <> $4; -- name: DeletePluginStorageByInstallation :exec DELETE FROM plugin_storage WHERE installation_id = $1; -- name: UpsertPluginSecret :exec INSERT INTO plugin_secret (installation_id, key, ciphertext) VALUES ($1, $2, $3) ON CONFLICT (installation_id, key) DO UPDATE SET ciphertext = EXCLUDED.ciphertext, updated_at = now(); -- name: ListPluginSecretKeys :many -- Deliberately never selects ciphertext: the presence of a secret is readable, -- its value is not. SELECT key, updated_at FROM plugin_secret WHERE installation_id = $1 ORDER BY key ASC; -- name: GetPluginSecret :one SELECT * FROM plugin_secret WHERE installation_id = $1 AND key = $2; -- name: DeletePluginSecret :execrows DELETE FROM plugin_secret WHERE installation_id = $1 AND key = $2; -- name: DeletePluginSecretsByInstallation :exec DELETE FROM plugin_secret WHERE installation_id = $1; -- name: SetPluginInstallationToken :exec UPDATE plugin_installation SET token_hash = $2, token_rotated_at = now(), updated_at = now() WHERE id = $1; -- name: GetPluginInstallationByTokenHash :one -- Looked up by hash, so the plaintext token exists only in the caller's request. SELECT * FROM plugin_installation WHERE token_hash = $1; -- name: CreatePluginInvocation :one INSERT INTO plugin_invocation ( id, installation_id, workspace_id, hook_key, trigger, status, event_type, delivery_id, planned_at, attempt, latency_ms, error ) VALUES ( COALESCE(sqlc.narg('id')::uuid, gen_random_uuid()), $1, $2, $3, $4, $5, sqlc.narg(event_type), sqlc.narg(delivery_id), sqlc.narg(planned_at), $6, $7, sqlc.narg(error) ) RETURNING *; -- name: ListPluginInvocations :many SELECT * FROM plugin_invocation WHERE installation_id = $1 ORDER BY created_at DESC LIMIT $2; -- name: CountRecentPluginInvocations :one -- Feeds the per-hook rate limit. Counts attempts, not distinct calls: a hook -- retrying into a dead endpoint is exactly the traffic the limit exists to cap. SELECT count(*) FROM plugin_invocation WHERE installation_id = $1 AND hook_key = $2 AND created_at > $3; -- name: CountRecentPluginFailures :one -- Consecutive-failure signal for the event circuit breaker. Bounded by time so -- a breaker that tripped hours ago does not keep a hook shut forever. SELECT count(*) FROM plugin_invocation WHERE installation_id = $1 AND hook_key = $2 AND created_at > $3 AND status <> 'ok'; -- name: DeletePluginInvocationsByInstallation :exec DELETE FROM plugin_invocation WHERE installation_id = $1; -- name: DeleteExpiredPluginInvocations :execrows -- TTL sweep. This table is operational telemetry, not history to keep. DELETE FROM plugin_invocation WHERE created_at < $1; -- name: UpsertPluginSkill :one -- A plugin's skill resource, as an ordinary workspace skill. -- -- Upsert on (workspace_id, name) because that is the table's own uniqueness -- rule and an upgrade re-installs the same skill. The WHERE clause is the -- important half: it refuses to overwrite a skill a PERSON created, or one -- another installation owns. A plugin claiming a name someone already used must -- fail the install loudly, not silently replace their work. INSERT INTO skill (workspace_id, name, description, content, config, created_by, plugin_installation_id) VALUES ($1, $2, $3, $4, '{}'::jsonb, sqlc.narg(created_by), $5) ON CONFLICT (workspace_id, name) DO UPDATE SET description = EXCLUDED.description, content = EXCLUDED.content, updated_at = now() WHERE skill.plugin_installation_id = EXCLUDED.plugin_installation_id RETURNING *; -- name: ListPluginSkills :many SELECT * FROM skill WHERE plugin_installation_id = $1 ORDER BY name ASC; -- name: DeletePluginSkillsByInstallation :exec DELETE FROM skill WHERE plugin_installation_id = $1; -- name: DeletePluginSkillsNotIn :exec -- Upgrade pruning: a skill this installation used to contribute but no longer -- declares must go, or a renamed skill leaves its predecessor behind forever. DELETE FROM skill WHERE plugin_installation_id = $1 AND name <> ALL(@keep_names::text[]); -- name: SetPluginMCPApprovals :one UPDATE plugin_installation SET mcp_approvals = $2, updated_at = now() WHERE id = $1 RETURNING *;