MCPcopy Index your code
hub / github.com/simstudioai/sim / promoteFork

Function promoteFork

apps/sim/lib/workspaces/fork/promote/promote.ts:334–902  ·  view source on GitHub ↗
(params: PromoteForkParams)

Source from the content-addressed store, hash-verified

332 * without mutating only when required references are unmapped.
333 */
334export async function promoteFork(params: PromoteForkParams): Promise<PromoteForkResult> {
335 const { edge, sourceWorkspaceId, targetWorkspaceId, direction, userId } = params
336 const requestId = params.requestId ?? 'unknown'
337
338 // Distinguish an OMITTED dependent mapping (leave the store as-is) from an explicit empty
339 // array (clear it). When values are PROVIDED the apply map is plan-independent, so build it
340 // here - BEFORE the transaction - to keep the advisory lock tight (pure in-memory, no DB),
341 // mirroring how the source states are pre-loaded above. The OMITTED path needs the plan's
342 // replace targets, so it loads + builds inside the tx below.
343 const dependentValuesProvided = params.dependentValues !== undefined
344 const providedOverridesByWorkflow = dependentValuesProvided
345 ? groupDependentOverrides(
346 (params.dependentValues ?? []).map((entry) => ({
347 targetWorkflowId: entry.workflowId,
348 targetBlockId: entry.blockId,
349 subBlockKey: entry.subBlockKey,
350 value: entry.value,
351 }))
352 )
353 : null
354
355 const targetMembers = (await getUsersWithPermissions(targetWorkspaceId)).map((m) => m.userId)
356
357 // Read the source's deployed workflows + states BEFORE the transaction so these
358 // heavy per-workflow reads never check out a second pooled connection from inside
359 // the promote tx (which can deadlock the pool at saturation). The source is
360 // read-only here, so this pre-tx snapshot is exactly what gets force-pushed.
361 const { deployedWorkflows, sourceStates } = await loadSourceDeployedStates(sourceWorkspaceId)
362
363 const txResult: PromoteTxBlocked | PromoteTxApplied = await db.transaction(async (tx) => {
364 // Bound lock waits so a contended sync into this target fails fast instead of
365 // stagnating the pool. Must run before acquiring the advisory locks below.
366 await setForkLockTimeout(tx)
367 // Target lock before edge lock (consistent ordering): the target lock serializes
368 // every sync into this target so sibling forks can't interleave writes, and so
369 // rollback's "newest sync" check stays race-free against a concurrent promote.
370 await acquireForkTargetLock(tx, targetWorkspaceId)
371 await acquireForkEdgeLock(tx, edge.childWorkspaceId)
372
373 const plan = await computeForkPromotePlan({
374 executor: tx,
375 edge,
376 sourceWorkspaceId,
377 targetWorkspaceId,
378 direction,
379 deployedSourceWorkflows: deployedWorkflows,
380 sourceStates,
381 })
382
383 const now = new Date()
384
385 // Copy the selected referenced-but-unmapped resources into the target BEFORE the gate, so a
386 // user can copy rather than map each one. The gate is evaluated against the post-copy state
387 // (the copy resolves the selected refs), so the copy only runs when the sync will actually
388 // proceed - if required refs remain unmapped, we block without copying anything.
389 const { selection: copySelection, willResolve } = buildPromoteCopySelection(
390 params.copyResources,
391 plan.copyableUnmapped

Callers 1

route.tsFile · 0.90

Calls 15

getUsersWithPermissionsFunction · 0.90
loadSourceDeployedStatesFunction · 0.90
setForkLockTimeoutFunction · 0.90
acquireForkTargetLockFunction · 0.90
acquireForkEdgeLockFunction · 0.90
computeForkPromotePlanFunction · 0.90
resolveForkFolderMappingFunction · 0.90
hasPromoteCopySelectionFunction · 0.90
augmentForkResolverFunction · 0.90

Tested by

no test coverage detected