@contentful/experience-design-system-cli 2.37.1-dev-build-9da0d812.0 → 2.37.1-dev-build-8757f66c.0

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 CHANGED
@@ -3202,9 +3202,11 @@ var init_resolve_session_id = __esm({
3202
3202
  });
3203
3203
 
3204
3204
  // packages/experience-design-system-backend-pipeline/dist/src/persistence/src/credentials/helpers/host-utils.js
3205
+ var DEFAULT_CONFIGURED_HOST;
3205
3206
  var init_host_utils = __esm({
3206
3207
  "packages/experience-design-system-backend-pipeline/dist/src/persistence/src/credentials/helpers/host-utils.js"() {
3207
3208
  "use strict";
3209
+ DEFAULT_CONFIGURED_HOST = "api.contentful.com";
3208
3210
  }
3209
3211
  });
3210
3212
 
@@ -3679,9 +3681,9 @@ var init_utils_gen = __esm({
3679
3681
  config.headers = mergeHeaders(a.headers, b.headers);
3680
3682
  return config;
3681
3683
  };
3682
- mergeHeaders = (...headers2) => {
3684
+ mergeHeaders = (...headers) => {
3683
3685
  const mergedHeaders = new Headers();
3684
- for (const header of headers2) {
3686
+ for (const header of headers) {
3685
3687
  if (!header || typeof header !== "object") {
3686
3688
  continue;
3687
3689
  }
@@ -3928,10 +3930,37 @@ var init_client_gen2 = __esm({
3928
3930
  });
3929
3931
 
3930
3932
  // packages/experience-design-system-client/dist/src/generated/sdk.gen.js
3933
+ var designSystemImportSourcelessPreview, designSystemImportApply, designSystemImportGetOperation;
3931
3934
  var init_sdk_gen = __esm({
3932
3935
  "packages/experience-design-system-client/dist/src/generated/sdk.gen.js"() {
3933
3936
  "use strict";
3934
3937
  init_client_gen2();
3938
+ designSystemImportSourcelessPreview = (options) => {
3939
+ return (options.client ?? client).post({
3940
+ url: "/spaces/{spaceId}/environments/{environmentId}/design_systems/imports/preview",
3941
+ ...options,
3942
+ headers: {
3943
+ "Content-Type": "application/json",
3944
+ ...options.headers
3945
+ }
3946
+ });
3947
+ };
3948
+ designSystemImportApply = (options) => {
3949
+ return (options.client ?? client).post({
3950
+ url: "/spaces/{spaceId}/environments/{environmentId}/design_systems/imports/apply",
3951
+ ...options,
3952
+ headers: {
3953
+ "Content-Type": "application/json",
3954
+ ...options.headers
3955
+ }
3956
+ });
3957
+ };
3958
+ designSystemImportGetOperation = (options) => {
3959
+ return (options.client ?? client).get({
3960
+ url: "/spaces/{spaceId}/environments/{environmentId}/design_systems/imports/apply/{operationId}",
3961
+ ...options
3962
+ });
3963
+ };
3935
3964
  }
3936
3965
  });
3937
3966
 
@@ -3954,9 +3983,13 @@ var init_src2 = __esm({
3954
3983
  });
3955
3984
 
3956
3985
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/constants/api.js
3986
+ var PREVIEW_ERROR_PREFIX, APPLY_ERROR_PREFIX, USER_AGENT;
3957
3987
  var init_api = __esm({
3958
3988
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/constants/api.js"() {
3959
3989
  "use strict";
3990
+ PREVIEW_ERROR_PREFIX = "preview failed:";
3991
+ APPLY_ERROR_PREFIX = "apply failed:";
3992
+ USER_AGENT = "experience-design-system-backend-pipeline";
3960
3993
  }
3961
3994
  });
3962
3995
 
@@ -3969,34 +4002,153 @@ var init_constants5 = __esm({
3969
4002
  });
3970
4003
 
3971
4004
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/http-utils.js
4005
+ function isTransientStatus(status) {
4006
+ return status >= 500 && status <= 599;
4007
+ }
4008
+ function retryAfterMs(response) {
4009
+ const value = response.headers?.get("retry-after")?.trim();
4010
+ if (!value)
4011
+ return void 0;
4012
+ const seconds = Number(value);
4013
+ const delayMs = Number.isFinite(seconds) ? seconds * 1e3 : Date.parse(value) - Date.now();
4014
+ if (!Number.isFinite(delayMs) || delayMs < 0 || delayMs > MAX_RETRY_AFTER_MS)
4015
+ return void 0;
4016
+ return Math.round(delayMs);
4017
+ }
4018
+ function isApsDenialBody(body) {
4019
+ if (!body)
4020
+ return false;
4021
+ try {
4022
+ const parsed = JSON.parse(body);
4023
+ const id = parsed?.sys?.id;
4024
+ return id === "NotFound" || id === "AccessDenied";
4025
+ } catch {
4026
+ return false;
4027
+ }
4028
+ }
4029
+ function stringifyError(error) {
4030
+ return typeof error === "string" ? error : JSON.stringify(error ?? {});
4031
+ }
4032
+ function errorMessage(error) {
4033
+ return error instanceof Error && error.message ? error.message : String(error);
4034
+ }
4035
+ function defaultSleep(delayMs) {
4036
+ return new Promise((resolve2) => setTimeout(resolve2, delayMs));
4037
+ }
4038
+ var MAX_RETRY_AFTER_MS;
3972
4039
  var init_http_utils = __esm({
3973
4040
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/http-utils.js"() {
3974
4041
  "use strict";
4042
+ MAX_RETRY_AFTER_MS = 6e4;
3975
4043
  }
3976
4044
  });
3977
4045
 
3978
4046
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/sanitize-preview.js
4047
+ function sanitizeBreakingChanges(raw) {
4048
+ if (!Array.isArray(raw))
4049
+ return [];
4050
+ const out = [];
4051
+ for (const bc of raw) {
4052
+ if (typeof bc !== "object" || bc === null)
4053
+ continue;
4054
+ const reason = bc.reason;
4055
+ if (typeof reason !== "string")
4056
+ continue;
4057
+ if ("propertyId" in bc && typeof bc.propertyId === "string") {
4058
+ if (PROPERTY_BREAKING_REASONS.has(reason))
4059
+ out.push(bc);
4060
+ continue;
4061
+ }
4062
+ if ("slotId" in bc && typeof bc.slotId === "string") {
4063
+ if (SLOT_BREAKING_REASONS.has(reason))
4064
+ out.push(bc);
4065
+ continue;
4066
+ }
4067
+ }
4068
+ return out;
4069
+ }
4070
+ function sanitizePreviewResponse(res) {
4071
+ for (const item of res.components?.changed ?? []) {
4072
+ const cc = item.changeClassification;
4073
+ if (cc && Array.isArray(cc.breakingChanges)) {
4074
+ cc.breakingChanges = sanitizeBreakingChanges(cc.breakingChanges);
4075
+ }
4076
+ }
4077
+ return res;
4078
+ }
4079
+ var PROPERTY_BREAKING_REASONS, SLOT_BREAKING_REASONS;
3979
4080
  var init_sanitize_preview = __esm({
3980
4081
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/sanitize-preview.js"() {
3981
4082
  "use strict";
4083
+ PROPERTY_BREAKING_REASONS = /* @__PURE__ */ new Set([
4084
+ "removed",
4085
+ "added_required_no_default",
4086
+ "type_changed",
4087
+ "validation_narrowed"
4088
+ ]);
4089
+ SLOT_BREAKING_REASONS = /* @__PURE__ */ new Set(["slot_removed", "slot_allowed_components_narrowed"]);
3982
4090
  }
3983
4091
  });
3984
4092
 
3985
4093
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/host-utils.js
4094
+ function trimTrailingSlashes(value) {
4095
+ return value.replace(/\/+$/, "");
4096
+ }
4097
+ function normalizeHostInput(host) {
4098
+ const value = host?.trim();
4099
+ if (!value)
4100
+ return void 0;
4101
+ return trimTrailingSlashes(value);
4102
+ }
4103
+ function toConfiguredHost2(host) {
4104
+ const normalized = normalizeHostInput(host);
4105
+ if (!normalized)
4106
+ return void 0;
4107
+ return normalized.replace(/^https:\/\//i, "");
4108
+ }
4109
+ function toApiHost2(host) {
4110
+ const normalized = normalizeHostInput(host);
4111
+ if (!normalized)
4112
+ return DEFAULT_API_HOST;
4113
+ if (/^[a-z][a-z\d+\-.]*:\/\//i.test(normalized))
4114
+ return normalized;
4115
+ return `https://${normalized}`;
4116
+ }
4117
+ var DEFAULT_API_HOST;
3986
4118
  var init_host_utils2 = __esm({
3987
4119
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/host-utils.js"() {
3988
4120
  "use strict";
4121
+ DEFAULT_API_HOST = "https://api.contentful.com";
3989
4122
  }
3990
4123
  });
3991
4124
 
3992
4125
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/types/api-error.js
4126
+ var ERROR_BODY_LOG_CAP, ApiError;
3993
4127
  var init_api_error = __esm({
3994
4128
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/types/api-error.js"() {
3995
4129
  "use strict";
4130
+ ERROR_BODY_LOG_CAP = 16384;
4131
+ ApiError = class extends Error {
4132
+ status;
4133
+ body;
4134
+ guidance;
4135
+ constructor(message, status, body, guidance) {
4136
+ super(message);
4137
+ this.status = status;
4138
+ this.body = body;
4139
+ this.guidance = guidance;
4140
+ if (body) {
4141
+ const trimmed = body.length > ERROR_BODY_LOG_CAP ? body.slice(0, ERROR_BODY_LOG_CAP) + "\u2026" : body;
4142
+ this.message = `${message}
4143
+ ${trimmed}`;
4144
+ }
4145
+ }
4146
+ };
3996
4147
  }
3997
4148
  });
3998
4149
 
3999
4150
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/api-client/api-client.js
4151
+ var ApiClient;
4000
4152
  var init_api_client = __esm({
4001
4153
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/api-client/api-client.js"() {
4002
4154
  "use strict";
@@ -4006,6 +4158,161 @@ var init_api_client = __esm({
4006
4158
  init_sanitize_preview();
4007
4159
  init_host_utils2();
4008
4160
  init_api_error();
4161
+ ApiClient = class {
4162
+ host;
4163
+ token;
4164
+ spaceId;
4165
+ environmentId;
4166
+ retry;
4167
+ lastRequestId;
4168
+ constructor(opts) {
4169
+ this.host = toApiHost2(opts.host);
4170
+ this.token = opts.cmaToken;
4171
+ this.spaceId = opts.spaceId;
4172
+ this.environmentId = opts.environmentId;
4173
+ const initialDelayMs = Math.max(0, opts.retry?.initialDelayMs ?? 250);
4174
+ this.retry = {
4175
+ maxAttempts: Math.max(1, Math.floor(opts.retry?.maxAttempts ?? 3)),
4176
+ initialDelayMs,
4177
+ maxDelayMs: Math.max(initialDelayMs, opts.retry?.maxDelayMs ?? 2e3),
4178
+ sleep: opts.retry?.sleep ?? defaultSleep
4179
+ };
4180
+ }
4181
+ getLastRequestId() {
4182
+ return this.lastRequestId;
4183
+ }
4184
+ noteRequestId(response) {
4185
+ const id = response.headers.get("x-contentful-request-id");
4186
+ if (id)
4187
+ this.lastRequestId = id;
4188
+ }
4189
+ headers() {
4190
+ return {
4191
+ Authorization: `Bearer ${this.token}`,
4192
+ "Content-Type": "application/json",
4193
+ "X-Contentful-User-Agent": USER_AGENT
4194
+ };
4195
+ }
4196
+ async requestWithRetry(phase, errorPrefix, makeCall) {
4197
+ for (let attempt = 1; attempt <= this.retry.maxAttempts; attempt++) {
4198
+ let result;
4199
+ try {
4200
+ result = await makeCall();
4201
+ } catch (error) {
4202
+ if (attempt === this.retry.maxAttempts) {
4203
+ const body = `The request failed after ${attempt} attempts because of a network error: ${errorMessage(error)}. Check your connection and try again.`;
4204
+ throw new ApiError(`${errorPrefix} 0`, 0, body);
4205
+ }
4206
+ await this.retry.sleep(Math.min(this.retry.initialDelayMs * 2 ** (attempt - 1), this.retry.maxDelayMs));
4207
+ continue;
4208
+ }
4209
+ if (!isTransientStatus(result.response.status)) {
4210
+ this.noteRequestId(result.response);
4211
+ return result;
4212
+ }
4213
+ if (attempt === this.retry.maxAttempts) {
4214
+ const body = stringifyError(result.error);
4215
+ const guidance = `The ${phase} request failed after ${attempt} attempts because the service remained unavailable. Wait a moment and try again.`;
4216
+ throw new ApiError(`${errorPrefix} ${result.response.status}`, result.response.status, body, guidance);
4217
+ }
4218
+ const backoffMs = Math.min(this.retry.initialDelayMs * 2 ** (attempt - 1), this.retry.maxDelayMs);
4219
+ await this.retry.sleep(retryAfterMs(result.response) ?? backoffMs);
4220
+ }
4221
+ throw new Error("Retry attempts exhausted");
4222
+ }
4223
+ async validateToken() {
4224
+ const res = await fetch(`${this.host}/users/me`, { headers: this.headers() });
4225
+ this.noteRequestId(res);
4226
+ if (res.status === 401) {
4227
+ throw new ApiError("CMA token is invalid or revoked", res.status, await res.text());
4228
+ }
4229
+ if (!res.ok) {
4230
+ throw new ApiError(`unexpected error validating token: ${res.status}`, res.status, await res.text());
4231
+ }
4232
+ await this.checkPreflight();
4233
+ }
4234
+ async checkPreflight() {
4235
+ const url = `${this.host}/spaces/${this.spaceId}/environments/${this.environmentId}/design_systems/preflight`;
4236
+ let res;
4237
+ try {
4238
+ res = await fetch(url, { headers: this.headers() });
4239
+ } catch {
4240
+ return;
4241
+ }
4242
+ this.noteRequestId(res);
4243
+ if (res.ok)
4244
+ return;
4245
+ if (res.status >= 500)
4246
+ return;
4247
+ const body = await res.text();
4248
+ if (res.status === 404 && !isApsDenialBody(body))
4249
+ return;
4250
+ throw new ApiError(`preflight failed: ${res.status}`, res.status, body);
4251
+ }
4252
+ async previewImport(cdf) {
4253
+ const result = await this.requestWithRetry("preview", PREVIEW_ERROR_PREFIX, () => designSystemImportSourcelessPreview({
4254
+ baseUrl: this.host,
4255
+ headers: this.headers(),
4256
+ path: { spaceId: this.spaceId, environmentId: this.environmentId },
4257
+ body: cdf,
4258
+ parseAs: "json"
4259
+ }));
4260
+ if (!result.response.ok) {
4261
+ throw new ApiError(`${PREVIEW_ERROR_PREFIX} ${result.response.status}`, result.response.status, stringifyError(result.error));
4262
+ }
4263
+ return sanitizePreviewResponse(result.data);
4264
+ }
4265
+ async applyImport(cdf, opts) {
4266
+ let result;
4267
+ try {
4268
+ result = await designSystemImportApply({
4269
+ baseUrl: this.host,
4270
+ headers: this.headers(),
4271
+ path: { spaceId: this.spaceId, environmentId: this.environmentId },
4272
+ body: { ...cdf, acknowledgeBreakingChanges: opts.acknowledgeBreakingChanges },
4273
+ parseAs: "json"
4274
+ });
4275
+ } catch (error) {
4276
+ const body = `The apply request was not retried because its outcome is unknown and retrying could start a duplicate operation. Cause: ${errorMessage(error)}`;
4277
+ throw new ApiError(`${APPLY_ERROR_PREFIX} 0`, 0, body);
4278
+ }
4279
+ if (!result.response.ok) {
4280
+ const body = stringifyError(result.error);
4281
+ const guidance = isTransientStatus(result.response.status) ? "The apply request was not retried because the server may already have started an operation and retrying could create a duplicate." : void 0;
4282
+ throw new ApiError(`${APPLY_ERROR_PREFIX} ${result.response.status}`, result.response.status, body, guidance);
4283
+ }
4284
+ this.noteRequestId(result.response);
4285
+ return result.data;
4286
+ }
4287
+ async pollOperation(operationId, opts = {}) {
4288
+ const intervalMs = opts.intervalMs ?? 2e3;
4289
+ const maxIntervalMs = opts.maxIntervalMs ?? Math.round(intervalMs * 2.5);
4290
+ const maxAttempts = opts.maxAttempts ?? 150;
4291
+ const terminalStatuses = /* @__PURE__ */ new Set(["succeeded", "partial", "failed"]);
4292
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
4293
+ const result = await this.requestWithRetry("poll", "poll failed:", () => designSystemImportGetOperation({
4294
+ baseUrl: this.host,
4295
+ headers: this.headers(),
4296
+ path: { spaceId: this.spaceId, environmentId: this.environmentId, operationId },
4297
+ parseAs: "json"
4298
+ }));
4299
+ if (!result.response.ok) {
4300
+ throw new ApiError(`poll failed: ${result.response.status}`, result.response.status, stringifyError(result.error));
4301
+ }
4302
+ const op = result.data;
4303
+ opts.onProgress?.(op);
4304
+ if (terminalStatuses.has(op.sys.status))
4305
+ return op;
4306
+ if (attempt < maxAttempts - 1) {
4307
+ const progress = maxAttempts > 1 ? attempt / (maxAttempts - 1) : 0;
4308
+ const baseDelay = intervalMs + (maxIntervalMs - intervalMs) * progress;
4309
+ const jitter = Math.random() * baseDelay * 0.15;
4310
+ await new Promise((resolve2) => setTimeout(resolve2, baseDelay + jitter));
4311
+ }
4312
+ }
4313
+ throw new Error(`Operation ${operationId} timed out after ${maxAttempts} attempts`);
4314
+ }
4315
+ };
4009
4316
  }
4010
4317
  });
4011
4318
 
@@ -4208,6 +4515,25 @@ var init_annotate_preview2 = __esm({
4208
4515
  });
4209
4516
 
4210
4517
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/parse-binding-diagnostics.js
4518
+ function parseBindingDiagnostics(body) {
4519
+ if (!/binding configurations are invalid|Pointer path does not exist/i.test(body))
4520
+ return null;
4521
+ const locationMatches = [...body.matchAll(/(?:^|\.\s)([A-Za-z0-9_$-]+(?:\s*›\s*[A-Za-z0-9_$-]+){2,})/g)];
4522
+ const location = locationMatches.at(-1)?.[1];
4523
+ const pointerMessage = body.match(/Pointer path does not exist for '\[object Object\]':\s*(.+?)(?=\.\s*Default\s*›|$)/i)?.[1];
4524
+ const graphQlMessage = body.match(/return GraphQL validation error:\s*(.+?)(?=\.\s*Default\s*›|$)/i)?.[1];
4525
+ const heading = body.match(/^(.*?)(?=\.?\s*Pointer path does not exist|\.?\s*Default\s*›)/i)?.[1]?.trim();
4526
+ const diagnostics = [];
4527
+ if (pointerMessage)
4528
+ diagnostics.push({ message: pointerMessage.trim(), ...location ? { path: location } : {} });
4529
+ if (graphQlMessage)
4530
+ diagnostics.push({ message: graphQlMessage.trim(), ...location ? { path: location } : {} });
4531
+ return {
4532
+ code: "BindingValidationFailed",
4533
+ message: heading || "One or more binding configurations are invalid.",
4534
+ ...diagnostics.length > 0 ? { diagnostics } : {}
4535
+ };
4536
+ }
4211
4537
  var init_parse_binding_diagnostics = __esm({
4212
4538
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/parse-binding-diagnostics.js"() {
4213
4539
  "use strict";
@@ -4215,6 +4541,76 @@ var init_parse_binding_diagnostics = __esm({
4215
4541
  });
4216
4542
 
4217
4543
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/helpers.js
4544
+ function asRecord(value) {
4545
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
4546
+ }
4547
+ function displayValue(value) {
4548
+ if (typeof value === "string")
4549
+ return value;
4550
+ if (typeof value === "number" || typeof value === "boolean")
4551
+ return String(value);
4552
+ if (value === null || value === void 0)
4553
+ return null;
4554
+ try {
4555
+ return JSON.stringify(value);
4556
+ } catch {
4557
+ return null;
4558
+ }
4559
+ }
4560
+ function isPathSegment(value) {
4561
+ return typeof value === "string" || typeof value === "number" && Number.isFinite(value);
4562
+ }
4563
+ function formatPath(value) {
4564
+ if (isPathSegment(value))
4565
+ return String(value) ? { path: String(value) } : { path: null };
4566
+ if (Array.isArray(value)) {
4567
+ const parts = value.filter(isPathSegment);
4568
+ return parts.length > 0 ? { path: parts.join(" \u203A ") } : { path: null };
4569
+ }
4570
+ return {};
4571
+ }
4572
+ function componentFromPath(path5) {
4573
+ if (!path5)
4574
+ return void 0;
4575
+ const manifestMatch = path5.match(/manifest:components\/([^/›]+)/);
4576
+ if (manifestMatch?.[1])
4577
+ return manifestMatch[1];
4578
+ const parts = path5.split(/[›/]/).map((part) => part.trim()).filter(Boolean);
4579
+ const componentsIndex = parts.findIndex((part) => part === "components");
4580
+ return componentsIndex === -1 ? void 0 : parts[componentsIndex + 1];
4581
+ }
4582
+ function diagnosticMessage(error) {
4583
+ const candidates = [
4584
+ ["message", error.message],
4585
+ ["details", error.details],
4586
+ ["error", error.error],
4587
+ ["name", error.name]
4588
+ ];
4589
+ for (const [messageSource, value] of candidates) {
4590
+ const message = displayValue(value);
4591
+ if (message !== null)
4592
+ return { message, messageSource };
4593
+ }
4594
+ return { message: "Validation failed" };
4595
+ }
4596
+ function parseObjectLiteralTail(body) {
4597
+ const braceStart = body.lastIndexOf("{");
4598
+ if (braceStart === -1)
4599
+ return null;
4600
+ const tail = body.slice(braceStart);
4601
+ const codeMatch = tail.match(/code:\s*['"]([^'"]+)['"]/);
4602
+ const cycleMatch = tail.match(/cycle:\s*\[\s*([^\]]*)\s*\]/);
4603
+ if (!codeMatch && !cycleMatch)
4604
+ return null;
4605
+ const code = codeMatch ? codeMatch[1] : null;
4606
+ let cycle = null;
4607
+ if (cycleMatch) {
4608
+ cycle = cycleMatch[1].split(",").map((s) => s.trim().replace(/^['"]|['"]$/g, "")).filter((s) => s.length > 0);
4609
+ if (cycle.length === 0)
4610
+ cycle = null;
4611
+ }
4612
+ return { code, cycle };
4613
+ }
4218
4614
  var init_helpers3 = __esm({
4219
4615
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/helpers.js"() {
4220
4616
  "use strict";
@@ -4222,6 +4618,50 @@ var init_helpers3 = __esm({
4222
4618
  });
4223
4619
 
4224
4620
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/parse-json-body.js
4621
+ function parseValidationDiagnostics(details) {
4622
+ if (!Array.isArray(details.errors))
4623
+ return [];
4624
+ const diagnostics = [];
4625
+ for (const rawError of details.errors) {
4626
+ const error = asRecord(rawError);
4627
+ if (!error)
4628
+ continue;
4629
+ const location = formatPath(error.path);
4630
+ const component = displayValue(error.component ?? error.componentName ?? error.componentId) ?? componentFromPath(location.path);
4631
+ diagnostics.push({ ...diagnosticMessage(error), ...location, ...component ? { component } : {} });
4632
+ }
4633
+ return diagnostics;
4634
+ }
4635
+ function parseJsonBody(body) {
4636
+ let parsed;
4637
+ try {
4638
+ parsed = JSON.parse(body);
4639
+ } catch {
4640
+ return null;
4641
+ }
4642
+ const p = asRecord(parsed);
4643
+ if (!p)
4644
+ return null;
4645
+ const details = asRecord(p.details) ?? {};
4646
+ const pick = (k) => p[k] !== void 0 ? p[k] : details[k];
4647
+ const codeRaw = pick("code") ?? asRecord(p.sys)?.id;
4648
+ const messageRaw = pick("message");
4649
+ const cycleRaw = pick("cycle");
4650
+ const out = {};
4651
+ if (typeof codeRaw === "string")
4652
+ out.code = codeRaw;
4653
+ if (typeof messageRaw === "string")
4654
+ out.message = messageRaw;
4655
+ if (Array.isArray(cycleRaw)) {
4656
+ const strs = cycleRaw.filter((x) => typeof x === "string");
4657
+ if (strs.length > 0)
4658
+ out.cycle = strs;
4659
+ }
4660
+ const diagnostics = parseValidationDiagnostics(details);
4661
+ if (diagnostics.length > 0)
4662
+ out.diagnostics = diagnostics;
4663
+ return out;
4664
+ }
4225
4665
  var init_parse_json_body = __esm({
4226
4666
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/parse-json-body.js"() {
4227
4667
  "use strict";
@@ -4230,13 +4670,72 @@ var init_parse_json_body = __esm({
4230
4670
  });
4231
4671
 
4232
4672
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/strip-lambda-log-prefix.js
4673
+ function stripLambdaLogPrefix(body) {
4674
+ return body.replace(LAMBDA_LOG_PREFIX_RE, "").replace(DD_TAG_RE, "").trim();
4675
+ }
4676
+ var LAMBDA_LOG_PREFIX_RE, DD_TAG_RE;
4233
4677
  var init_strip_lambda_log_prefix = __esm({
4234
4678
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/strip-lambda-log-prefix.js"() {
4235
4679
  "use strict";
4680
+ LAMBDA_LOG_PREFIX_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z\s+[0-9a-f-]+\s+ERROR\s+(?:\[dd\.[^\]]*\]\s*)?/;
4681
+ DD_TAG_RE = /\[dd\.(?:trace_id|span_id)=[^\]]*\]\s*/g;
4236
4682
  }
4237
4683
  });
4238
4684
 
4239
4685
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/parse-edsi-error.js
4686
+ function parseEdsiError(rawInput) {
4687
+ if (!rawInput)
4688
+ return { code: null, message: "", cycle: null, raw: true };
4689
+ const { body, prefix } = splitPhasePrefix(rawInput);
4690
+ const cleaned = stripLambdaLogPrefix(body);
4691
+ const json = parseJsonBody(cleaned) ?? parseJsonBody(body);
4692
+ const bindingFromJson = typeof json?.message === "string" ? parseBindingDiagnostics(json.message) : null;
4693
+ if (bindingFromJson) {
4694
+ return {
4695
+ code: bindingFromJson.code ?? json?.code ?? null,
4696
+ message: bindingFromJson.message ?? cleaned,
4697
+ cycle: null,
4698
+ raw: false,
4699
+ ...bindingFromJson.diagnostics ? { diagnostics: bindingFromJson.diagnostics } : {}
4700
+ };
4701
+ }
4702
+ if (json && (json.code || json.message || json.cycle)) {
4703
+ return {
4704
+ code: json.code ?? null,
4705
+ message: json.message ?? (cleaned || prefix),
4706
+ cycle: json.cycle ?? null,
4707
+ raw: false,
4708
+ ...json.diagnostics ? { diagnostics: json.diagnostics } : {}
4709
+ };
4710
+ }
4711
+ const binding = parseBindingDiagnostics(cleaned);
4712
+ if (binding) {
4713
+ return {
4714
+ code: binding.code ?? null,
4715
+ message: binding.message ?? cleaned,
4716
+ cycle: null,
4717
+ raw: false,
4718
+ ...binding.diagnostics ? { diagnostics: binding.diagnostics } : {}
4719
+ };
4720
+ }
4721
+ const literal2 = parseObjectLiteralTail(cleaned);
4722
+ if (literal2 && (literal2.code || literal2.cycle)) {
4723
+ const braceStart = cleaned.lastIndexOf("{");
4724
+ const head = braceStart === -1 ? cleaned : cleaned.slice(0, braceStart).trim();
4725
+ return { code: literal2.code ?? null, message: head || cleaned, cycle: literal2.cycle ?? null, raw: false };
4726
+ }
4727
+ return { code: null, message: cleaned || prefix || rawInput, cycle: null, raw: true };
4728
+ }
4729
+ function splitPhasePrefix(input) {
4730
+ const nlIndex = input.indexOf("\n");
4731
+ if (nlIndex === -1)
4732
+ return { body: input, prefix: "" };
4733
+ const firstLine = input.slice(0, nlIndex);
4734
+ if (!API_ERROR_PREFIX_RE.test(firstLine))
4735
+ return { body: input, prefix: "" };
4736
+ return { body: input.slice(nlIndex + 1), prefix: firstLine };
4737
+ }
4738
+ var API_ERROR_PREFIX_RE;
4240
4739
  var init_parse_edsi_error = __esm({
4241
4740
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/parse-edsi-error.js"() {
4242
4741
  "use strict";
@@ -4244,10 +4743,51 @@ var init_parse_edsi_error = __esm({
4244
4743
  init_parse_json_body();
4245
4744
  init_helpers3();
4246
4745
  init_strip_lambda_log_prefix();
4746
+ API_ERROR_PREFIX_RE = /^(?:apply|preview|poll) failed: \d+$/;
4247
4747
  }
4248
4748
  });
4249
4749
 
4250
4750
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/format-parsed-edsi-error.js
4751
+ function formatParsedEdsiError(parsed, opts = {}) {
4752
+ const lines = [];
4753
+ if (parsed.code)
4754
+ lines.push(`[${parsed.code}]`);
4755
+ if (parsed.message)
4756
+ lines.push(parsed.message);
4757
+ for (const diagnostic of parsed.diagnostics ?? []) {
4758
+ const context = [
4759
+ diagnostic.component ? `Component: ${diagnostic.component}` : null,
4760
+ diagnostic.path ? `Path: ${diagnostic.path}` : null
4761
+ ].filter(Boolean);
4762
+ lines.push(`- ${diagnostic.message}${context.length > 0 ? ` (${context.join("; ")})` : ""}`);
4763
+ if (diagnostic.path === null) {
4764
+ lines.push(" Location: not provided by the server. Review the submitted CDF file; no component or field was identified.");
4765
+ }
4766
+ if (opts.verbose && diagnostic.messageSource) {
4767
+ lines.push(` Message field: ${diagnostic.messageSource}`);
4768
+ }
4769
+ }
4770
+ if (parsed.code === "BindingValidationFailed") {
4771
+ const location = parsed.diagnostics?.find((d) => d.path)?.path;
4772
+ lines.push(location ? `Next action: review the binding at ${location} and correct its pointer or GraphQL selection.` : "Next action: review the binding pointer and GraphQL selection.");
4773
+ }
4774
+ if (parsed.code === "AccessDenied") {
4775
+ lines.push("Next action: this operation requires DesignToken and Component permissions in this environment. Ask a Contentful admin to grant both on your role.");
4776
+ }
4777
+ if (parsed.code === "NotFound") {
4778
+ lines.push("Next action: verify the resource id is correct. If it should exist, your role may lack read permission on DesignToken or Component.");
4779
+ }
4780
+ if (parsed.cycle && parsed.cycle.length > 0) {
4781
+ lines.push(`Cycle: ${parsed.cycle.join(" \u2192 ")} \u2192 ${parsed.cycle[0]}`);
4782
+ lines.push("Break the cycle by removing at least one $allowedComponents entry.");
4783
+ }
4784
+ if (opts.verbose && opts.raw) {
4785
+ lines.push("");
4786
+ lines.push("--- raw ---");
4787
+ lines.push(opts.raw);
4788
+ }
4789
+ return lines.filter(Boolean).join("\n");
4790
+ }
4251
4791
  var init_format_parsed_edsi_error = __esm({
4252
4792
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/format-parsed-edsi-error.js"() {
4253
4793
  "use strict";
@@ -4255,6 +4795,12 @@ var init_format_parsed_edsi_error = __esm({
4255
4795
  });
4256
4796
 
4257
4797
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/format-edsi-error.js
4798
+ function formatEdsiError(raw, opts = {}) {
4799
+ const input = typeof raw === "string" ? raw : displayValue(raw);
4800
+ if (!input)
4801
+ return "";
4802
+ return formatParsedEdsiError(parseEdsiError(input), { ...opts, raw: opts.raw ?? input });
4803
+ }
4258
4804
  var init_format_edsi_error = __esm({
4259
4805
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/format-edsi-error.js"() {
4260
4806
  "use strict";
@@ -4265,6 +4811,14 @@ var init_format_edsi_error = __esm({
4265
4811
  });
4266
4812
 
4267
4813
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/format-api-error.js
4814
+ function formatApiError(error, verbose = false) {
4815
+ const formatted = formatEdsiError(error.body || error.message, { verbose, raw: error.body }) || error.message;
4816
+ const phase = error.message.split("\n", 1)[0];
4817
+ const withPhase = /^(?:apply|preview|poll) failed: \d+$/.test(phase) && formatted !== phase ? `${phase}
4818
+ ${formatted}` : formatted;
4819
+ return error.guidance ? `${withPhase}
4820
+ ${error.guidance}` : withPhase;
4821
+ }
4268
4822
  var init_format_api_error = __esm({
4269
4823
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/format-api-error.js"() {
4270
4824
  "use strict";
@@ -4301,6 +4855,9 @@ var init_format_edsi_error2 = __esm({
4301
4855
  });
4302
4856
 
4303
4857
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/controller/errors/format-api-error.js
4858
+ function formatApiError2(request) {
4859
+ return formatApiError(request.error, request.verbose ?? false);
4860
+ }
4304
4861
  var init_format_api_error2 = __esm({
4305
4862
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/controller/errors/format-api-error.js"() {
4306
4863
  "use strict";
@@ -4810,21 +5367,12 @@ function keyAction2(input, key) {
4810
5367
  function nextField(field) {
4811
5368
  return FIELDS[(FIELDS.indexOf(field) + 1) % FIELDS.length];
4812
5369
  }
4813
- function toConfiguredHost3(host) {
4814
- const value = (host ?? "").trim().replace(/\/+$/, "");
4815
- return value === "" ? DEFAULT_HOST : value.replace(/^https:\/\//i, "");
4816
- }
4817
- function toApiHost3(host) {
4818
- const value = host.trim().replace(/\/+$/, "");
4819
- if (value === "") return `https://${DEFAULT_HOST}`;
4820
- return /^[a-z][a-z\d+\-.]*:\/\//i.test(value) ? value : `https://${value}`;
4821
- }
4822
5370
  function normalize(values) {
4823
5371
  return {
4824
5372
  spaceId: values.spaceId.trim(),
4825
5373
  environmentId: values.environmentId.trim(),
4826
5374
  cmaToken: values.cmaToken.trim(),
4827
- host: toConfiguredHost3(values.host)
5375
+ host: toConfiguredHost2(values.host) ?? DEFAULT_CONFIGURED_HOST
4828
5376
  };
4829
5377
  }
4830
5378
  function missingField(values) {
@@ -4833,12 +5381,12 @@ function missingField(values) {
4833
5381
  function isUnchanged(current, initial) {
4834
5382
  return FIELDS.every((field) => current[field] === initial[field]);
4835
5383
  }
4836
- var FIELDS, DEFAULT_HOST;
5384
+ var FIELDS;
4837
5385
  var init_logic4 = __esm({
4838
5386
  "packages/experience-design-system-cli/src/tui/import/steps/04-credentials/logic.ts"() {
4839
5387
  "use strict";
5388
+ init_src3();
4840
5389
  FIELDS = ["spaceId", "environmentId", "cmaToken", "host"];
4841
- DEFAULT_HOST = "api.contentful.com";
4842
5390
  }
4843
5391
  });
4844
5392
 
@@ -4868,65 +5416,35 @@ var init_controls4 = __esm({
4868
5416
  });
4869
5417
 
4870
5418
  // packages/experience-design-system-cli/src/tui/import/steps/04-credentials/validate.ts
4871
- function headers(token) {
4872
- return { Authorization: `Bearer ${token}`, "X-Contentful-User-Agent": USER_AGENT2 };
4873
- }
4874
- function isApsDenial(body) {
4875
- try {
4876
- const id = JSON.parse(body).sys?.id;
4877
- return id === "NotFound" || id === "AccessDenied";
4878
- } catch {
4879
- return false;
4880
- }
4881
- }
4882
- function messageFrom(body) {
4883
- try {
4884
- const message = JSON.parse(body).message;
4885
- return typeof message === "string" && message !== "" ? message : void 0;
4886
- } catch {
4887
- return void 0;
4888
- }
4889
- }
4890
5419
  async function validateCredentials(values) {
4891
- const base = toApiHost3(values.host);
4892
- let me;
4893
- try {
4894
- me = await fetch(`${base}/users/me`, { headers: headers(values.cmaToken) });
4895
- } catch (error) {
4896
- return { ok: false, error: `Could not reach ${base}: ${error instanceof Error ? error.message : String(error)}` };
4897
- }
4898
- if (me.status === 401) return { ok: false, error: "CMA token is invalid or revoked." };
4899
- if (!me.ok) return { ok: false, error: `Unexpected error validating the token (${me.status}).` };
4900
- let preflight;
5420
+ const host = toApiHost2(values.host);
5421
+ const client2 = new ApiClient({
5422
+ host,
5423
+ spaceId: values.spaceId,
5424
+ environmentId: values.environmentId,
5425
+ cmaToken: values.cmaToken
5426
+ });
4901
5427
  try {
4902
- preflight = await fetch(
4903
- `${base}/spaces/${values.spaceId}/environments/${values.environmentId}/design_systems/preflight`,
4904
- { headers: headers(values.cmaToken) }
4905
- );
4906
- } catch {
5428
+ await client2.validateToken();
4907
5429
  return { ok: true };
5430
+ } catch (error) {
5431
+ return { ok: false, error: toUserError(error, host) };
4908
5432
  }
4909
- if (preflight.ok || preflight.status >= 500) return { ok: true };
4910
- const body = await preflight.text();
4911
- if (preflight.status === 404 && !isApsDenial(body)) return { ok: true };
4912
- const detail = messageFrom(body);
4913
- if (preflight.status === 403) {
4914
- return { ok: false, error: `Access denied. ${detail ?? "Your token cannot write design system components here."}` };
4915
- }
4916
- if (preflight.status === 404) {
4917
- return {
4918
- ok: false,
4919
- error: `Not found. Check the space ID, environment and API host.${detail ? ` (${detail})` : ""}`
4920
- };
5433
+ }
5434
+ function toUserError(error, host) {
5435
+ if (error instanceof ApiError) {
5436
+ if (error.status === 404 && error.message.startsWith("preflight failed:")) {
5437
+ return "Not found. Check the space ID, environment and API host.";
5438
+ }
5439
+ return formatApiError2({ error });
4921
5440
  }
4922
- return { ok: false, error: `Credential check failed (${preflight.status}).${detail ? ` ${detail}` : ""}` };
5441
+ if (error instanceof Error) return `Could not reach ${host}: ${error.message}`;
5442
+ return String(error);
4923
5443
  }
4924
- var USER_AGENT2;
4925
5444
  var init_validate4 = __esm({
4926
5445
  "packages/experience-design-system-cli/src/tui/import/steps/04-credentials/validate.ts"() {
4927
5446
  "use strict";
4928
- init_logic4();
4929
- USER_AGENT2 = "app contentful.experience-design-system-cli";
5447
+ init_src3();
4930
5448
  }
4931
5449
  });
4932
5450
 
@@ -5001,7 +5519,7 @@ function CredentialsScreen({
5001
5519
  value: values[field],
5002
5520
  focus: active === field && !validating,
5003
5521
  mask: field === "cmaToken" ? "\u2022" : void 0,
5004
- placeholder: field === "host" ? DEFAULT_HOST : void 0,
5522
+ placeholder: field === "host" ? DEFAULT_CONFIGURED_HOST : void 0,
5005
5523
  onChange: change(field),
5006
5524
  onSubmit: () => void submit(field)
5007
5525
  }
@@ -5028,6 +5546,7 @@ var init_screen4 = __esm({
5028
5546
  "use strict";
5029
5547
  init_home_theme();
5030
5548
  init_controls4();
5549
+ init_src3();
5031
5550
  init_logic4();
5032
5551
  init_validate4();
5033
5552
  LABELS = {