chore: import upstream snapshot with attribution
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
@@ -0,0 +1,158 @@
import { db } from '@sim/db'
import { webhook, workflow, workflowDeploymentVersion } from '@sim/db/schema'
import { and, eq, isNull, or } from 'drizzle-orm'
import {
SIM_EVENT_TYPES,
SIM_RULE_DEFAULTS,
SIM_TRIGGER_PROVIDER,
type SimEventType,
} from '@/lib/workspace-events/constants'
import type { SimSubscription, SimSubscriptionConfig } from '@/lib/workspace-events/types'
/**
* Fetches active Sim-trigger subscriptions for one workspace.
*
* Workspace-scoped on purpose: execution completion is the hottest event in
* the platform, so this must never degrade into a global provider scan. The
* deployment-version join enforces that subscribers are deployed and the
* webhook row belongs to the active deployment version.
*/
export async function fetchSimTriggerSubscriptions(
workspaceId: string
): Promise<SimSubscription[]> {
const rows = await db
.select({ webhook, workflow })
.from(webhook)
.innerJoin(workflow, eq(webhook.workflowId, workflow.id))
.leftJoin(
workflowDeploymentVersion,
and(
eq(workflowDeploymentVersion.workflowId, workflow.id),
eq(workflowDeploymentVersion.isActive, true)
)
)
.where(
and(
eq(webhook.provider, SIM_TRIGGER_PROVIDER),
eq(webhook.isActive, true),
isNull(webhook.archivedAt),
eq(workflow.workspaceId, workspaceId),
eq(workflow.isDeployed, true),
isNull(workflow.archivedAt),
or(
eq(webhook.deploymentVersionId, workflowDeploymentVersion.id),
and(isNull(workflowDeploymentVersion.id), isNull(webhook.deploymentVersionId))
)
)
)
return rows
}
function parseStringArray(value: unknown): string[] {
if (Array.isArray(value)) {
return value.filter((entry): entry is string => typeof entry === 'string' && entry.length > 0)
}
if (typeof value === 'string' && value.length > 0) {
return value
.split(',')
.map((entry) => entry.trim())
.filter(Boolean)
}
return []
}
/**
* Per-field bounds ported from the legacy notifications contract. Rule SQL
* runs on the execution-completion hot path, so windows and counts must stay
* inside the designed envelope regardless of what the free-text subblocks
* contain. Integer fields are rounded — counts feed SQL LIMIT, which rejects
* fractional values. The credit bounds are the legacy dollar bounds
* ($0.01-$1000) at 200 credits per dollar; credits stay fractional like the
* legacy dollar threshold.
*/
const SIM_RULE_BOUNDS = {
consecutiveFailures: { min: 1, max: 100, integer: true },
failureRatePercent: { min: 1, max: 100, integer: true },
windowHours: { min: 1, max: 168, integer: true },
durationThresholdMs: { min: 1000, max: 3_600_000, integer: true },
latencySpikePercent: { min: 10, max: 1000, integer: true },
costThresholdCredits: { min: 2, max: 200_000 },
errorCountThreshold: { min: 1, max: 1000, integer: true },
inactivityHours: { min: 1, max: 168, integer: true },
} as const
function parseBoundedNumber(
value: unknown,
fallback: number,
bounds: { min: number; max: number; integer?: boolean }
): number {
const parsed = typeof value === 'number' ? value : Number(value)
if (!Number.isFinite(parsed) || parsed <= 0) return fallback
const clamped = Math.min(Math.max(parsed, bounds.min), bounds.max)
return bounds.integer ? Math.round(clamped) : clamped
}
/**
* Parses a webhook row's providerConfig into a typed subscription config.
* Returns null when the config has no recognizable event type.
*/
export function parseSubscriptionConfig(providerConfig: unknown): SimSubscriptionConfig | null {
const config =
providerConfig && typeof providerConfig === 'object' && !Array.isArray(providerConfig)
? (providerConfig as Record<string, unknown>)
: {}
const eventType = config.eventType
if (
typeof eventType !== 'string' ||
!(SIM_EVENT_TYPES as readonly string[]).includes(eventType)
) {
return null
}
return {
eventType: eventType as SimEventType,
workflowIds: parseStringArray(config.workflowIds),
consecutiveFailures: parseBoundedNumber(
config.consecutiveFailures,
SIM_RULE_DEFAULTS.consecutiveFailures,
SIM_RULE_BOUNDS.consecutiveFailures
),
failureRatePercent: parseBoundedNumber(
config.failureRatePercent,
SIM_RULE_DEFAULTS.failureRatePercent,
SIM_RULE_BOUNDS.failureRatePercent
),
windowHours: parseBoundedNumber(
config.windowHours,
SIM_RULE_DEFAULTS.windowHours,
SIM_RULE_BOUNDS.windowHours
),
durationThresholdMs: parseBoundedNumber(
config.durationThresholdMs,
SIM_RULE_DEFAULTS.durationThresholdMs,
SIM_RULE_BOUNDS.durationThresholdMs
),
latencySpikePercent: parseBoundedNumber(
config.latencySpikePercent,
SIM_RULE_DEFAULTS.latencySpikePercent,
SIM_RULE_BOUNDS.latencySpikePercent
),
costThresholdCredits: parseBoundedNumber(
config.costThresholdCredits,
SIM_RULE_DEFAULTS.costThresholdCredits,
SIM_RULE_BOUNDS.costThresholdCredits
),
errorCountThreshold: parseBoundedNumber(
config.errorCountThreshold,
SIM_RULE_DEFAULTS.errorCountThreshold,
SIM_RULE_BOUNDS.errorCountThreshold
),
inactivityHours: parseBoundedNumber(
config.inactivityHours,
SIM_RULE_DEFAULTS.inactivityHours,
SIM_RULE_BOUNDS.inactivityHours
),
}
}