@contentful/experience-design-system-cli 2.37.1-dev-build-91b5f8aa.0 → 2.37.1-dev-build-a961485e.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
@@ -3223,9 +3223,11 @@ var init_resolve_session_id = __esm({
3223
3223
  });
3224
3224
 
3225
3225
  // packages/experience-design-system-backend-pipeline/dist/src/persistence/src/credentials/helpers/host-utils.js
3226
+ var DEFAULT_CONFIGURED_HOST;
3226
3227
  var init_host_utils = __esm({
3227
3228
  "packages/experience-design-system-backend-pipeline/dist/src/persistence/src/credentials/helpers/host-utils.js"() {
3228
3229
  "use strict";
3230
+ DEFAULT_CONFIGURED_HOST = "api.contentful.com";
3229
3231
  }
3230
3232
  });
3231
3233
 
@@ -3700,9 +3702,9 @@ var init_utils_gen = __esm({
3700
3702
  config.headers = mergeHeaders(a.headers, b.headers);
3701
3703
  return config;
3702
3704
  };
3703
- mergeHeaders = (...headers2) => {
3705
+ mergeHeaders = (...headers) => {
3704
3706
  const mergedHeaders = new Headers();
3705
- for (const header of headers2) {
3707
+ for (const header of headers) {
3706
3708
  if (!header || typeof header !== "object") {
3707
3709
  continue;
3708
3710
  }
@@ -3949,10 +3951,37 @@ var init_client_gen2 = __esm({
3949
3951
  });
3950
3952
 
3951
3953
  // packages/experience-design-system-client/dist/src/generated/sdk.gen.js
3954
+ var designSystemImportSourcelessPreview, designSystemImportApply, designSystemImportGetOperation;
3952
3955
  var init_sdk_gen = __esm({
3953
3956
  "packages/experience-design-system-client/dist/src/generated/sdk.gen.js"() {
3954
3957
  "use strict";
3955
3958
  init_client_gen2();
3959
+ designSystemImportSourcelessPreview = (options) => {
3960
+ return (options.client ?? client).post({
3961
+ url: "/spaces/{spaceId}/environments/{environmentId}/design_systems/imports/preview",
3962
+ ...options,
3963
+ headers: {
3964
+ "Content-Type": "application/json",
3965
+ ...options.headers
3966
+ }
3967
+ });
3968
+ };
3969
+ designSystemImportApply = (options) => {
3970
+ return (options.client ?? client).post({
3971
+ url: "/spaces/{spaceId}/environments/{environmentId}/design_systems/imports/apply",
3972
+ ...options,
3973
+ headers: {
3974
+ "Content-Type": "application/json",
3975
+ ...options.headers
3976
+ }
3977
+ });
3978
+ };
3979
+ designSystemImportGetOperation = (options) => {
3980
+ return (options.client ?? client).get({
3981
+ url: "/spaces/{spaceId}/environments/{environmentId}/design_systems/imports/apply/{operationId}",
3982
+ ...options
3983
+ });
3984
+ };
3956
3985
  }
3957
3986
  });
3958
3987
 
@@ -3975,9 +4004,13 @@ var init_src2 = __esm({
3975
4004
  });
3976
4005
 
3977
4006
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/constants/api.js
4007
+ var PREVIEW_ERROR_PREFIX, APPLY_ERROR_PREFIX, USER_AGENT;
3978
4008
  var init_api = __esm({
3979
4009
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/constants/api.js"() {
3980
4010
  "use strict";
4011
+ PREVIEW_ERROR_PREFIX = "preview failed:";
4012
+ APPLY_ERROR_PREFIX = "apply failed:";
4013
+ USER_AGENT = "experience-design-system-backend-pipeline";
3981
4014
  }
3982
4015
  });
3983
4016
 
@@ -3990,34 +4023,153 @@ var init_constants5 = __esm({
3990
4023
  });
3991
4024
 
3992
4025
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/http-utils.js
4026
+ function isTransientStatus(status) {
4027
+ return status >= 500 && status <= 599;
4028
+ }
4029
+ function retryAfterMs(response) {
4030
+ const value = response.headers?.get("retry-after")?.trim();
4031
+ if (!value)
4032
+ return void 0;
4033
+ const seconds = Number(value);
4034
+ const delayMs = Number.isFinite(seconds) ? seconds * 1e3 : Date.parse(value) - Date.now();
4035
+ if (!Number.isFinite(delayMs) || delayMs < 0 || delayMs > MAX_RETRY_AFTER_MS)
4036
+ return void 0;
4037
+ return Math.round(delayMs);
4038
+ }
4039
+ function isApsDenialBody(body) {
4040
+ if (!body)
4041
+ return false;
4042
+ try {
4043
+ const parsed = JSON.parse(body);
4044
+ const id = parsed?.sys?.id;
4045
+ return id === "NotFound" || id === "AccessDenied";
4046
+ } catch {
4047
+ return false;
4048
+ }
4049
+ }
4050
+ function stringifyError(error) {
4051
+ return typeof error === "string" ? error : JSON.stringify(error ?? {});
4052
+ }
4053
+ function errorMessage(error) {
4054
+ return error instanceof Error && error.message ? error.message : String(error);
4055
+ }
4056
+ function defaultSleep(delayMs) {
4057
+ return new Promise((resolve2) => setTimeout(resolve2, delayMs));
4058
+ }
4059
+ var MAX_RETRY_AFTER_MS;
3993
4060
  var init_http_utils = __esm({
3994
4061
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/http-utils.js"() {
3995
4062
  "use strict";
4063
+ MAX_RETRY_AFTER_MS = 6e4;
3996
4064
  }
3997
4065
  });
3998
4066
 
3999
4067
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/sanitize-preview.js
4068
+ function sanitizeBreakingChanges(raw) {
4069
+ if (!Array.isArray(raw))
4070
+ return [];
4071
+ const out = [];
4072
+ for (const bc of raw) {
4073
+ if (typeof bc !== "object" || bc === null)
4074
+ continue;
4075
+ const reason = bc.reason;
4076
+ if (typeof reason !== "string")
4077
+ continue;
4078
+ if ("propertyId" in bc && typeof bc.propertyId === "string") {
4079
+ if (PROPERTY_BREAKING_REASONS.has(reason))
4080
+ out.push(bc);
4081
+ continue;
4082
+ }
4083
+ if ("slotId" in bc && typeof bc.slotId === "string") {
4084
+ if (SLOT_BREAKING_REASONS.has(reason))
4085
+ out.push(bc);
4086
+ continue;
4087
+ }
4088
+ }
4089
+ return out;
4090
+ }
4091
+ function sanitizePreviewResponse(res) {
4092
+ for (const item of res.components?.changed ?? []) {
4093
+ const cc = item.changeClassification;
4094
+ if (cc && Array.isArray(cc.breakingChanges)) {
4095
+ cc.breakingChanges = sanitizeBreakingChanges(cc.breakingChanges);
4096
+ }
4097
+ }
4098
+ return res;
4099
+ }
4100
+ var PROPERTY_BREAKING_REASONS, SLOT_BREAKING_REASONS;
4000
4101
  var init_sanitize_preview = __esm({
4001
4102
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/sanitize-preview.js"() {
4002
4103
  "use strict";
4104
+ PROPERTY_BREAKING_REASONS = /* @__PURE__ */ new Set([
4105
+ "removed",
4106
+ "added_required_no_default",
4107
+ "type_changed",
4108
+ "validation_narrowed"
4109
+ ]);
4110
+ SLOT_BREAKING_REASONS = /* @__PURE__ */ new Set(["slot_removed", "slot_allowed_components_narrowed"]);
4003
4111
  }
4004
4112
  });
4005
4113
 
4006
4114
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/host-utils.js
4115
+ function trimTrailingSlashes(value) {
4116
+ return value.replace(/\/+$/, "");
4117
+ }
4118
+ function normalizeHostInput(host) {
4119
+ const value = host?.trim();
4120
+ if (!value)
4121
+ return void 0;
4122
+ return trimTrailingSlashes(value);
4123
+ }
4124
+ function toConfiguredHost2(host) {
4125
+ const normalized = normalizeHostInput(host);
4126
+ if (!normalized)
4127
+ return void 0;
4128
+ return normalized.replace(/^https:\/\//i, "");
4129
+ }
4130
+ function toApiHost2(host) {
4131
+ const normalized = normalizeHostInput(host);
4132
+ if (!normalized)
4133
+ return DEFAULT_API_HOST;
4134
+ if (/^[a-z][a-z\d+\-.]*:\/\//i.test(normalized))
4135
+ return normalized;
4136
+ return `https://${normalized}`;
4137
+ }
4138
+ var DEFAULT_API_HOST;
4007
4139
  var init_host_utils2 = __esm({
4008
4140
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/host-utils.js"() {
4009
4141
  "use strict";
4142
+ DEFAULT_API_HOST = "https://api.contentful.com";
4010
4143
  }
4011
4144
  });
4012
4145
 
4013
4146
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/types/api-error.js
4147
+ var ERROR_BODY_LOG_CAP, ApiError;
4014
4148
  var init_api_error = __esm({
4015
4149
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/types/api-error.js"() {
4016
4150
  "use strict";
4151
+ ERROR_BODY_LOG_CAP = 16384;
4152
+ ApiError = class extends Error {
4153
+ status;
4154
+ body;
4155
+ guidance;
4156
+ constructor(message, status, body, guidance) {
4157
+ super(message);
4158
+ this.status = status;
4159
+ this.body = body;
4160
+ this.guidance = guidance;
4161
+ if (body) {
4162
+ const trimmed = body.length > ERROR_BODY_LOG_CAP ? body.slice(0, ERROR_BODY_LOG_CAP) + "\u2026" : body;
4163
+ this.message = `${message}
4164
+ ${trimmed}`;
4165
+ }
4166
+ }
4167
+ };
4017
4168
  }
4018
4169
  });
4019
4170
 
4020
4171
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/api-client/api-client.js
4172
+ var ApiClient;
4021
4173
  var init_api_client = __esm({
4022
4174
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/api-client/api-client.js"() {
4023
4175
  "use strict";
@@ -4027,6 +4179,161 @@ var init_api_client = __esm({
4027
4179
  init_sanitize_preview();
4028
4180
  init_host_utils2();
4029
4181
  init_api_error();
4182
+ ApiClient = class {
4183
+ host;
4184
+ token;
4185
+ spaceId;
4186
+ environmentId;
4187
+ retry;
4188
+ lastRequestId;
4189
+ constructor(opts) {
4190
+ this.host = toApiHost2(opts.host);
4191
+ this.token = opts.cmaToken;
4192
+ this.spaceId = opts.spaceId;
4193
+ this.environmentId = opts.environmentId;
4194
+ const initialDelayMs = Math.max(0, opts.retry?.initialDelayMs ?? 250);
4195
+ this.retry = {
4196
+ maxAttempts: Math.max(1, Math.floor(opts.retry?.maxAttempts ?? 3)),
4197
+ initialDelayMs,
4198
+ maxDelayMs: Math.max(initialDelayMs, opts.retry?.maxDelayMs ?? 2e3),
4199
+ sleep: opts.retry?.sleep ?? defaultSleep
4200
+ };
4201
+ }
4202
+ getLastRequestId() {
4203
+ return this.lastRequestId;
4204
+ }
4205
+ noteRequestId(response) {
4206
+ const id = response.headers.get("x-contentful-request-id");
4207
+ if (id)
4208
+ this.lastRequestId = id;
4209
+ }
4210
+ headers() {
4211
+ return {
4212
+ Authorization: `Bearer ${this.token}`,
4213
+ "Content-Type": "application/json",
4214
+ "X-Contentful-User-Agent": USER_AGENT
4215
+ };
4216
+ }
4217
+ async requestWithRetry(phase, errorPrefix, makeCall) {
4218
+ for (let attempt = 1; attempt <= this.retry.maxAttempts; attempt++) {
4219
+ let result;
4220
+ try {
4221
+ result = await makeCall();
4222
+ } catch (error) {
4223
+ if (attempt === this.retry.maxAttempts) {
4224
+ const body = `The request failed after ${attempt} attempts because of a network error: ${errorMessage(error)}. Check your connection and try again.`;
4225
+ throw new ApiError(`${errorPrefix} 0`, 0, body);
4226
+ }
4227
+ await this.retry.sleep(Math.min(this.retry.initialDelayMs * 2 ** (attempt - 1), this.retry.maxDelayMs));
4228
+ continue;
4229
+ }
4230
+ if (!isTransientStatus(result.response.status)) {
4231
+ this.noteRequestId(result.response);
4232
+ return result;
4233
+ }
4234
+ if (attempt === this.retry.maxAttempts) {
4235
+ const body = stringifyError(result.error);
4236
+ const guidance = `The ${phase} request failed after ${attempt} attempts because the service remained unavailable. Wait a moment and try again.`;
4237
+ throw new ApiError(`${errorPrefix} ${result.response.status}`, result.response.status, body, guidance);
4238
+ }
4239
+ const backoffMs = Math.min(this.retry.initialDelayMs * 2 ** (attempt - 1), this.retry.maxDelayMs);
4240
+ await this.retry.sleep(retryAfterMs(result.response) ?? backoffMs);
4241
+ }
4242
+ throw new Error("Retry attempts exhausted");
4243
+ }
4244
+ async validateToken() {
4245
+ const res = await fetch(`${this.host}/users/me`, { headers: this.headers() });
4246
+ this.noteRequestId(res);
4247
+ if (res.status === 401) {
4248
+ throw new ApiError("CMA token is invalid or revoked", res.status, await res.text());
4249
+ }
4250
+ if (!res.ok) {
4251
+ throw new ApiError(`unexpected error validating token: ${res.status}`, res.status, await res.text());
4252
+ }
4253
+ await this.checkPreflight();
4254
+ }
4255
+ async checkPreflight() {
4256
+ const url = `${this.host}/spaces/${this.spaceId}/environments/${this.environmentId}/design_systems/preflight`;
4257
+ let res;
4258
+ try {
4259
+ res = await fetch(url, { headers: this.headers() });
4260
+ } catch {
4261
+ return;
4262
+ }
4263
+ this.noteRequestId(res);
4264
+ if (res.ok)
4265
+ return;
4266
+ if (res.status >= 500)
4267
+ return;
4268
+ const body = await res.text();
4269
+ if (res.status === 404 && !isApsDenialBody(body))
4270
+ return;
4271
+ throw new ApiError(`preflight failed: ${res.status}`, res.status, body);
4272
+ }
4273
+ async previewImport(cdf) {
4274
+ const result = await this.requestWithRetry("preview", PREVIEW_ERROR_PREFIX, () => designSystemImportSourcelessPreview({
4275
+ baseUrl: this.host,
4276
+ headers: this.headers(),
4277
+ path: { spaceId: this.spaceId, environmentId: this.environmentId },
4278
+ body: cdf,
4279
+ parseAs: "json"
4280
+ }));
4281
+ if (!result.response.ok) {
4282
+ throw new ApiError(`${PREVIEW_ERROR_PREFIX} ${result.response.status}`, result.response.status, stringifyError(result.error));
4283
+ }
4284
+ return sanitizePreviewResponse(result.data);
4285
+ }
4286
+ async applyImport(cdf, opts) {
4287
+ let result;
4288
+ try {
4289
+ result = await designSystemImportApply({
4290
+ baseUrl: this.host,
4291
+ headers: this.headers(),
4292
+ path: { spaceId: this.spaceId, environmentId: this.environmentId },
4293
+ body: { ...cdf, acknowledgeBreakingChanges: opts.acknowledgeBreakingChanges },
4294
+ parseAs: "json"
4295
+ });
4296
+ } catch (error) {
4297
+ const body = `The apply request was not retried because its outcome is unknown and retrying could start a duplicate operation. Cause: ${errorMessage(error)}`;
4298
+ throw new ApiError(`${APPLY_ERROR_PREFIX} 0`, 0, body);
4299
+ }
4300
+ if (!result.response.ok) {
4301
+ const body = stringifyError(result.error);
4302
+ 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;
4303
+ throw new ApiError(`${APPLY_ERROR_PREFIX} ${result.response.status}`, result.response.status, body, guidance);
4304
+ }
4305
+ this.noteRequestId(result.response);
4306
+ return result.data;
4307
+ }
4308
+ async pollOperation(operationId, opts = {}) {
4309
+ const intervalMs = opts.intervalMs ?? 2e3;
4310
+ const maxIntervalMs = opts.maxIntervalMs ?? Math.round(intervalMs * 2.5);
4311
+ const maxAttempts = opts.maxAttempts ?? 150;
4312
+ const terminalStatuses = /* @__PURE__ */ new Set(["succeeded", "partial", "failed"]);
4313
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
4314
+ const result = await this.requestWithRetry("poll", "poll failed:", () => designSystemImportGetOperation({
4315
+ baseUrl: this.host,
4316
+ headers: this.headers(),
4317
+ path: { spaceId: this.spaceId, environmentId: this.environmentId, operationId },
4318
+ parseAs: "json"
4319
+ }));
4320
+ if (!result.response.ok) {
4321
+ throw new ApiError(`poll failed: ${result.response.status}`, result.response.status, stringifyError(result.error));
4322
+ }
4323
+ const op = result.data;
4324
+ opts.onProgress?.(op);
4325
+ if (terminalStatuses.has(op.sys.status))
4326
+ return op;
4327
+ if (attempt < maxAttempts - 1) {
4328
+ const progress = maxAttempts > 1 ? attempt / (maxAttempts - 1) : 0;
4329
+ const baseDelay = intervalMs + (maxIntervalMs - intervalMs) * progress;
4330
+ const jitter = Math.random() * baseDelay * 0.15;
4331
+ await new Promise((resolve2) => setTimeout(resolve2, baseDelay + jitter));
4332
+ }
4333
+ }
4334
+ throw new Error(`Operation ${operationId} timed out after ${maxAttempts} attempts`);
4335
+ }
4336
+ };
4030
4337
  }
4031
4338
  });
4032
4339
 
@@ -4229,6 +4536,25 @@ var init_annotate_preview2 = __esm({
4229
4536
  });
4230
4537
 
4231
4538
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/parse-binding-diagnostics.js
4539
+ function parseBindingDiagnostics(body) {
4540
+ if (!/binding configurations are invalid|Pointer path does not exist/i.test(body))
4541
+ return null;
4542
+ const locationMatches = [...body.matchAll(/(?:^|\.\s)([A-Za-z0-9_$-]+(?:\s*›\s*[A-Za-z0-9_$-]+){2,})/g)];
4543
+ const location = locationMatches.at(-1)?.[1];
4544
+ const pointerMessage = body.match(/Pointer path does not exist for '\[object Object\]':\s*(.+?)(?=\.\s*Default\s*›|$)/i)?.[1];
4545
+ const graphQlMessage = body.match(/return GraphQL validation error:\s*(.+?)(?=\.\s*Default\s*›|$)/i)?.[1];
4546
+ const heading = body.match(/^(.*?)(?=\.?\s*Pointer path does not exist|\.?\s*Default\s*›)/i)?.[1]?.trim();
4547
+ const diagnostics = [];
4548
+ if (pointerMessage)
4549
+ diagnostics.push({ message: pointerMessage.trim(), ...location ? { path: location } : {} });
4550
+ if (graphQlMessage)
4551
+ diagnostics.push({ message: graphQlMessage.trim(), ...location ? { path: location } : {} });
4552
+ return {
4553
+ code: "BindingValidationFailed",
4554
+ message: heading || "One or more binding configurations are invalid.",
4555
+ ...diagnostics.length > 0 ? { diagnostics } : {}
4556
+ };
4557
+ }
4232
4558
  var init_parse_binding_diagnostics = __esm({
4233
4559
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/parse-binding-diagnostics.js"() {
4234
4560
  "use strict";
@@ -4236,6 +4562,76 @@ var init_parse_binding_diagnostics = __esm({
4236
4562
  });
4237
4563
 
4238
4564
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/helpers.js
4565
+ function asRecord(value) {
4566
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
4567
+ }
4568
+ function displayValue(value) {
4569
+ if (typeof value === "string")
4570
+ return value;
4571
+ if (typeof value === "number" || typeof value === "boolean")
4572
+ return String(value);
4573
+ if (value === null || value === void 0)
4574
+ return null;
4575
+ try {
4576
+ return JSON.stringify(value);
4577
+ } catch {
4578
+ return null;
4579
+ }
4580
+ }
4581
+ function isPathSegment(value) {
4582
+ return typeof value === "string" || typeof value === "number" && Number.isFinite(value);
4583
+ }
4584
+ function formatPath(value) {
4585
+ if (isPathSegment(value))
4586
+ return String(value) ? { path: String(value) } : { path: null };
4587
+ if (Array.isArray(value)) {
4588
+ const parts = value.filter(isPathSegment);
4589
+ return parts.length > 0 ? { path: parts.join(" \u203A ") } : { path: null };
4590
+ }
4591
+ return {};
4592
+ }
4593
+ function componentFromPath(path5) {
4594
+ if (!path5)
4595
+ return void 0;
4596
+ const manifestMatch = path5.match(/manifest:components\/([^/›]+)/);
4597
+ if (manifestMatch?.[1])
4598
+ return manifestMatch[1];
4599
+ const parts = path5.split(/[›/]/).map((part) => part.trim()).filter(Boolean);
4600
+ const componentsIndex = parts.findIndex((part) => part === "components");
4601
+ return componentsIndex === -1 ? void 0 : parts[componentsIndex + 1];
4602
+ }
4603
+ function diagnosticMessage(error) {
4604
+ const candidates = [
4605
+ ["message", error.message],
4606
+ ["details", error.details],
4607
+ ["error", error.error],
4608
+ ["name", error.name]
4609
+ ];
4610
+ for (const [messageSource, value] of candidates) {
4611
+ const message = displayValue(value);
4612
+ if (message !== null)
4613
+ return { message, messageSource };
4614
+ }
4615
+ return { message: "Validation failed" };
4616
+ }
4617
+ function parseObjectLiteralTail(body) {
4618
+ const braceStart = body.lastIndexOf("{");
4619
+ if (braceStart === -1)
4620
+ return null;
4621
+ const tail = body.slice(braceStart);
4622
+ const codeMatch = tail.match(/code:\s*['"]([^'"]+)['"]/);
4623
+ const cycleMatch = tail.match(/cycle:\s*\[\s*([^\]]*)\s*\]/);
4624
+ if (!codeMatch && !cycleMatch)
4625
+ return null;
4626
+ const code = codeMatch ? codeMatch[1] : null;
4627
+ let cycle = null;
4628
+ if (cycleMatch) {
4629
+ cycle = cycleMatch[1].split(",").map((s) => s.trim().replace(/^['"]|['"]$/g, "")).filter((s) => s.length > 0);
4630
+ if (cycle.length === 0)
4631
+ cycle = null;
4632
+ }
4633
+ return { code, cycle };
4634
+ }
4239
4635
  var init_helpers3 = __esm({
4240
4636
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/helpers.js"() {
4241
4637
  "use strict";
@@ -4243,6 +4639,50 @@ var init_helpers3 = __esm({
4243
4639
  });
4244
4640
 
4245
4641
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/parse-json-body.js
4642
+ function parseValidationDiagnostics(details) {
4643
+ if (!Array.isArray(details.errors))
4644
+ return [];
4645
+ const diagnostics = [];
4646
+ for (const rawError of details.errors) {
4647
+ const error = asRecord(rawError);
4648
+ if (!error)
4649
+ continue;
4650
+ const location = formatPath(error.path);
4651
+ const component = displayValue(error.component ?? error.componentName ?? error.componentId) ?? componentFromPath(location.path);
4652
+ diagnostics.push({ ...diagnosticMessage(error), ...location, ...component ? { component } : {} });
4653
+ }
4654
+ return diagnostics;
4655
+ }
4656
+ function parseJsonBody(body) {
4657
+ let parsed;
4658
+ try {
4659
+ parsed = JSON.parse(body);
4660
+ } catch {
4661
+ return null;
4662
+ }
4663
+ const p = asRecord(parsed);
4664
+ if (!p)
4665
+ return null;
4666
+ const details = asRecord(p.details) ?? {};
4667
+ const pick = (k) => p[k] !== void 0 ? p[k] : details[k];
4668
+ const codeRaw = pick("code") ?? asRecord(p.sys)?.id;
4669
+ const messageRaw = pick("message");
4670
+ const cycleRaw = pick("cycle");
4671
+ const out = {};
4672
+ if (typeof codeRaw === "string")
4673
+ out.code = codeRaw;
4674
+ if (typeof messageRaw === "string")
4675
+ out.message = messageRaw;
4676
+ if (Array.isArray(cycleRaw)) {
4677
+ const strs = cycleRaw.filter((x) => typeof x === "string");
4678
+ if (strs.length > 0)
4679
+ out.cycle = strs;
4680
+ }
4681
+ const diagnostics = parseValidationDiagnostics(details);
4682
+ if (diagnostics.length > 0)
4683
+ out.diagnostics = diagnostics;
4684
+ return out;
4685
+ }
4246
4686
  var init_parse_json_body = __esm({
4247
4687
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/parse-json-body.js"() {
4248
4688
  "use strict";
@@ -4251,13 +4691,72 @@ var init_parse_json_body = __esm({
4251
4691
  });
4252
4692
 
4253
4693
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/strip-lambda-log-prefix.js
4694
+ function stripLambdaLogPrefix(body) {
4695
+ return body.replace(LAMBDA_LOG_PREFIX_RE, "").replace(DD_TAG_RE, "").trim();
4696
+ }
4697
+ var LAMBDA_LOG_PREFIX_RE, DD_TAG_RE;
4254
4698
  var init_strip_lambda_log_prefix = __esm({
4255
4699
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/strip-lambda-log-prefix.js"() {
4256
4700
  "use strict";
4701
+ 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*)?/;
4702
+ DD_TAG_RE = /\[dd\.(?:trace_id|span_id)=[^\]]*\]\s*/g;
4257
4703
  }
4258
4704
  });
4259
4705
 
4260
4706
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/parse-edsi-error.js
4707
+ function parseEdsiError(rawInput) {
4708
+ if (!rawInput)
4709
+ return { code: null, message: "", cycle: null, raw: true };
4710
+ const { body, prefix } = splitPhasePrefix(rawInput);
4711
+ const cleaned = stripLambdaLogPrefix(body);
4712
+ const json = parseJsonBody(cleaned) ?? parseJsonBody(body);
4713
+ const bindingFromJson = typeof json?.message === "string" ? parseBindingDiagnostics(json.message) : null;
4714
+ if (bindingFromJson) {
4715
+ return {
4716
+ code: bindingFromJson.code ?? json?.code ?? null,
4717
+ message: bindingFromJson.message ?? cleaned,
4718
+ cycle: null,
4719
+ raw: false,
4720
+ ...bindingFromJson.diagnostics ? { diagnostics: bindingFromJson.diagnostics } : {}
4721
+ };
4722
+ }
4723
+ if (json && (json.code || json.message || json.cycle)) {
4724
+ return {
4725
+ code: json.code ?? null,
4726
+ message: json.message ?? (cleaned || prefix),
4727
+ cycle: json.cycle ?? null,
4728
+ raw: false,
4729
+ ...json.diagnostics ? { diagnostics: json.diagnostics } : {}
4730
+ };
4731
+ }
4732
+ const binding = parseBindingDiagnostics(cleaned);
4733
+ if (binding) {
4734
+ return {
4735
+ code: binding.code ?? null,
4736
+ message: binding.message ?? cleaned,
4737
+ cycle: null,
4738
+ raw: false,
4739
+ ...binding.diagnostics ? { diagnostics: binding.diagnostics } : {}
4740
+ };
4741
+ }
4742
+ const literal2 = parseObjectLiteralTail(cleaned);
4743
+ if (literal2 && (literal2.code || literal2.cycle)) {
4744
+ const braceStart = cleaned.lastIndexOf("{");
4745
+ const head = braceStart === -1 ? cleaned : cleaned.slice(0, braceStart).trim();
4746
+ return { code: literal2.code ?? null, message: head || cleaned, cycle: literal2.cycle ?? null, raw: false };
4747
+ }
4748
+ return { code: null, message: cleaned || prefix || rawInput, cycle: null, raw: true };
4749
+ }
4750
+ function splitPhasePrefix(input) {
4751
+ const nlIndex = input.indexOf("\n");
4752
+ if (nlIndex === -1)
4753
+ return { body: input, prefix: "" };
4754
+ const firstLine = input.slice(0, nlIndex);
4755
+ if (!API_ERROR_PREFIX_RE.test(firstLine))
4756
+ return { body: input, prefix: "" };
4757
+ return { body: input.slice(nlIndex + 1), prefix: firstLine };
4758
+ }
4759
+ var API_ERROR_PREFIX_RE;
4261
4760
  var init_parse_edsi_error = __esm({
4262
4761
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/parse-edsi-error.js"() {
4263
4762
  "use strict";
@@ -4265,10 +4764,51 @@ var init_parse_edsi_error = __esm({
4265
4764
  init_parse_json_body();
4266
4765
  init_helpers3();
4267
4766
  init_strip_lambda_log_prefix();
4767
+ API_ERROR_PREFIX_RE = /^(?:apply|preview|poll) failed: \d+$/;
4268
4768
  }
4269
4769
  });
4270
4770
 
4271
4771
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/format-parsed-edsi-error.js
4772
+ function formatParsedEdsiError(parsed, opts = {}) {
4773
+ const lines = [];
4774
+ if (parsed.code)
4775
+ lines.push(`[${parsed.code}]`);
4776
+ if (parsed.message)
4777
+ lines.push(parsed.message);
4778
+ for (const diagnostic of parsed.diagnostics ?? []) {
4779
+ const context = [
4780
+ diagnostic.component ? `Component: ${diagnostic.component}` : null,
4781
+ diagnostic.path ? `Path: ${diagnostic.path}` : null
4782
+ ].filter(Boolean);
4783
+ lines.push(`- ${diagnostic.message}${context.length > 0 ? ` (${context.join("; ")})` : ""}`);
4784
+ if (diagnostic.path === null) {
4785
+ lines.push(" Location: not provided by the server. Review the submitted CDF file; no component or field was identified.");
4786
+ }
4787
+ if (opts.verbose && diagnostic.messageSource) {
4788
+ lines.push(` Message field: ${diagnostic.messageSource}`);
4789
+ }
4790
+ }
4791
+ if (parsed.code === "BindingValidationFailed") {
4792
+ const location = parsed.diagnostics?.find((d) => d.path)?.path;
4793
+ 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.");
4794
+ }
4795
+ if (parsed.code === "AccessDenied") {
4796
+ lines.push("Next action: this operation requires DesignToken and Component permissions in this environment. Ask a Contentful admin to grant both on your role.");
4797
+ }
4798
+ if (parsed.code === "NotFound") {
4799
+ lines.push("Next action: verify the resource id is correct. If it should exist, your role may lack read permission on DesignToken or Component.");
4800
+ }
4801
+ if (parsed.cycle && parsed.cycle.length > 0) {
4802
+ lines.push(`Cycle: ${parsed.cycle.join(" \u2192 ")} \u2192 ${parsed.cycle[0]}`);
4803
+ lines.push("Break the cycle by removing at least one $allowedComponents entry.");
4804
+ }
4805
+ if (opts.verbose && opts.raw) {
4806
+ lines.push("");
4807
+ lines.push("--- raw ---");
4808
+ lines.push(opts.raw);
4809
+ }
4810
+ return lines.filter(Boolean).join("\n");
4811
+ }
4272
4812
  var init_format_parsed_edsi_error = __esm({
4273
4813
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/format-parsed-edsi-error.js"() {
4274
4814
  "use strict";
@@ -4276,6 +4816,12 @@ var init_format_parsed_edsi_error = __esm({
4276
4816
  });
4277
4817
 
4278
4818
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/format-edsi-error.js
4819
+ function formatEdsiError(raw, opts = {}) {
4820
+ const input = typeof raw === "string" ? raw : displayValue(raw);
4821
+ if (!input)
4822
+ return "";
4823
+ return formatParsedEdsiError(parseEdsiError(input), { ...opts, raw: opts.raw ?? input });
4824
+ }
4279
4825
  var init_format_edsi_error = __esm({
4280
4826
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/format-edsi-error.js"() {
4281
4827
  "use strict";
@@ -4286,6 +4832,14 @@ var init_format_edsi_error = __esm({
4286
4832
  });
4287
4833
 
4288
4834
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/format-api-error.js
4835
+ function formatApiError(error, verbose = false) {
4836
+ const formatted = formatEdsiError(error.body || error.message, { verbose, raw: error.body }) || error.message;
4837
+ const phase = error.message.split("\n", 1)[0];
4838
+ const withPhase = /^(?:apply|preview|poll) failed: \d+$/.test(phase) && formatted !== phase ? `${phase}
4839
+ ${formatted}` : formatted;
4840
+ return error.guidance ? `${withPhase}
4841
+ ${error.guidance}` : withPhase;
4842
+ }
4289
4843
  var init_format_api_error = __esm({
4290
4844
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/helpers/edsi-errors/format-api-error.js"() {
4291
4845
  "use strict";
@@ -4322,6 +4876,9 @@ var init_format_edsi_error2 = __esm({
4322
4876
  });
4323
4877
 
4324
4878
  // packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/controller/errors/format-api-error.js
4879
+ function formatApiError2(request) {
4880
+ return formatApiError(request.error, request.verbose ?? false);
4881
+ }
4325
4882
  var init_format_api_error2 = __esm({
4326
4883
  "packages/experience-design-system-backend-pipeline/dist/src/steps/apply/src/controller/errors/format-api-error.js"() {
4327
4884
  "use strict";
@@ -4831,21 +5388,12 @@ function keyAction2(input, key) {
4831
5388
  function nextField(field) {
4832
5389
  return FIELDS[(FIELDS.indexOf(field) + 1) % FIELDS.length];
4833
5390
  }
4834
- function toConfiguredHost3(host) {
4835
- const value = (host ?? "").trim().replace(/\/+$/, "");
4836
- return value === "" ? DEFAULT_HOST : value.replace(/^https:\/\//i, "");
4837
- }
4838
- function toApiHost3(host) {
4839
- const value = host.trim().replace(/\/+$/, "");
4840
- if (value === "") return `https://${DEFAULT_HOST}`;
4841
- return /^[a-z][a-z\d+\-.]*:\/\//i.test(value) ? value : `https://${value}`;
4842
- }
4843
5391
  function normalize(values) {
4844
5392
  return {
4845
5393
  spaceId: values.spaceId.trim(),
4846
5394
  environmentId: values.environmentId.trim(),
4847
5395
  cmaToken: values.cmaToken.trim(),
4848
- host: toConfiguredHost3(values.host)
5396
+ host: toConfiguredHost2(values.host) ?? DEFAULT_CONFIGURED_HOST
4849
5397
  };
4850
5398
  }
4851
5399
  function missingField(values) {
@@ -4854,12 +5402,12 @@ function missingField(values) {
4854
5402
  function isUnchanged(current, initial) {
4855
5403
  return FIELDS.every((field) => current[field] === initial[field]);
4856
5404
  }
4857
- var FIELDS, DEFAULT_HOST;
5405
+ var FIELDS;
4858
5406
  var init_logic4 = __esm({
4859
5407
  "packages/experience-design-system-cli/src/tui/import/steps/04-credentials/logic.ts"() {
4860
5408
  "use strict";
5409
+ init_src3();
4861
5410
  FIELDS = ["spaceId", "environmentId", "cmaToken", "host"];
4862
- DEFAULT_HOST = "api.contentful.com";
4863
5411
  }
4864
5412
  });
4865
5413
 
@@ -4889,65 +5437,35 @@ var init_controls4 = __esm({
4889
5437
  });
4890
5438
 
4891
5439
  // packages/experience-design-system-cli/src/tui/import/steps/04-credentials/validate.ts
4892
- function headers(token) {
4893
- return { Authorization: `Bearer ${token}`, "X-Contentful-User-Agent": USER_AGENT2 };
4894
- }
4895
- function isApsDenial(body) {
4896
- try {
4897
- const id = JSON.parse(body).sys?.id;
4898
- return id === "NotFound" || id === "AccessDenied";
4899
- } catch {
4900
- return false;
4901
- }
4902
- }
4903
- function messageFrom(body) {
4904
- try {
4905
- const message = JSON.parse(body).message;
4906
- return typeof message === "string" && message !== "" ? message : void 0;
4907
- } catch {
4908
- return void 0;
4909
- }
4910
- }
4911
5440
  async function validateCredentials(values) {
4912
- const base = toApiHost3(values.host);
4913
- let me;
4914
- try {
4915
- me = await fetch(`${base}/users/me`, { headers: headers(values.cmaToken) });
4916
- } catch (error) {
4917
- return { ok: false, error: `Could not reach ${base}: ${error instanceof Error ? error.message : String(error)}` };
4918
- }
4919
- if (me.status === 401) return { ok: false, error: "CMA token is invalid or revoked." };
4920
- if (!me.ok) return { ok: false, error: `Unexpected error validating the token (${me.status}).` };
4921
- let preflight;
5441
+ const host = toApiHost2(values.host);
5442
+ const client2 = new ApiClient({
5443
+ host,
5444
+ spaceId: values.spaceId,
5445
+ environmentId: values.environmentId,
5446
+ cmaToken: values.cmaToken
5447
+ });
4922
5448
  try {
4923
- preflight = await fetch(
4924
- `${base}/spaces/${values.spaceId}/environments/${values.environmentId}/design_systems/preflight`,
4925
- { headers: headers(values.cmaToken) }
4926
- );
4927
- } catch {
5449
+ await client2.validateToken();
4928
5450
  return { ok: true };
5451
+ } catch (error) {
5452
+ return { ok: false, error: toUserError(error, host) };
4929
5453
  }
4930
- if (preflight.ok || preflight.status >= 500) return { ok: true };
4931
- const body = await preflight.text();
4932
- if (preflight.status === 404 && !isApsDenial(body)) return { ok: true };
4933
- const detail = messageFrom(body);
4934
- if (preflight.status === 403) {
4935
- return { ok: false, error: `Access denied. ${detail ?? "Your token cannot write design system components here."}` };
4936
- }
4937
- if (preflight.status === 404) {
4938
- return {
4939
- ok: false,
4940
- error: `Not found. Check the space ID, environment and API host.${detail ? ` (${detail})` : ""}`
4941
- };
5454
+ }
5455
+ function toUserError(error, host) {
5456
+ if (error instanceof ApiError) {
5457
+ if (error.status === 404 && error.message.startsWith("preflight failed:")) {
5458
+ return "Not found. Check the space ID, environment and API host.";
5459
+ }
5460
+ return formatApiError2({ error });
4942
5461
  }
4943
- return { ok: false, error: `Credential check failed (${preflight.status}).${detail ? ` ${detail}` : ""}` };
5462
+ if (error instanceof Error) return `Could not reach ${host}: ${error.message}`;
5463
+ return String(error);
4944
5464
  }
4945
- var USER_AGENT2;
4946
5465
  var init_validate4 = __esm({
4947
5466
  "packages/experience-design-system-cli/src/tui/import/steps/04-credentials/validate.ts"() {
4948
5467
  "use strict";
4949
- init_logic4();
4950
- USER_AGENT2 = "app contentful.experience-design-system-cli";
5468
+ init_src3();
4951
5469
  }
4952
5470
  });
4953
5471
 
@@ -5022,7 +5540,7 @@ function CredentialsScreen({
5022
5540
  value: values[field],
5023
5541
  focus: active === field && !validating,
5024
5542
  mask: field === "cmaToken" ? "\u2022" : void 0,
5025
- placeholder: field === "host" ? DEFAULT_HOST : void 0,
5543
+ placeholder: field === "host" ? DEFAULT_CONFIGURED_HOST : void 0,
5026
5544
  onChange: change(field),
5027
5545
  onSubmit: () => void submit(field)
5028
5546
  }
@@ -5049,6 +5567,7 @@ var init_screen4 = __esm({
5049
5567
  "use strict";
5050
5568
  init_home_theme();
5051
5569
  init_controls4();
5570
+ init_src3();
5052
5571
  init_logic4();
5053
5572
  init_validate4();
5054
5573
  LABELS = {