@contentful/experience-design-system-cli 2.20.1-dev-build-11e15ac.0 → 2.20.1-dev-build-52daaec.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-cli",
3
- "version": "2.20.1-dev-build-11e15ac.0",
3
+ "version": "2.20.1-dev-build-52daaec.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -50,6 +50,7 @@ export declare class ImportApiClient {
50
50
  private headers;
51
51
  private requestWithRetry;
52
52
  validateToken(): Promise<void>;
53
+ checkPreflight(): Promise<void>;
53
54
  previewImport(manifest: ManifestPayload): Promise<ServerPreviewResponse>;
54
55
  applyImport(manifest: ManifestPayload, acknowledgeBreakingChanges: boolean): Promise<ApplyOperationResponse>;
55
56
  pollOperation(operationId: string, opts?: {
@@ -148,6 +148,18 @@ function sanitizePreviewResponse(res) {
148
148
  }
149
149
  return res;
150
150
  }
151
+ function isApsDenialBody(body) {
152
+ if (!body)
153
+ return false;
154
+ try {
155
+ const parsed = JSON.parse(body);
156
+ const id = parsed?.sys?.id;
157
+ return id === 'NotFound' || id === 'AccessDenied';
158
+ }
159
+ catch {
160
+ return false;
161
+ }
162
+ }
151
163
  async function request(url, options) {
152
164
  const headers = {
153
165
  Authorization: `Bearer ${options.token}`,
@@ -267,6 +279,33 @@ export class ImportApiClient {
267
279
  if (!res.ok) {
268
280
  throw new ApiError(`unexpected error validating token: ${res.status}`, res.status, await res.text());
269
281
  }
282
+ await this.checkPreflight();
283
+ }
284
+ // Probe the sources-api preflight endpoint to catch APS-denied users up-front,
285
+ // rather than letting them run a full apply flow that only fails at the write.
286
+ // The endpoint gates Component + DesignToken permissions and returns:
287
+ // 200 → user has apply permissions, proceed
288
+ // 403 { sys.id: AccessDenied } → user lacks write; surface via error-parser
289
+ // 404 { sys.id: NotFound } → user lacks read (APS hides existence)
290
+ // 404 without a NotFound envelope → older backend deployment; treat as pass
291
+ // 5xx / network → backend flake; treat as pass, do not block
292
+ async checkPreflight() {
293
+ const url = `${this.host}/spaces/${this.spaceId}/environments/${this.environmentId}/design_systems/preflight`;
294
+ let res;
295
+ try {
296
+ res = await request(url, { token: this.token });
297
+ }
298
+ catch {
299
+ return; // network error — don't block; the real call will surface it
300
+ }
301
+ if (res.ok)
302
+ return;
303
+ if (res.status >= 500)
304
+ return; // backend flake — don't block
305
+ const body = await res.text();
306
+ if (res.status === 404 && !isApsDenialBody(body))
307
+ return; // legacy backend without the endpoint
308
+ throw new ApiError(`preflight failed: ${res.status}`, res.status, body);
270
309
  }
271
310
  async previewImport(manifest) {
272
311
  const debug = getDebugLogger();
@@ -747,9 +747,13 @@ export function WizardApp({ initialSpaceId = '', initialEnvironmentId = 'master'
747
747
  await advanceAfterCredentialsValidated();
748
748
  }
749
749
  catch (e) {
750
- if (e instanceof ApiError && (e.status === 401 || e.status === 403)) {
750
+ if (e instanceof ApiError && (e.status === 401 || e.status === 403 || e.status === 404)) {
751
751
  cancelGeneratePrefetch();
752
- update({ step: 'credentials', credentialsValidating: false, credentialsError: e.message });
752
+ update({
753
+ step: 'credentials',
754
+ credentialsValidating: false,
755
+ credentialsError: formatApiError(e, process.env['EDSI_VERBOSE_ERRORS'] === '1'),
756
+ });
753
757
  return;
754
758
  }
755
759
  const msg = e instanceof Error ? e.message : 'Credential check failed';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-cli",
3
- "version": "2.20.1-dev-build-11e15ac.0",
3
+ "version": "2.20.1-dev-build-52daaec.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -33,10 +33,10 @@
33
33
  "react": "^18.3.1",
34
34
  "react-devtools-core": "^4.19.1",
35
35
  "react-dom": "^18.3.1",
36
- "@contentful/experience-design-system-client": "2.20.1-dev-build-11e15ac.0",
37
- "@contentful/experience-design-system-generation": "2.20.1-dev-build-11e15ac.0",
38
- "@contentful/experience-design-system-types": "2.20.1-dev-build-11e15ac.0",
39
- "@contentful/experience-design-system-extraction": "2.20.1-dev-build-11e15ac.0"
36
+ "@contentful/experience-design-system-client": "2.20.1-dev-build-52daaec.0",
37
+ "@contentful/experience-design-system-extraction": "2.20.1-dev-build-52daaec.0",
38
+ "@contentful/experience-design-system-generation": "2.20.1-dev-build-52daaec.0",
39
+ "@contentful/experience-design-system-types": "2.20.1-dev-build-52daaec.0"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@tsconfig/node24": "^24.0.4",