@postman-cse/onboarding-repo-sync 2.1.7 → 2.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/action.cjs CHANGED
@@ -126895,7 +126895,85 @@ var BifrostInternalIntegrationAdapter = class {
126895
126895
  throw advised ?? httpErr;
126896
126896
  }
126897
126897
  }
126898
- async connectWorkspaceToRepository(workspaceId, repoUrl) {
126898
+ /**
126899
+ * Probe who (if anyone) already owns the global `(repo, path)` filesystem
126900
+ * link. Non-fatal: unexpected statuses / network errors yield `unknown` so
126901
+ * callers can proceed and rely on reactive POST conflict handling.
126902
+ *
126903
+ * Bifrost states (FileSystemController.fetchWorkspaceForFileSystem):
126904
+ * - 200 + data null -> free
126905
+ * - 200 + data -> linked-visible (workspace payload)
126906
+ * - 403 + error.meta.workspaceId -> linked-invisible
126907
+ * - 200 + error.meta.workspaceId -> linked-invisible (proxy envelope)
126908
+ */
126909
+ async findWorkspaceForRepo(repoUrl, path9 = "/") {
126910
+ const fsPath = path9 && path9.trim() ? path9.trim() : "/";
126911
+ const url = `${this.bifrostBaseUrl}/ws/proxy`;
126912
+ const payload = {
126913
+ service: "workspaces",
126914
+ method: "GET",
126915
+ path: `/workspaces/filesystem?repo=${encodeURIComponent(repoUrl)}&path=${encodeURIComponent(fsPath)}`
126916
+ };
126917
+ try {
126918
+ const response = await this.fetchImpl(url, {
126919
+ method: "POST",
126920
+ headers: this.bifrostHeaders(),
126921
+ body: JSON.stringify(payload)
126922
+ });
126923
+ let parsed = {};
126924
+ try {
126925
+ parsed = await response.json();
126926
+ } catch {
126927
+ return {
126928
+ state: "unknown",
126929
+ reason: `filesystem lookup returned non-JSON body (HTTP ${response.status})`
126930
+ };
126931
+ }
126932
+ const errorMetaWorkspaceId = typeof parsed?.error?.meta?.workspaceId === "string" && parsed.error.meta.workspaceId.trim() ? parsed.error.meta.workspaceId.trim() : void 0;
126933
+ if (errorMetaWorkspaceId) {
126934
+ return { state: "linked-invisible", workspaceId: errorMetaWorkspaceId };
126935
+ }
126936
+ if (response.ok) {
126937
+ if (parsed?.data == null) {
126938
+ return { state: "free" };
126939
+ }
126940
+ const id = typeof parsed.data.id === "string" ? parsed.data.id.trim() : "";
126941
+ if (!id) {
126942
+ return {
126943
+ state: "unknown",
126944
+ reason: "filesystem lookup returned 200 without a workspace id"
126945
+ };
126946
+ }
126947
+ const name = typeof parsed.data.name === "string" && parsed.data.name.trim() ? parsed.data.name.trim() : void 0;
126948
+ return {
126949
+ state: "linked-visible",
126950
+ workspace: name ? { id, name } : { id }
126951
+ };
126952
+ }
126953
+ if (response.status === 403) {
126954
+ const workspaceId = extractDuplicateWorkspaceId(
126955
+ JSON.stringify(parsed)
126956
+ );
126957
+ if (workspaceId) {
126958
+ return { state: "linked-invisible", workspaceId };
126959
+ }
126960
+ return {
126961
+ state: "unknown",
126962
+ reason: "filesystem lookup returned 403 without error.meta.workspaceId"
126963
+ };
126964
+ }
126965
+ return {
126966
+ state: "unknown",
126967
+ reason: `filesystem lookup returned HTTP ${response.status}`
126968
+ };
126969
+ } catch (error2) {
126970
+ return {
126971
+ state: "unknown",
126972
+ reason: error2 instanceof Error ? error2.message : String(error2)
126973
+ };
126974
+ }
126975
+ }
126976
+ async connectWorkspaceToRepository(workspaceId, repoUrl, options) {
126899
126977
  const url = `${this.bifrostBaseUrl}/ws/proxy`;
126900
126978
  const payload = {
126901
126979
  service: "workspaces",
@@ -126922,6 +127000,11 @@ var BifrostInternalIntegrationAdapter = class {
126922
127000
  if (isDuplicate) {
126923
127001
  const existingWorkspaceId = extractDuplicateWorkspaceId(body);
126924
127002
  if (existingWorkspaceId && existingWorkspaceId !== workspaceId) {
127003
+ if (options?.preflightWasFree) {
127004
+ throw new Error(
127005
+ `REPOSITORY_LINK_CONFLICT_UNRESOLVED: Preflight found no active owner, but link creation reported workspace ${existingWorkspaceId}. Stop and contact Postman support; do not alter the repository URL.`
127006
+ );
127007
+ }
126925
127008
  throw new Error(
126926
127009
  await this.describeWorkspaceLinkConflict(existingWorkspaceId, workspaceId, repoUrl)
126927
127010
  );
@@ -129848,6 +129931,39 @@ async function runRepoSyncInner(inputs, dependencies) {
129848
129931
  }
129849
129932
  }
129850
129933
  }
129934
+ let skipRepositoryLinkPost = false;
129935
+ let repositoryLinkPreflightWasFree = false;
129936
+ if (inputs.workspaceLinkEnabled && inputs.workspaceId && inputs.repoUrl && dependencies.internalIntegration?.findWorkspaceForRepo) {
129937
+ const probe = await dependencies.internalIntegration.findWorkspaceForRepo(
129938
+ inputs.repoUrl,
129939
+ "/"
129940
+ );
129941
+ if (probe.state === "linked-visible") {
129942
+ if (probe.workspace.id === inputs.workspaceId) {
129943
+ skipRepositoryLinkPost = true;
129944
+ dependencies.core.info(
129945
+ `REPOSITORY_LINK_ALREADY_TARGET: Repository ${inputs.repoUrl} at path / is already linked to target workspace ${inputs.workspaceId}; continuing.`
129946
+ );
129947
+ } else {
129948
+ const ownerName = probe.workspace.name?.trim() || "unknown";
129949
+ throw new Error(
129950
+ `REPOSITORY_LINK_CONFLICT_VISIBLE: Repository ${inputs.repoUrl} at path / is already linked to workspace ${probe.workspace.id} ("${ownerName}"). No Postman assets were changed. Reuse that workspace or disconnect it in Workspace Settings, then rerun.`
129951
+ );
129952
+ }
129953
+ } else if (probe.state === "linked-invisible") {
129954
+ let message = `REPOSITORY_LINK_CONFLICT_INVISIBLE: Repository ${inputs.repoUrl} at path / is linked to workspace ${probe.workspaceId}, but these credentials cannot view it. No Postman assets were changed. Ask its owner or a team admin to disconnect it.`;
129955
+ if (inputs.orgMode) {
129956
+ message += " Verify workspace-team-id; if the owner is in another sub-team, ask that sub-team's admin to disconnect it.";
129957
+ }
129958
+ throw new Error(message);
129959
+ } else if (probe.state === "free") {
129960
+ repositoryLinkPreflightWasFree = true;
129961
+ } else {
129962
+ dependencies.core.warning(
129963
+ `REPOSITORY_LINK_PREFLIGHT_UNKNOWN: Unable to determine the existing repository link (${probe.reason}); continuing and relying on link creation conflict handling.`
129964
+ );
129965
+ }
129966
+ }
129851
129967
  const branchAssetMarker = buildBranchAssetMarker(branchDecision, inputs);
129852
129968
  const envUids = await upsertEnvironments(inputs, dependencies, resourcesState, branchAssetMarker);
129853
129969
  outputs["environment-uids-json"] = JSON.stringify(envUids);
@@ -129980,18 +130096,33 @@ async function runRepoSyncInner(inputs, dependencies) {
129980
130096
  }
129981
130097
  if (inputs.workspaceLinkEnabled && inputs.workspaceId && inputs.repoUrl && dependencies.internalIntegration) {
129982
130098
  try {
129983
- await dependencies.internalIntegration.connectWorkspaceToRepository(
129984
- inputs.workspaceId,
129985
- inputs.repoUrl
129986
- );
129987
- outputs["workspace-link-status"] = "success";
129988
- dependencies.core.info(
129989
- `workspace-link-status=success workspace-id=${inputs.workspaceId} repo=${inputs.repoUrl}`
129990
- );
130099
+ if (skipRepositoryLinkPost) {
130100
+ outputs["workspace-link-status"] = "success";
130101
+ dependencies.core.info(
130102
+ `workspace-link-status=success workspace-id=${inputs.workspaceId} repo=${inputs.repoUrl} (preflight already-target; link POST skipped)`
130103
+ );
130104
+ } else {
130105
+ await dependencies.internalIntegration.connectWorkspaceToRepository(
130106
+ inputs.workspaceId,
130107
+ inputs.repoUrl,
130108
+ repositoryLinkPreflightWasFree ? { preflightWasFree: true } : void 0
130109
+ );
130110
+ outputs["workspace-link-status"] = "success";
130111
+ dependencies.core.info(
130112
+ `workspace-link-status=success workspace-id=${inputs.workspaceId} repo=${inputs.repoUrl}`
130113
+ );
130114
+ }
129991
130115
  } catch (error2) {
129992
130116
  outputs["workspace-link-status"] = "failed";
129993
- const message = `Workspace link failed: ${error2 instanceof Error ? error2.message : String(error2)}`;
130117
+ const rawMessage = error2 instanceof Error ? error2.message : String(error2);
130118
+ const isUnresolvedContract = rawMessage.startsWith(
130119
+ "REPOSITORY_LINK_CONFLICT_UNRESOLVED:"
130120
+ );
130121
+ const message = isUnresolvedContract ? rawMessage : `Workspace link failed: ${rawMessage}`;
129994
130122
  if (branchDecision.tier === "canonical") {
130123
+ if (isUnresolvedContract && error2 instanceof Error) {
130124
+ throw error2;
130125
+ }
129995
130126
  throw new Error(message, { cause: error2 });
129996
130127
  }
129997
130128
  dependencies.core.warning(message);
package/dist/cli.cjs CHANGED
@@ -124998,7 +124998,85 @@ var BifrostInternalIntegrationAdapter = class {
124998
124998
  throw advised ?? httpErr;
124999
124999
  }
125000
125000
  }
125001
- async connectWorkspaceToRepository(workspaceId, repoUrl) {
125001
+ /**
125002
+ * Probe who (if anyone) already owns the global `(repo, path)` filesystem
125003
+ * link. Non-fatal: unexpected statuses / network errors yield `unknown` so
125004
+ * callers can proceed and rely on reactive POST conflict handling.
125005
+ *
125006
+ * Bifrost states (FileSystemController.fetchWorkspaceForFileSystem):
125007
+ * - 200 + data null -> free
125008
+ * - 200 + data -> linked-visible (workspace payload)
125009
+ * - 403 + error.meta.workspaceId -> linked-invisible
125010
+ * - 200 + error.meta.workspaceId -> linked-invisible (proxy envelope)
125011
+ */
125012
+ async findWorkspaceForRepo(repoUrl, path5 = "/") {
125013
+ const fsPath = path5 && path5.trim() ? path5.trim() : "/";
125014
+ const url = `${this.bifrostBaseUrl}/ws/proxy`;
125015
+ const payload = {
125016
+ service: "workspaces",
125017
+ method: "GET",
125018
+ path: `/workspaces/filesystem?repo=${encodeURIComponent(repoUrl)}&path=${encodeURIComponent(fsPath)}`
125019
+ };
125020
+ try {
125021
+ const response = await this.fetchImpl(url, {
125022
+ method: "POST",
125023
+ headers: this.bifrostHeaders(),
125024
+ body: JSON.stringify(payload)
125025
+ });
125026
+ let parsed = {};
125027
+ try {
125028
+ parsed = await response.json();
125029
+ } catch {
125030
+ return {
125031
+ state: "unknown",
125032
+ reason: `filesystem lookup returned non-JSON body (HTTP ${response.status})`
125033
+ };
125034
+ }
125035
+ const errorMetaWorkspaceId = typeof parsed?.error?.meta?.workspaceId === "string" && parsed.error.meta.workspaceId.trim() ? parsed.error.meta.workspaceId.trim() : void 0;
125036
+ if (errorMetaWorkspaceId) {
125037
+ return { state: "linked-invisible", workspaceId: errorMetaWorkspaceId };
125038
+ }
125039
+ if (response.ok) {
125040
+ if (parsed?.data == null) {
125041
+ return { state: "free" };
125042
+ }
125043
+ const id = typeof parsed.data.id === "string" ? parsed.data.id.trim() : "";
125044
+ if (!id) {
125045
+ return {
125046
+ state: "unknown",
125047
+ reason: "filesystem lookup returned 200 without a workspace id"
125048
+ };
125049
+ }
125050
+ const name = typeof parsed.data.name === "string" && parsed.data.name.trim() ? parsed.data.name.trim() : void 0;
125051
+ return {
125052
+ state: "linked-visible",
125053
+ workspace: name ? { id, name } : { id }
125054
+ };
125055
+ }
125056
+ if (response.status === 403) {
125057
+ const workspaceId = extractDuplicateWorkspaceId(
125058
+ JSON.stringify(parsed)
125059
+ );
125060
+ if (workspaceId) {
125061
+ return { state: "linked-invisible", workspaceId };
125062
+ }
125063
+ return {
125064
+ state: "unknown",
125065
+ reason: "filesystem lookup returned 403 without error.meta.workspaceId"
125066
+ };
125067
+ }
125068
+ return {
125069
+ state: "unknown",
125070
+ reason: `filesystem lookup returned HTTP ${response.status}`
125071
+ };
125072
+ } catch (error) {
125073
+ return {
125074
+ state: "unknown",
125075
+ reason: error instanceof Error ? error.message : String(error)
125076
+ };
125077
+ }
125078
+ }
125079
+ async connectWorkspaceToRepository(workspaceId, repoUrl, options) {
125002
125080
  const url = `${this.bifrostBaseUrl}/ws/proxy`;
125003
125081
  const payload = {
125004
125082
  service: "workspaces",
@@ -125025,6 +125103,11 @@ var BifrostInternalIntegrationAdapter = class {
125025
125103
  if (isDuplicate) {
125026
125104
  const existingWorkspaceId = extractDuplicateWorkspaceId(body);
125027
125105
  if (existingWorkspaceId && existingWorkspaceId !== workspaceId) {
125106
+ if (options?.preflightWasFree) {
125107
+ throw new Error(
125108
+ `REPOSITORY_LINK_CONFLICT_UNRESOLVED: Preflight found no active owner, but link creation reported workspace ${existingWorkspaceId}. Stop and contact Postman support; do not alter the repository URL.`
125109
+ );
125110
+ }
125028
125111
  throw new Error(
125029
125112
  await this.describeWorkspaceLinkConflict(existingWorkspaceId, workspaceId, repoUrl)
125030
125113
  );
@@ -127758,6 +127841,39 @@ async function runRepoSyncInner(inputs, dependencies) {
127758
127841
  }
127759
127842
  }
127760
127843
  }
127844
+ let skipRepositoryLinkPost = false;
127845
+ let repositoryLinkPreflightWasFree = false;
127846
+ if (inputs.workspaceLinkEnabled && inputs.workspaceId && inputs.repoUrl && dependencies.internalIntegration?.findWorkspaceForRepo) {
127847
+ const probe = await dependencies.internalIntegration.findWorkspaceForRepo(
127848
+ inputs.repoUrl,
127849
+ "/"
127850
+ );
127851
+ if (probe.state === "linked-visible") {
127852
+ if (probe.workspace.id === inputs.workspaceId) {
127853
+ skipRepositoryLinkPost = true;
127854
+ dependencies.core.info(
127855
+ `REPOSITORY_LINK_ALREADY_TARGET: Repository ${inputs.repoUrl} at path / is already linked to target workspace ${inputs.workspaceId}; continuing.`
127856
+ );
127857
+ } else {
127858
+ const ownerName = probe.workspace.name?.trim() || "unknown";
127859
+ throw new Error(
127860
+ `REPOSITORY_LINK_CONFLICT_VISIBLE: Repository ${inputs.repoUrl} at path / is already linked to workspace ${probe.workspace.id} ("${ownerName}"). No Postman assets were changed. Reuse that workspace or disconnect it in Workspace Settings, then rerun.`
127861
+ );
127862
+ }
127863
+ } else if (probe.state === "linked-invisible") {
127864
+ let message = `REPOSITORY_LINK_CONFLICT_INVISIBLE: Repository ${inputs.repoUrl} at path / is linked to workspace ${probe.workspaceId}, but these credentials cannot view it. No Postman assets were changed. Ask its owner or a team admin to disconnect it.`;
127865
+ if (inputs.orgMode) {
127866
+ message += " Verify workspace-team-id; if the owner is in another sub-team, ask that sub-team's admin to disconnect it.";
127867
+ }
127868
+ throw new Error(message);
127869
+ } else if (probe.state === "free") {
127870
+ repositoryLinkPreflightWasFree = true;
127871
+ } else {
127872
+ dependencies.core.warning(
127873
+ `REPOSITORY_LINK_PREFLIGHT_UNKNOWN: Unable to determine the existing repository link (${probe.reason}); continuing and relying on link creation conflict handling.`
127874
+ );
127875
+ }
127876
+ }
127761
127877
  const branchAssetMarker = buildBranchAssetMarker(branchDecision, inputs);
127762
127878
  const envUids = await upsertEnvironments(inputs, dependencies, resourcesState, branchAssetMarker);
127763
127879
  outputs["environment-uids-json"] = JSON.stringify(envUids);
@@ -127890,18 +128006,33 @@ async function runRepoSyncInner(inputs, dependencies) {
127890
128006
  }
127891
128007
  if (inputs.workspaceLinkEnabled && inputs.workspaceId && inputs.repoUrl && dependencies.internalIntegration) {
127892
128008
  try {
127893
- await dependencies.internalIntegration.connectWorkspaceToRepository(
127894
- inputs.workspaceId,
127895
- inputs.repoUrl
127896
- );
127897
- outputs["workspace-link-status"] = "success";
127898
- dependencies.core.info(
127899
- `workspace-link-status=success workspace-id=${inputs.workspaceId} repo=${inputs.repoUrl}`
127900
- );
128009
+ if (skipRepositoryLinkPost) {
128010
+ outputs["workspace-link-status"] = "success";
128011
+ dependencies.core.info(
128012
+ `workspace-link-status=success workspace-id=${inputs.workspaceId} repo=${inputs.repoUrl} (preflight already-target; link POST skipped)`
128013
+ );
128014
+ } else {
128015
+ await dependencies.internalIntegration.connectWorkspaceToRepository(
128016
+ inputs.workspaceId,
128017
+ inputs.repoUrl,
128018
+ repositoryLinkPreflightWasFree ? { preflightWasFree: true } : void 0
128019
+ );
128020
+ outputs["workspace-link-status"] = "success";
128021
+ dependencies.core.info(
128022
+ `workspace-link-status=success workspace-id=${inputs.workspaceId} repo=${inputs.repoUrl}`
128023
+ );
128024
+ }
127901
128025
  } catch (error) {
127902
128026
  outputs["workspace-link-status"] = "failed";
127903
- const message = `Workspace link failed: ${error instanceof Error ? error.message : String(error)}`;
128027
+ const rawMessage = error instanceof Error ? error.message : String(error);
128028
+ const isUnresolvedContract = rawMessage.startsWith(
128029
+ "REPOSITORY_LINK_CONFLICT_UNRESOLVED:"
128030
+ );
128031
+ const message = isUnresolvedContract ? rawMessage : `Workspace link failed: ${rawMessage}`;
127904
128032
  if (branchDecision.tier === "canonical") {
128033
+ if (isUnresolvedContract && error instanceof Error) {
128034
+ throw error;
128035
+ }
127905
128036
  throw new Error(message, { cause: error });
127906
128037
  }
127907
128038
  dependencies.core.warning(message);
package/dist/index.cjs CHANGED
@@ -126915,7 +126915,85 @@ var BifrostInternalIntegrationAdapter = class {
126915
126915
  throw advised ?? httpErr;
126916
126916
  }
126917
126917
  }
126918
- async connectWorkspaceToRepository(workspaceId, repoUrl) {
126918
+ /**
126919
+ * Probe who (if anyone) already owns the global `(repo, path)` filesystem
126920
+ * link. Non-fatal: unexpected statuses / network errors yield `unknown` so
126921
+ * callers can proceed and rely on reactive POST conflict handling.
126922
+ *
126923
+ * Bifrost states (FileSystemController.fetchWorkspaceForFileSystem):
126924
+ * - 200 + data null -> free
126925
+ * - 200 + data -> linked-visible (workspace payload)
126926
+ * - 403 + error.meta.workspaceId -> linked-invisible
126927
+ * - 200 + error.meta.workspaceId -> linked-invisible (proxy envelope)
126928
+ */
126929
+ async findWorkspaceForRepo(repoUrl, path9 = "/") {
126930
+ const fsPath = path9 && path9.trim() ? path9.trim() : "/";
126931
+ const url = `${this.bifrostBaseUrl}/ws/proxy`;
126932
+ const payload = {
126933
+ service: "workspaces",
126934
+ method: "GET",
126935
+ path: `/workspaces/filesystem?repo=${encodeURIComponent(repoUrl)}&path=${encodeURIComponent(fsPath)}`
126936
+ };
126937
+ try {
126938
+ const response = await this.fetchImpl(url, {
126939
+ method: "POST",
126940
+ headers: this.bifrostHeaders(),
126941
+ body: JSON.stringify(payload)
126942
+ });
126943
+ let parsed = {};
126944
+ try {
126945
+ parsed = await response.json();
126946
+ } catch {
126947
+ return {
126948
+ state: "unknown",
126949
+ reason: `filesystem lookup returned non-JSON body (HTTP ${response.status})`
126950
+ };
126951
+ }
126952
+ const errorMetaWorkspaceId = typeof parsed?.error?.meta?.workspaceId === "string" && parsed.error.meta.workspaceId.trim() ? parsed.error.meta.workspaceId.trim() : void 0;
126953
+ if (errorMetaWorkspaceId) {
126954
+ return { state: "linked-invisible", workspaceId: errorMetaWorkspaceId };
126955
+ }
126956
+ if (response.ok) {
126957
+ if (parsed?.data == null) {
126958
+ return { state: "free" };
126959
+ }
126960
+ const id = typeof parsed.data.id === "string" ? parsed.data.id.trim() : "";
126961
+ if (!id) {
126962
+ return {
126963
+ state: "unknown",
126964
+ reason: "filesystem lookup returned 200 without a workspace id"
126965
+ };
126966
+ }
126967
+ const name = typeof parsed.data.name === "string" && parsed.data.name.trim() ? parsed.data.name.trim() : void 0;
126968
+ return {
126969
+ state: "linked-visible",
126970
+ workspace: name ? { id, name } : { id }
126971
+ };
126972
+ }
126973
+ if (response.status === 403) {
126974
+ const workspaceId = extractDuplicateWorkspaceId(
126975
+ JSON.stringify(parsed)
126976
+ );
126977
+ if (workspaceId) {
126978
+ return { state: "linked-invisible", workspaceId };
126979
+ }
126980
+ return {
126981
+ state: "unknown",
126982
+ reason: "filesystem lookup returned 403 without error.meta.workspaceId"
126983
+ };
126984
+ }
126985
+ return {
126986
+ state: "unknown",
126987
+ reason: `filesystem lookup returned HTTP ${response.status}`
126988
+ };
126989
+ } catch (error2) {
126990
+ return {
126991
+ state: "unknown",
126992
+ reason: error2 instanceof Error ? error2.message : String(error2)
126993
+ };
126994
+ }
126995
+ }
126996
+ async connectWorkspaceToRepository(workspaceId, repoUrl, options) {
126919
126997
  const url = `${this.bifrostBaseUrl}/ws/proxy`;
126920
126998
  const payload = {
126921
126999
  service: "workspaces",
@@ -126942,6 +127020,11 @@ var BifrostInternalIntegrationAdapter = class {
126942
127020
  if (isDuplicate) {
126943
127021
  const existingWorkspaceId = extractDuplicateWorkspaceId(body);
126944
127022
  if (existingWorkspaceId && existingWorkspaceId !== workspaceId) {
127023
+ if (options?.preflightWasFree) {
127024
+ throw new Error(
127025
+ `REPOSITORY_LINK_CONFLICT_UNRESOLVED: Preflight found no active owner, but link creation reported workspace ${existingWorkspaceId}. Stop and contact Postman support; do not alter the repository URL.`
127026
+ );
127027
+ }
126945
127028
  throw new Error(
126946
127029
  await this.describeWorkspaceLinkConflict(existingWorkspaceId, workspaceId, repoUrl)
126947
127030
  );
@@ -129868,6 +129951,39 @@ async function runRepoSyncInner(inputs, dependencies) {
129868
129951
  }
129869
129952
  }
129870
129953
  }
129954
+ let skipRepositoryLinkPost = false;
129955
+ let repositoryLinkPreflightWasFree = false;
129956
+ if (inputs.workspaceLinkEnabled && inputs.workspaceId && inputs.repoUrl && dependencies.internalIntegration?.findWorkspaceForRepo) {
129957
+ const probe = await dependencies.internalIntegration.findWorkspaceForRepo(
129958
+ inputs.repoUrl,
129959
+ "/"
129960
+ );
129961
+ if (probe.state === "linked-visible") {
129962
+ if (probe.workspace.id === inputs.workspaceId) {
129963
+ skipRepositoryLinkPost = true;
129964
+ dependencies.core.info(
129965
+ `REPOSITORY_LINK_ALREADY_TARGET: Repository ${inputs.repoUrl} at path / is already linked to target workspace ${inputs.workspaceId}; continuing.`
129966
+ );
129967
+ } else {
129968
+ const ownerName = probe.workspace.name?.trim() || "unknown";
129969
+ throw new Error(
129970
+ `REPOSITORY_LINK_CONFLICT_VISIBLE: Repository ${inputs.repoUrl} at path / is already linked to workspace ${probe.workspace.id} ("${ownerName}"). No Postman assets were changed. Reuse that workspace or disconnect it in Workspace Settings, then rerun.`
129971
+ );
129972
+ }
129973
+ } else if (probe.state === "linked-invisible") {
129974
+ let message = `REPOSITORY_LINK_CONFLICT_INVISIBLE: Repository ${inputs.repoUrl} at path / is linked to workspace ${probe.workspaceId}, but these credentials cannot view it. No Postman assets were changed. Ask its owner or a team admin to disconnect it.`;
129975
+ if (inputs.orgMode) {
129976
+ message += " Verify workspace-team-id; if the owner is in another sub-team, ask that sub-team's admin to disconnect it.";
129977
+ }
129978
+ throw new Error(message);
129979
+ } else if (probe.state === "free") {
129980
+ repositoryLinkPreflightWasFree = true;
129981
+ } else {
129982
+ dependencies.core.warning(
129983
+ `REPOSITORY_LINK_PREFLIGHT_UNKNOWN: Unable to determine the existing repository link (${probe.reason}); continuing and relying on link creation conflict handling.`
129984
+ );
129985
+ }
129986
+ }
129871
129987
  const branchAssetMarker = buildBranchAssetMarker(branchDecision, inputs);
129872
129988
  const envUids = await upsertEnvironments(inputs, dependencies, resourcesState, branchAssetMarker);
129873
129989
  outputs["environment-uids-json"] = JSON.stringify(envUids);
@@ -130000,18 +130116,33 @@ async function runRepoSyncInner(inputs, dependencies) {
130000
130116
  }
130001
130117
  if (inputs.workspaceLinkEnabled && inputs.workspaceId && inputs.repoUrl && dependencies.internalIntegration) {
130002
130118
  try {
130003
- await dependencies.internalIntegration.connectWorkspaceToRepository(
130004
- inputs.workspaceId,
130005
- inputs.repoUrl
130006
- );
130007
- outputs["workspace-link-status"] = "success";
130008
- dependencies.core.info(
130009
- `workspace-link-status=success workspace-id=${inputs.workspaceId} repo=${inputs.repoUrl}`
130010
- );
130119
+ if (skipRepositoryLinkPost) {
130120
+ outputs["workspace-link-status"] = "success";
130121
+ dependencies.core.info(
130122
+ `workspace-link-status=success workspace-id=${inputs.workspaceId} repo=${inputs.repoUrl} (preflight already-target; link POST skipped)`
130123
+ );
130124
+ } else {
130125
+ await dependencies.internalIntegration.connectWorkspaceToRepository(
130126
+ inputs.workspaceId,
130127
+ inputs.repoUrl,
130128
+ repositoryLinkPreflightWasFree ? { preflightWasFree: true } : void 0
130129
+ );
130130
+ outputs["workspace-link-status"] = "success";
130131
+ dependencies.core.info(
130132
+ `workspace-link-status=success workspace-id=${inputs.workspaceId} repo=${inputs.repoUrl}`
130133
+ );
130134
+ }
130011
130135
  } catch (error2) {
130012
130136
  outputs["workspace-link-status"] = "failed";
130013
- const message = `Workspace link failed: ${error2 instanceof Error ? error2.message : String(error2)}`;
130137
+ const rawMessage = error2 instanceof Error ? error2.message : String(error2);
130138
+ const isUnresolvedContract = rawMessage.startsWith(
130139
+ "REPOSITORY_LINK_CONFLICT_UNRESOLVED:"
130140
+ );
130141
+ const message = isUnresolvedContract ? rawMessage : `Workspace link failed: ${rawMessage}`;
130014
130142
  if (branchDecision.tier === "canonical") {
130143
+ if (isUnresolvedContract && error2 instanceof Error) {
130144
+ throw error2;
130145
+ }
130015
130146
  throw new Error(message, { cause: error2 });
130016
130147
  }
130017
130148
  dependencies.core.warning(message);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@postman-cse/onboarding-repo-sync",
3
- "version": "2.1.7",
3
+ "version": "2.1.8",
4
4
  "description": "Postman repo sync GitHub Action.",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",