contentful-import 10.5.0 → 10.5.1
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/index.js +131 -41
- package/dist/index.mjs +131 -41
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5984,6 +5984,29 @@ var PARENT_FOLDER_GROUP_IDS = {
|
|
|
5984
5984
|
fragment: "contentful.folder-group-fragment",
|
|
5985
5985
|
experience: "contentful.folder-group-experience"
|
|
5986
5986
|
};
|
|
5987
|
+
var VERSION_CONFLICT_MAX_ATTEMPTS = 5;
|
|
5988
|
+
var VERSION_CONFLICT_RETRY_DELAY_MS = 250;
|
|
5989
|
+
var MissingExoFolderGroupSchemesError = class extends Error {
|
|
5990
|
+
constructor(missingSchemeIds) {
|
|
5991
|
+
super(`Missing ExO folder-group concept scheme(s) in the destination organization: ${missingSchemeIds.join(", ")}`);
|
|
5992
|
+
this.name = "MissingExoFolderGroupSchemesError";
|
|
5993
|
+
this.missingSchemeIds = missingSchemeIds;
|
|
5994
|
+
}
|
|
5995
|
+
};
|
|
5996
|
+
var SourceExoFolderConceptReadError = class extends Error {
|
|
5997
|
+
constructor(sourceConceptId, error) {
|
|
5998
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
5999
|
+
super(`Unable to read source ExO folder concept ${sourceConceptId}: ${reason}`);
|
|
6000
|
+
this.name = "SourceExoFolderConceptReadError";
|
|
6001
|
+
this.sourceConceptId = sourceConceptId;
|
|
6002
|
+
}
|
|
6003
|
+
};
|
|
6004
|
+
var SourceOrganizationResolutionError = class extends Error {
|
|
6005
|
+
constructor(message) {
|
|
6006
|
+
super(message);
|
|
6007
|
+
this.name = "SourceOrganizationResolutionError";
|
|
6008
|
+
}
|
|
6009
|
+
};
|
|
5987
6010
|
var ENTITY_TYPE_TO_PARENT_GROUP_ID = {
|
|
5988
6011
|
designTokens: PARENT_FOLDER_GROUP_IDS.designToken,
|
|
5989
6012
|
components: PARENT_FOLDER_GROUP_IDS.componentType,
|
|
@@ -6000,19 +6023,44 @@ function getSourceSpaceId(sourceEntities) {
|
|
|
6000
6023
|
}
|
|
6001
6024
|
return void 0;
|
|
6002
6025
|
}
|
|
6003
|
-
|
|
6026
|
+
function isVersionMismatchError(err) {
|
|
6027
|
+
return err?.error?.sys?.id === "VersionMismatch";
|
|
6028
|
+
}
|
|
6029
|
+
async function waitForVersionConflictRetry(attempt) {
|
|
6030
|
+
await new Promise((resolve2) => setTimeout(resolve2, VERSION_CONFLICT_RETRY_DELAY_MS * attempt));
|
|
6031
|
+
}
|
|
6032
|
+
async function resolveSourceOrganizationId(client, sourceSpaceId) {
|
|
6033
|
+
if (!sourceSpaceId) {
|
|
6034
|
+
throw new SourceOrganizationResolutionError(
|
|
6035
|
+
"Unable to resolve the source organization because the exported ExO entity does not include a source space ID"
|
|
6036
|
+
);
|
|
6037
|
+
}
|
|
6038
|
+
try {
|
|
6039
|
+
const sourceSpace = await client.space.get({ spaceId: sourceSpaceId });
|
|
6040
|
+
const sourceOrganizationId = sourceSpace?.sys?.organization?.sys?.id;
|
|
6041
|
+
if (!sourceOrganizationId) {
|
|
6042
|
+
throw new Error(`source space ${sourceSpaceId} has no organization link`);
|
|
6043
|
+
}
|
|
6044
|
+
return sourceOrganizationId;
|
|
6045
|
+
} catch (err) {
|
|
6046
|
+
if (err instanceof SourceOrganizationResolutionError) throw err;
|
|
6047
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
6048
|
+
throw new SourceOrganizationResolutionError(
|
|
6049
|
+
`Unable to resolve the source organization for space ${sourceSpaceId}: ${reason}`
|
|
6050
|
+
);
|
|
6051
|
+
}
|
|
6052
|
+
}
|
|
6053
|
+
async function ensureParentFolderGroupsExist(client, destinationOrganizationId, requiredParentGroupIds) {
|
|
6054
|
+
if (requiredParentGroupIds.size === 0) return /* @__PURE__ */ new Map();
|
|
6004
6055
|
const { items } = await client.conceptScheme.getMany({
|
|
6005
|
-
organizationId,
|
|
6056
|
+
organizationId: destinationOrganizationId,
|
|
6006
6057
|
query: { purpose: "internal" }
|
|
6007
6058
|
});
|
|
6008
6059
|
const existingIds = new Set(items.map((s) => s.sys.id));
|
|
6009
|
-
const
|
|
6010
|
-
if (
|
|
6011
|
-
return /* @__PURE__ */ new Map();
|
|
6012
|
-
}
|
|
6013
|
-
const parentGroupIdSet = new Set(Object.values(PARENT_FOLDER_GROUP_IDS));
|
|
6060
|
+
const missingSchemeIds = [...requiredParentGroupIds].filter((id) => !existingIds.has(id));
|
|
6061
|
+
if (missingSchemeIds.length > 0) throw new MissingExoFolderGroupSchemesError(missingSchemeIds);
|
|
6014
6062
|
return new Map(
|
|
6015
|
-
items.filter((s) =>
|
|
6063
|
+
items.filter((s) => requiredParentGroupIds.has(s.sys.id)).map((s) => [s.sys.id, s])
|
|
6016
6064
|
);
|
|
6017
6065
|
}
|
|
6018
6066
|
function deriveChildConceptMap(sourceEntities, destinationSpaceId) {
|
|
@@ -6031,27 +6079,48 @@ function deriveChildConceptMap(sourceEntities, destinationSpaceId) {
|
|
|
6031
6079
|
}
|
|
6032
6080
|
return childConceptMap;
|
|
6033
6081
|
}
|
|
6034
|
-
async function createOrPatchChildConcepts(client,
|
|
6082
|
+
async function createOrPatchChildConcepts(client, sourceOrganizationId, destinationOrganizationId, destinationSpaceId, childConceptMap) {
|
|
6035
6083
|
const spaceLink = { sys: { type: "Link", linkType: "Space", id: destinationSpaceId } };
|
|
6084
|
+
const existingDestinationConcepts = /* @__PURE__ */ new Map();
|
|
6036
6085
|
for (const [sourceConceptId, { destConceptId }] of childConceptMap) {
|
|
6037
|
-
let prefLabel = { "en-US": destConceptId };
|
|
6038
|
-
try {
|
|
6039
|
-
const sourceConcept = await client.concept.get({ organizationId, conceptId: sourceConceptId });
|
|
6040
|
-
if (sourceConcept?.prefLabel) prefLabel = sourceConcept.prefLabel;
|
|
6041
|
-
} catch {
|
|
6042
|
-
}
|
|
6043
6086
|
let existing = null;
|
|
6044
6087
|
try {
|
|
6045
|
-
existing = await client.concept.get({
|
|
6088
|
+
existing = await client.concept.get({
|
|
6089
|
+
organizationId: destinationOrganizationId,
|
|
6090
|
+
conceptId: destConceptId
|
|
6091
|
+
});
|
|
6046
6092
|
} catch (err) {
|
|
6047
6093
|
if (err?.name !== "NotFound") {
|
|
6048
6094
|
import_logging10.logEmitter.emit("warning", `Could not fetch destination child concept ${destConceptId}: ${err?.message ?? err}`);
|
|
6049
6095
|
}
|
|
6050
6096
|
}
|
|
6097
|
+
existingDestinationConcepts.set(sourceConceptId, existing);
|
|
6098
|
+
}
|
|
6099
|
+
const sourceConceptLabels = /* @__PURE__ */ new Map();
|
|
6100
|
+
for (const [sourceConceptId] of childConceptMap) {
|
|
6101
|
+
if (existingDestinationConcepts.get(sourceConceptId)) {
|
|
6102
|
+
continue;
|
|
6103
|
+
}
|
|
6104
|
+
try {
|
|
6105
|
+
const sourceConcept = await client.concept.get({
|
|
6106
|
+
organizationId: sourceOrganizationId,
|
|
6107
|
+
conceptId: sourceConceptId
|
|
6108
|
+
});
|
|
6109
|
+
if (!sourceConcept?.prefLabel) {
|
|
6110
|
+
throw new Error("source concept has no prefLabel");
|
|
6111
|
+
}
|
|
6112
|
+
sourceConceptLabels.set(sourceConceptId, sourceConcept.prefLabel);
|
|
6113
|
+
} catch (err) {
|
|
6114
|
+
throw new SourceExoFolderConceptReadError(sourceConceptId, err);
|
|
6115
|
+
}
|
|
6116
|
+
}
|
|
6117
|
+
for (const [sourceConceptId, { destConceptId }] of childConceptMap) {
|
|
6118
|
+
const existing = existingDestinationConcepts.get(sourceConceptId);
|
|
6051
6119
|
if (!existing) {
|
|
6120
|
+
const prefLabel = sourceConceptLabels.get(sourceConceptId);
|
|
6052
6121
|
try {
|
|
6053
6122
|
await client.concept.createWithId(
|
|
6054
|
-
{ organizationId, conceptId: destConceptId },
|
|
6123
|
+
{ organizationId: destinationOrganizationId, conceptId: destConceptId },
|
|
6055
6124
|
// @ts-expect-error - CMA.js type needs to be updated to be aware of purpose: 'internal'
|
|
6056
6125
|
{ purpose: "internal", prefLabel, metadata: { spaces: [spaceLink] } }
|
|
6057
6126
|
);
|
|
@@ -6068,7 +6137,7 @@ async function createOrPatchChildConcepts(client, organizationId, destinationSpa
|
|
|
6068
6137
|
if (patches.length > 0) {
|
|
6069
6138
|
try {
|
|
6070
6139
|
await client.concept.patch(
|
|
6071
|
-
{ organizationId, conceptId: destConceptId, version: existing.sys.version },
|
|
6140
|
+
{ organizationId: destinationOrganizationId, conceptId: destConceptId, version: existing.sys.version },
|
|
6072
6141
|
patches
|
|
6073
6142
|
);
|
|
6074
6143
|
import_logging10.logEmitter.emit("info", `Patched child folder concept ${destConceptId} (${patches.map((p) => p.path).join(", ")})`);
|
|
@@ -6079,21 +6148,33 @@ async function createOrPatchChildConcepts(client, organizationId, destinationSpa
|
|
|
6079
6148
|
}
|
|
6080
6149
|
}
|
|
6081
6150
|
}
|
|
6082
|
-
async function linkChildConceptsToParentGroups(client,
|
|
6151
|
+
async function linkChildConceptsToParentGroups(client, destinationOrganizationId, childConceptMap, parentGroups) {
|
|
6083
6152
|
for (const [, { destConceptId, parentGroupId }] of childConceptMap) {
|
|
6084
|
-
|
|
6085
|
-
|
|
6086
|
-
|
|
6087
|
-
|
|
6088
|
-
|
|
6089
|
-
|
|
6090
|
-
|
|
6091
|
-
|
|
6092
|
-
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
|
|
6096
|
-
|
|
6153
|
+
let parentGroup = parentGroups.get(parentGroupId);
|
|
6154
|
+
for (let attempt = 1; parentGroup && attempt <= VERSION_CONFLICT_MAX_ATTEMPTS; attempt++) {
|
|
6155
|
+
const alreadyLinked = (parentGroup.concepts ?? []).some((c) => c.sys.id === destConceptId);
|
|
6156
|
+
if (alreadyLinked) break;
|
|
6157
|
+
try {
|
|
6158
|
+
const updated = await client.conceptScheme.patch(
|
|
6159
|
+
{ organizationId: destinationOrganizationId, conceptSchemeId: parentGroupId, version: parentGroup.sys.version },
|
|
6160
|
+
[{ op: "add", path: "/concepts/-", value: { sys: { type: "Link", linkType: "TaxonomyConcept", id: destConceptId } } }]
|
|
6161
|
+
);
|
|
6162
|
+
parentGroups.set(parentGroupId, updated);
|
|
6163
|
+
import_logging10.logEmitter.emit("info", `Linked child concept ${destConceptId} to parent group ${parentGroupId}`);
|
|
6164
|
+
break;
|
|
6165
|
+
} catch (err) {
|
|
6166
|
+
if (!isVersionMismatchError(err) || attempt === VERSION_CONFLICT_MAX_ATTEMPTS) {
|
|
6167
|
+
import_logging10.logEmitter.emit("error", `Failed to link child concept ${destConceptId} to parent group ${parentGroupId}: ${err?.message ?? err}`);
|
|
6168
|
+
break;
|
|
6169
|
+
}
|
|
6170
|
+
import_logging10.logEmitter.emit("warning", `Version mismatch linking child concept ${destConceptId} to parent group ${parentGroupId}; retrying`);
|
|
6171
|
+
await waitForVersionConflictRetry(attempt);
|
|
6172
|
+
parentGroup = await client.conceptScheme.get({
|
|
6173
|
+
organizationId: destinationOrganizationId,
|
|
6174
|
+
conceptSchemeId: parentGroupId
|
|
6175
|
+
});
|
|
6176
|
+
parentGroups.set(parentGroupId, parentGroup);
|
|
6177
|
+
}
|
|
6097
6178
|
}
|
|
6098
6179
|
}
|
|
6099
6180
|
}
|
|
@@ -6109,7 +6190,7 @@ function rewriteEntityFolderConcepts(entities2, childConceptMap) {
|
|
|
6109
6190
|
}
|
|
6110
6191
|
async function importExoFolders({
|
|
6111
6192
|
client,
|
|
6112
|
-
|
|
6193
|
+
destinationOrganizationId,
|
|
6113
6194
|
destinationSpaceId,
|
|
6114
6195
|
sourceEntities
|
|
6115
6196
|
}) {
|
|
@@ -6118,16 +6199,22 @@ async function importExoFolders({
|
|
|
6118
6199
|
import_logging10.logEmitter.emit("info", "Source and destination space are the same \u2014 skipping ExO folder import");
|
|
6119
6200
|
return;
|
|
6120
6201
|
}
|
|
6121
|
-
const parentGroups = await ensureParentFolderGroupsExist(client, organizationId);
|
|
6122
|
-
if (parentGroups.size === 0) {
|
|
6123
|
-
import_logging10.logEmitter.emit("warn", "One or more Experience Orchestration folder group concept schemes are missing in the destination organization. Please create them before importing.");
|
|
6124
|
-
return;
|
|
6125
|
-
}
|
|
6126
6202
|
const childConceptMap = deriveChildConceptMap(sourceEntities, destinationSpaceId);
|
|
6127
6203
|
if (childConceptMap.size === 0) return;
|
|
6204
|
+
const requiredParentGroupIds = new Set(
|
|
6205
|
+
[...childConceptMap.values()].map(({ parentGroupId }) => parentGroupId)
|
|
6206
|
+
);
|
|
6207
|
+
const sourceOrganizationId = await resolveSourceOrganizationId(client, sourceSpaceId);
|
|
6208
|
+
const parentGroups = await ensureParentFolderGroupsExist(client, destinationOrganizationId, requiredParentGroupIds);
|
|
6128
6209
|
import_logging10.logEmitter.emit("info", `Importing ${childConceptMap.size} ExO folder concept(s) into destination space ${destinationSpaceId}`);
|
|
6129
|
-
await createOrPatchChildConcepts(
|
|
6130
|
-
|
|
6210
|
+
await createOrPatchChildConcepts(
|
|
6211
|
+
client,
|
|
6212
|
+
sourceOrganizationId,
|
|
6213
|
+
destinationOrganizationId,
|
|
6214
|
+
destinationSpaceId,
|
|
6215
|
+
childConceptMap
|
|
6216
|
+
);
|
|
6217
|
+
await linkChildConceptsToParentGroups(client, destinationOrganizationId, childConceptMap, parentGroups);
|
|
6131
6218
|
const allEntities = [
|
|
6132
6219
|
...sourceEntities.designTokens ?? [],
|
|
6133
6220
|
...sourceEntities.components ?? [],
|
|
@@ -6557,7 +6644,7 @@ function pushToSpace({
|
|
|
6557
6644
|
const space = await client.space.get({ spaceId });
|
|
6558
6645
|
await importExoFolders({
|
|
6559
6646
|
client,
|
|
6560
|
-
|
|
6647
|
+
destinationOrganizationId: space.sys.organization.sys.id,
|
|
6561
6648
|
destinationSpaceId: spaceId,
|
|
6562
6649
|
sourceEntities: {
|
|
6563
6650
|
designTokens: sourceData.designTokens,
|
|
@@ -6568,6 +6655,9 @@ function pushToSpace({
|
|
|
6568
6655
|
}
|
|
6569
6656
|
});
|
|
6570
6657
|
} catch (error) {
|
|
6658
|
+
if (error instanceof MissingExoFolderGroupSchemesError || error instanceof SourceOrganizationResolutionError || error instanceof SourceExoFolderConceptReadError) {
|
|
6659
|
+
throw error;
|
|
6660
|
+
}
|
|
6571
6661
|
import_logging12.logEmitter.emit("warning", `Unable to create Experience Orchestration (ExO) folders, error: ${error}`);
|
|
6572
6662
|
}
|
|
6573
6663
|
}),
|
package/dist/index.mjs
CHANGED
|
@@ -5951,6 +5951,29 @@ var PARENT_FOLDER_GROUP_IDS = {
|
|
|
5951
5951
|
fragment: "contentful.folder-group-fragment",
|
|
5952
5952
|
experience: "contentful.folder-group-experience"
|
|
5953
5953
|
};
|
|
5954
|
+
var VERSION_CONFLICT_MAX_ATTEMPTS = 5;
|
|
5955
|
+
var VERSION_CONFLICT_RETRY_DELAY_MS = 250;
|
|
5956
|
+
var MissingExoFolderGroupSchemesError = class extends Error {
|
|
5957
|
+
constructor(missingSchemeIds) {
|
|
5958
|
+
super(`Missing ExO folder-group concept scheme(s) in the destination organization: ${missingSchemeIds.join(", ")}`);
|
|
5959
|
+
this.name = "MissingExoFolderGroupSchemesError";
|
|
5960
|
+
this.missingSchemeIds = missingSchemeIds;
|
|
5961
|
+
}
|
|
5962
|
+
};
|
|
5963
|
+
var SourceExoFolderConceptReadError = class extends Error {
|
|
5964
|
+
constructor(sourceConceptId, error) {
|
|
5965
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
5966
|
+
super(`Unable to read source ExO folder concept ${sourceConceptId}: ${reason}`);
|
|
5967
|
+
this.name = "SourceExoFolderConceptReadError";
|
|
5968
|
+
this.sourceConceptId = sourceConceptId;
|
|
5969
|
+
}
|
|
5970
|
+
};
|
|
5971
|
+
var SourceOrganizationResolutionError = class extends Error {
|
|
5972
|
+
constructor(message) {
|
|
5973
|
+
super(message);
|
|
5974
|
+
this.name = "SourceOrganizationResolutionError";
|
|
5975
|
+
}
|
|
5976
|
+
};
|
|
5954
5977
|
var ENTITY_TYPE_TO_PARENT_GROUP_ID = {
|
|
5955
5978
|
designTokens: PARENT_FOLDER_GROUP_IDS.designToken,
|
|
5956
5979
|
components: PARENT_FOLDER_GROUP_IDS.componentType,
|
|
@@ -5967,19 +5990,44 @@ function getSourceSpaceId(sourceEntities) {
|
|
|
5967
5990
|
}
|
|
5968
5991
|
return void 0;
|
|
5969
5992
|
}
|
|
5970
|
-
|
|
5993
|
+
function isVersionMismatchError(err) {
|
|
5994
|
+
return err?.error?.sys?.id === "VersionMismatch";
|
|
5995
|
+
}
|
|
5996
|
+
async function waitForVersionConflictRetry(attempt) {
|
|
5997
|
+
await new Promise((resolve2) => setTimeout(resolve2, VERSION_CONFLICT_RETRY_DELAY_MS * attempt));
|
|
5998
|
+
}
|
|
5999
|
+
async function resolveSourceOrganizationId(client, sourceSpaceId) {
|
|
6000
|
+
if (!sourceSpaceId) {
|
|
6001
|
+
throw new SourceOrganizationResolutionError(
|
|
6002
|
+
"Unable to resolve the source organization because the exported ExO entity does not include a source space ID"
|
|
6003
|
+
);
|
|
6004
|
+
}
|
|
6005
|
+
try {
|
|
6006
|
+
const sourceSpace = await client.space.get({ spaceId: sourceSpaceId });
|
|
6007
|
+
const sourceOrganizationId = sourceSpace?.sys?.organization?.sys?.id;
|
|
6008
|
+
if (!sourceOrganizationId) {
|
|
6009
|
+
throw new Error(`source space ${sourceSpaceId} has no organization link`);
|
|
6010
|
+
}
|
|
6011
|
+
return sourceOrganizationId;
|
|
6012
|
+
} catch (err) {
|
|
6013
|
+
if (err instanceof SourceOrganizationResolutionError) throw err;
|
|
6014
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
6015
|
+
throw new SourceOrganizationResolutionError(
|
|
6016
|
+
`Unable to resolve the source organization for space ${sourceSpaceId}: ${reason}`
|
|
6017
|
+
);
|
|
6018
|
+
}
|
|
6019
|
+
}
|
|
6020
|
+
async function ensureParentFolderGroupsExist(client, destinationOrganizationId, requiredParentGroupIds) {
|
|
6021
|
+
if (requiredParentGroupIds.size === 0) return /* @__PURE__ */ new Map();
|
|
5971
6022
|
const { items } = await client.conceptScheme.getMany({
|
|
5972
|
-
organizationId,
|
|
6023
|
+
organizationId: destinationOrganizationId,
|
|
5973
6024
|
query: { purpose: "internal" }
|
|
5974
6025
|
});
|
|
5975
6026
|
const existingIds = new Set(items.map((s) => s.sys.id));
|
|
5976
|
-
const
|
|
5977
|
-
if (
|
|
5978
|
-
return /* @__PURE__ */ new Map();
|
|
5979
|
-
}
|
|
5980
|
-
const parentGroupIdSet = new Set(Object.values(PARENT_FOLDER_GROUP_IDS));
|
|
6027
|
+
const missingSchemeIds = [...requiredParentGroupIds].filter((id) => !existingIds.has(id));
|
|
6028
|
+
if (missingSchemeIds.length > 0) throw new MissingExoFolderGroupSchemesError(missingSchemeIds);
|
|
5981
6029
|
return new Map(
|
|
5982
|
-
items.filter((s) =>
|
|
6030
|
+
items.filter((s) => requiredParentGroupIds.has(s.sys.id)).map((s) => [s.sys.id, s])
|
|
5983
6031
|
);
|
|
5984
6032
|
}
|
|
5985
6033
|
function deriveChildConceptMap(sourceEntities, destinationSpaceId) {
|
|
@@ -5998,27 +6046,48 @@ function deriveChildConceptMap(sourceEntities, destinationSpaceId) {
|
|
|
5998
6046
|
}
|
|
5999
6047
|
return childConceptMap;
|
|
6000
6048
|
}
|
|
6001
|
-
async function createOrPatchChildConcepts(client,
|
|
6049
|
+
async function createOrPatchChildConcepts(client, sourceOrganizationId, destinationOrganizationId, destinationSpaceId, childConceptMap) {
|
|
6002
6050
|
const spaceLink = { sys: { type: "Link", linkType: "Space", id: destinationSpaceId } };
|
|
6051
|
+
const existingDestinationConcepts = /* @__PURE__ */ new Map();
|
|
6003
6052
|
for (const [sourceConceptId, { destConceptId }] of childConceptMap) {
|
|
6004
|
-
let prefLabel = { "en-US": destConceptId };
|
|
6005
|
-
try {
|
|
6006
|
-
const sourceConcept = await client.concept.get({ organizationId, conceptId: sourceConceptId });
|
|
6007
|
-
if (sourceConcept?.prefLabel) prefLabel = sourceConcept.prefLabel;
|
|
6008
|
-
} catch {
|
|
6009
|
-
}
|
|
6010
6053
|
let existing = null;
|
|
6011
6054
|
try {
|
|
6012
|
-
existing = await client.concept.get({
|
|
6055
|
+
existing = await client.concept.get({
|
|
6056
|
+
organizationId: destinationOrganizationId,
|
|
6057
|
+
conceptId: destConceptId
|
|
6058
|
+
});
|
|
6013
6059
|
} catch (err) {
|
|
6014
6060
|
if (err?.name !== "NotFound") {
|
|
6015
6061
|
import_logging10.logEmitter.emit("warning", `Could not fetch destination child concept ${destConceptId}: ${err?.message ?? err}`);
|
|
6016
6062
|
}
|
|
6017
6063
|
}
|
|
6064
|
+
existingDestinationConcepts.set(sourceConceptId, existing);
|
|
6065
|
+
}
|
|
6066
|
+
const sourceConceptLabels = /* @__PURE__ */ new Map();
|
|
6067
|
+
for (const [sourceConceptId] of childConceptMap) {
|
|
6068
|
+
if (existingDestinationConcepts.get(sourceConceptId)) {
|
|
6069
|
+
continue;
|
|
6070
|
+
}
|
|
6071
|
+
try {
|
|
6072
|
+
const sourceConcept = await client.concept.get({
|
|
6073
|
+
organizationId: sourceOrganizationId,
|
|
6074
|
+
conceptId: sourceConceptId
|
|
6075
|
+
});
|
|
6076
|
+
if (!sourceConcept?.prefLabel) {
|
|
6077
|
+
throw new Error("source concept has no prefLabel");
|
|
6078
|
+
}
|
|
6079
|
+
sourceConceptLabels.set(sourceConceptId, sourceConcept.prefLabel);
|
|
6080
|
+
} catch (err) {
|
|
6081
|
+
throw new SourceExoFolderConceptReadError(sourceConceptId, err);
|
|
6082
|
+
}
|
|
6083
|
+
}
|
|
6084
|
+
for (const [sourceConceptId, { destConceptId }] of childConceptMap) {
|
|
6085
|
+
const existing = existingDestinationConcepts.get(sourceConceptId);
|
|
6018
6086
|
if (!existing) {
|
|
6087
|
+
const prefLabel = sourceConceptLabels.get(sourceConceptId);
|
|
6019
6088
|
try {
|
|
6020
6089
|
await client.concept.createWithId(
|
|
6021
|
-
{ organizationId, conceptId: destConceptId },
|
|
6090
|
+
{ organizationId: destinationOrganizationId, conceptId: destConceptId },
|
|
6022
6091
|
// @ts-expect-error - CMA.js type needs to be updated to be aware of purpose: 'internal'
|
|
6023
6092
|
{ purpose: "internal", prefLabel, metadata: { spaces: [spaceLink] } }
|
|
6024
6093
|
);
|
|
@@ -6035,7 +6104,7 @@ async function createOrPatchChildConcepts(client, organizationId, destinationSpa
|
|
|
6035
6104
|
if (patches.length > 0) {
|
|
6036
6105
|
try {
|
|
6037
6106
|
await client.concept.patch(
|
|
6038
|
-
{ organizationId, conceptId: destConceptId, version: existing.sys.version },
|
|
6107
|
+
{ organizationId: destinationOrganizationId, conceptId: destConceptId, version: existing.sys.version },
|
|
6039
6108
|
patches
|
|
6040
6109
|
);
|
|
6041
6110
|
import_logging10.logEmitter.emit("info", `Patched child folder concept ${destConceptId} (${patches.map((p) => p.path).join(", ")})`);
|
|
@@ -6046,21 +6115,33 @@ async function createOrPatchChildConcepts(client, organizationId, destinationSpa
|
|
|
6046
6115
|
}
|
|
6047
6116
|
}
|
|
6048
6117
|
}
|
|
6049
|
-
async function linkChildConceptsToParentGroups(client,
|
|
6118
|
+
async function linkChildConceptsToParentGroups(client, destinationOrganizationId, childConceptMap, parentGroups) {
|
|
6050
6119
|
for (const [, { destConceptId, parentGroupId }] of childConceptMap) {
|
|
6051
|
-
|
|
6052
|
-
|
|
6053
|
-
|
|
6054
|
-
|
|
6055
|
-
|
|
6056
|
-
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6120
|
+
let parentGroup = parentGroups.get(parentGroupId);
|
|
6121
|
+
for (let attempt = 1; parentGroup && attempt <= VERSION_CONFLICT_MAX_ATTEMPTS; attempt++) {
|
|
6122
|
+
const alreadyLinked = (parentGroup.concepts ?? []).some((c) => c.sys.id === destConceptId);
|
|
6123
|
+
if (alreadyLinked) break;
|
|
6124
|
+
try {
|
|
6125
|
+
const updated = await client.conceptScheme.patch(
|
|
6126
|
+
{ organizationId: destinationOrganizationId, conceptSchemeId: parentGroupId, version: parentGroup.sys.version },
|
|
6127
|
+
[{ op: "add", path: "/concepts/-", value: { sys: { type: "Link", linkType: "TaxonomyConcept", id: destConceptId } } }]
|
|
6128
|
+
);
|
|
6129
|
+
parentGroups.set(parentGroupId, updated);
|
|
6130
|
+
import_logging10.logEmitter.emit("info", `Linked child concept ${destConceptId} to parent group ${parentGroupId}`);
|
|
6131
|
+
break;
|
|
6132
|
+
} catch (err) {
|
|
6133
|
+
if (!isVersionMismatchError(err) || attempt === VERSION_CONFLICT_MAX_ATTEMPTS) {
|
|
6134
|
+
import_logging10.logEmitter.emit("error", `Failed to link child concept ${destConceptId} to parent group ${parentGroupId}: ${err?.message ?? err}`);
|
|
6135
|
+
break;
|
|
6136
|
+
}
|
|
6137
|
+
import_logging10.logEmitter.emit("warning", `Version mismatch linking child concept ${destConceptId} to parent group ${parentGroupId}; retrying`);
|
|
6138
|
+
await waitForVersionConflictRetry(attempt);
|
|
6139
|
+
parentGroup = await client.conceptScheme.get({
|
|
6140
|
+
organizationId: destinationOrganizationId,
|
|
6141
|
+
conceptSchemeId: parentGroupId
|
|
6142
|
+
});
|
|
6143
|
+
parentGroups.set(parentGroupId, parentGroup);
|
|
6144
|
+
}
|
|
6064
6145
|
}
|
|
6065
6146
|
}
|
|
6066
6147
|
}
|
|
@@ -6076,7 +6157,7 @@ function rewriteEntityFolderConcepts(entities2, childConceptMap) {
|
|
|
6076
6157
|
}
|
|
6077
6158
|
async function importExoFolders({
|
|
6078
6159
|
client,
|
|
6079
|
-
|
|
6160
|
+
destinationOrganizationId,
|
|
6080
6161
|
destinationSpaceId,
|
|
6081
6162
|
sourceEntities
|
|
6082
6163
|
}) {
|
|
@@ -6085,16 +6166,22 @@ async function importExoFolders({
|
|
|
6085
6166
|
import_logging10.logEmitter.emit("info", "Source and destination space are the same \u2014 skipping ExO folder import");
|
|
6086
6167
|
return;
|
|
6087
6168
|
}
|
|
6088
|
-
const parentGroups = await ensureParentFolderGroupsExist(client, organizationId);
|
|
6089
|
-
if (parentGroups.size === 0) {
|
|
6090
|
-
import_logging10.logEmitter.emit("warn", "One or more Experience Orchestration folder group concept schemes are missing in the destination organization. Please create them before importing.");
|
|
6091
|
-
return;
|
|
6092
|
-
}
|
|
6093
6169
|
const childConceptMap = deriveChildConceptMap(sourceEntities, destinationSpaceId);
|
|
6094
6170
|
if (childConceptMap.size === 0) return;
|
|
6171
|
+
const requiredParentGroupIds = new Set(
|
|
6172
|
+
[...childConceptMap.values()].map(({ parentGroupId }) => parentGroupId)
|
|
6173
|
+
);
|
|
6174
|
+
const sourceOrganizationId = await resolveSourceOrganizationId(client, sourceSpaceId);
|
|
6175
|
+
const parentGroups = await ensureParentFolderGroupsExist(client, destinationOrganizationId, requiredParentGroupIds);
|
|
6095
6176
|
import_logging10.logEmitter.emit("info", `Importing ${childConceptMap.size} ExO folder concept(s) into destination space ${destinationSpaceId}`);
|
|
6096
|
-
await createOrPatchChildConcepts(
|
|
6097
|
-
|
|
6177
|
+
await createOrPatchChildConcepts(
|
|
6178
|
+
client,
|
|
6179
|
+
sourceOrganizationId,
|
|
6180
|
+
destinationOrganizationId,
|
|
6181
|
+
destinationSpaceId,
|
|
6182
|
+
childConceptMap
|
|
6183
|
+
);
|
|
6184
|
+
await linkChildConceptsToParentGroups(client, destinationOrganizationId, childConceptMap, parentGroups);
|
|
6098
6185
|
const allEntities = [
|
|
6099
6186
|
...sourceEntities.designTokens ?? [],
|
|
6100
6187
|
...sourceEntities.components ?? [],
|
|
@@ -6524,7 +6611,7 @@ function pushToSpace({
|
|
|
6524
6611
|
const space = await client.space.get({ spaceId });
|
|
6525
6612
|
await importExoFolders({
|
|
6526
6613
|
client,
|
|
6527
|
-
|
|
6614
|
+
destinationOrganizationId: space.sys.organization.sys.id,
|
|
6528
6615
|
destinationSpaceId: spaceId,
|
|
6529
6616
|
sourceEntities: {
|
|
6530
6617
|
designTokens: sourceData.designTokens,
|
|
@@ -6535,6 +6622,9 @@ function pushToSpace({
|
|
|
6535
6622
|
}
|
|
6536
6623
|
});
|
|
6537
6624
|
} catch (error) {
|
|
6625
|
+
if (error instanceof MissingExoFolderGroupSchemesError || error instanceof SourceOrganizationResolutionError || error instanceof SourceExoFolderConceptReadError) {
|
|
6626
|
+
throw error;
|
|
6627
|
+
}
|
|
6538
6628
|
import_logging12.logEmitter.emit("warning", `Unable to create Experience Orchestration (ExO) folders, error: ${error}`);
|
|
6539
6629
|
}
|
|
6540
6630
|
}),
|