@contentful/experience-design-system-cli 2.35.1-dev-build-c4a4d1cd.0 → 2.35.1-dev-build-57c625cc.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.35.1-dev-build-c4a4d1cd.0",
3
+ "version": "2.35.1-dev-build-57c625cc.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -2011,8 +2011,8 @@ function deleteRawTokensForSession(db, sessionId2) {
2011
2011
  }
2012
2012
  function createRawTokenGroups(db, sessionId2, groups) {
2013
2013
  const insertGroup = db.prepare(`INSERT INTO raw_token_groups (session_id, path, description) VALUES (?, ?, ?)`);
2014
- for (const group of groups) {
2015
- insertGroup.run(sessionId2, group.path, group.$description ?? null);
2014
+ for (const group2 of groups) {
2015
+ insertGroup.run(sessionId2, group2.path, group2.$description ?? null);
2016
2016
  }
2017
2017
  }
2018
2018
  function createRawTokens(db, sessionId2, tokens) {
@@ -6891,24 +6891,24 @@ function parseEdsiError(rawInput) {
6891
6891
  }
6892
6892
  }
6893
6893
  const cleaned = stripLambdaLogPrefix(body);
6894
- const json = parseJsonBody(cleaned) ?? parseJsonBody(body);
6895
- const bindingFromJson = typeof json?.message === "string" ? parseBindingDiagnostics(json.message) : null;
6894
+ const json2 = parseJsonBody(cleaned) ?? parseJsonBody(body);
6895
+ const bindingFromJson = typeof json2?.message === "string" ? parseBindingDiagnostics(json2.message) : null;
6896
6896
  if (bindingFromJson) {
6897
6897
  return {
6898
- code: bindingFromJson.code ?? json?.code ?? null,
6898
+ code: bindingFromJson.code ?? json2?.code ?? null,
6899
6899
  message: bindingFromJson.message ?? cleaned,
6900
6900
  cycle: null,
6901
6901
  raw: false,
6902
6902
  ...bindingFromJson.diagnostics ? { diagnostics: bindingFromJson.diagnostics } : {}
6903
6903
  };
6904
6904
  }
6905
- if (json && (json.code || json.message || json.cycle)) {
6905
+ if (json2 && (json2.code || json2.message || json2.cycle)) {
6906
6906
  return {
6907
- code: json.code ?? null,
6908
- message: json.message ?? (cleaned || prefix),
6909
- cycle: json.cycle ?? null,
6907
+ code: json2.code ?? null,
6908
+ message: json2.message ?? (cleaned || prefix),
6909
+ cycle: json2.cycle ?? null,
6910
6910
  raw: false,
6911
- ...json.diagnostics ? { diagnostics: json.diagnostics } : {}
6911
+ ...json2.diagnostics ? { diagnostics: json2.diagnostics } : {}
6912
6912
  };
6913
6913
  }
6914
6914
  const binding = parseBindingDiagnostics(cleaned);
@@ -8448,8 +8448,8 @@ async function resolveSession(sessionFlag, command) {
8448
8448
  }
8449
8449
  function rebuildDTCGTree(groups, tokens) {
8450
8450
  const root = {};
8451
- for (const group of groups) {
8452
- const segments = group.path.split(".");
8451
+ for (const group2 of groups) {
8452
+ const segments = group2.path.split(".");
8453
8453
  let node = root;
8454
8454
  for (const seg of segments) {
8455
8455
  if (typeof node[seg] !== "object" || node[seg] === null) {
@@ -8457,8 +8457,8 @@ function rebuildDTCGTree(groups, tokens) {
8457
8457
  }
8458
8458
  node = node[seg];
8459
8459
  }
8460
- if (group.$description) {
8461
- node["$description"] = group.$description;
8460
+ if (group2.$description) {
8461
+ node["$description"] = group2.$description;
8462
8462
  }
8463
8463
  }
8464
8464
  for (const token of tokens) {
@@ -9204,18 +9204,27 @@ var init_run_teaser = __esm({
9204
9204
  // packages/experience-design-system-cli-legacy/src/lib/push-debug-log.ts
9205
9205
  import { existsSync as existsSync3, mkdirSync as mkdirSync3, readdirSync, writeFileSync } from "node:fs";
9206
9206
  import { join as join10 } from "node:path";
9207
- function scrub(_key, value) {
9208
- if (/^cma_?token$/i.test(_key))
9207
+ function scrub(key, value) {
9208
+ if (/^cma_?token$/i.test(key)) {
9209
9209
  return typeof value === "string" && value ? `[present, ${value.length} chars]` : "[not set]";
9210
+ }
9210
9211
  if (typeof value === "string" && SECRET_VALUE.test(value)) return "[redacted]";
9211
9212
  return value;
9212
9213
  }
9213
- function pad(n) {
9214
- return String(n).padStart(2, "0");
9214
+ function json(value) {
9215
+ const text = JSON.stringify(value, scrub, 2) ?? "null";
9216
+ return text.length > MAX_BLOCK_CHARS ? `${text.slice(0, MAX_BLOCK_CHARS)}
9217
+ \u2026 truncated, ${text.length - MAX_BLOCK_CHARS} more characters` : text;
9218
+ }
9219
+ function pad(n, width = 2) {
9220
+ return String(n).padStart(width, "0");
9215
9221
  }
9216
9222
  function datePrefix(now) {
9217
9223
  return `${pad(now.getMonth() + 1)}-${pad(now.getDate())}-${now.getFullYear()}`;
9218
9224
  }
9225
+ function clock(now) {
9226
+ return `${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}.${pad(now.getMilliseconds(), 3)}`;
9227
+ }
9219
9228
  function nextFilename(dir, now) {
9220
9229
  const today = datePrefix(now);
9221
9230
  const pattern = new RegExp(`^${today}-push-attempt-(\\d+)\\.md$`);
@@ -9226,59 +9235,176 @@ function nextFilename(dir, now) {
9226
9235
  }, 0);
9227
9236
  return `${today}-push-attempt-${max + 1}.md`;
9228
9237
  }
9229
- function render2(runId, inputs, outputs, status, durationMs, now) {
9230
- return `# Debug Log
9238
+ function entityName(entry) {
9239
+ if (typeof entry === "string") return entry;
9240
+ if (entry && typeof entry === "object") {
9241
+ const record = entry;
9242
+ for (const field of ["key", "name", "$name", "id"]) {
9243
+ if (typeof record[field] === "string") return record[field];
9244
+ }
9245
+ const current = record["current"];
9246
+ if (current && typeof current === "object" && typeof current["name"] === "string") {
9247
+ return current["name"];
9248
+ }
9249
+ }
9250
+ return "unknown";
9251
+ }
9252
+ function group(diff) {
9253
+ return {
9254
+ new: diff.new.map(entityName),
9255
+ changed: diff.changed.map((entry) => {
9256
+ const breaking = entry && typeof entry === "object" && entry.changeClassification?.classification === "breaking";
9257
+ return breaking ? `${entityName(entry)} (breaking)` : entityName(entry);
9258
+ }),
9259
+ unchanged: diff.unchanged,
9260
+ removed: diff.removed.map(entityName)
9261
+ };
9262
+ }
9263
+ function summarizePreview(preview) {
9264
+ return { components: group(preview.components), tokens: group(preview.tokens) };
9265
+ }
9266
+ function summarizeCdf(cdf) {
9267
+ return Object.entries(cdf).filter(([key]) => !key.startsWith("$") && key !== "allowDeletions").map(([key, value]) => {
9268
+ const entry = value ?? {};
9269
+ const properties = entry["$properties"];
9270
+ const slots = entry["$slots"];
9271
+ return {
9272
+ name: key,
9273
+ type: entry["$type"],
9274
+ properties: properties && typeof properties === "object" ? Object.keys(properties) : [],
9275
+ slots: slots && typeof slots === "object" ? Object.keys(slots) : []
9276
+ };
9277
+ });
9278
+ }
9279
+ function renderEvents(events) {
9280
+ if (events.length === 0) return "_Nothing recorded yet._";
9281
+ return events.map((event, index) => {
9282
+ const note = event.note ? ` \u2014 ${event.note}` : "";
9283
+ const request2 = event.requestId ? ` _(request ${event.requestId})_` : "";
9284
+ return `${index + 1}. \`${clock(event.at)}\` (+${event.sinceStartMs}ms) **${event.title}**${note}${request2}`;
9285
+ }).join("\n");
9286
+ }
9287
+ function renderDetails(events) {
9288
+ const withData = events.map((event, index) => ({ event, index })).filter(({ event }) => event.data && Object.keys(event.data).length > 0);
9289
+ if (withData.length === 0) return "";
9290
+ return withData.map(
9291
+ ({ event, index }) => `<details>
9292
+ <summary>${index + 1}. ${event.title}</summary>
9293
+
9294
+ \`\`\`json
9295
+ ${json(event.data)}
9296
+ \`\`\`
9297
+
9298
+ </details>`
9299
+ ).join("\n\n");
9300
+ }
9301
+ function render2(runId, inputs, events, startedAt, result, durationMs) {
9302
+ const requestIds = [...new Set(events.map((event) => event.requestId).filter(Boolean))];
9303
+ const text = (field) => String(inputs[field] ?? "\u2014");
9304
+ const details = renderDetails(events);
9305
+ return `# Push to Contentful \u2014 debug log
9306
+
9307
+ ## Summary
9308
+
9309
+ | | |
9310
+ |---|---|
9311
+ | **Result** | ${OUTCOME_LABEL[result.outcome]} |
9312
+ | **What happened** | ${result.summary} |
9313
+ | **Space / environment** | \`${text("space_id")}\` / \`${text("environment_id")}\` |
9314
+ | **Host** | ${text("host")} |
9315
+ | **Started** | ${startedAt.toISOString()} |
9316
+ | **Duration** | ${durationMs}ms |
9317
+ | **Request IDs** | ${requestIds.length > 0 ? requestIds.map((id) => `\`${id}\``).join(", ") : "\u2014"} |
9318
+ | **CLI / runtime** | ${cliVersion()} \xB7 ${process.platform} \xB7 Node ${process.version} |
9319
+ | **Run ID** | ${runId} |
9320
+
9321
+ ## Timeline
9231
9322
 
9232
- - Run ID: ${runId}
9233
- - Flow: import
9234
- - Step: 01 - push
9235
- - Menu option: Push
9236
- - Date: ${now.toISOString()}
9237
- - CLI version: ${cliVersion()}
9238
- - Platform: ${process.platform} / Node ${process.version}
9239
- - Duration on screen: ${durationMs}ms
9240
- - Status: ${status}
9241
- - Exit method: completed
9323
+ ${renderEvents(events)}
9242
9324
 
9243
9325
  ## Inputs
9326
+
9244
9327
  \`\`\`json
9245
- ${JSON.stringify(inputs, scrub, 2)}
9328
+ ${json(inputs)}
9246
9329
  \`\`\`
9247
9330
 
9248
- ## Outputs
9331
+ ## Result
9332
+
9249
9333
  \`\`\`json
9250
- ${JSON.stringify(outputs, scrub, 2)}
9334
+ ${json({ outcome: result.outcome, summary: result.summary, ...result.details ?? {} })}
9251
9335
  \`\`\`
9252
- `;
9336
+ ${details ? `
9337
+ ## Details
9338
+
9339
+ ${details}
9340
+ ` : ""}`;
9253
9341
  }
9254
9342
  function startPushDebugRun(inputs) {
9255
9343
  const sessionDir = process.env[DEBUG_SESSION_DIR_ENV];
9256
9344
  if (!sessionDir) return NOOP_RUN;
9257
- const startedAt = Date.now();
9345
+ const startedAt = /* @__PURE__ */ new Date();
9346
+ const runId = `${startedAt.getFullYear()}${pad(startedAt.getMonth() + 1)}${pad(startedAt.getDate())}-${pad(startedAt.getHours())}${pad(startedAt.getMinutes())}${pad(startedAt.getSeconds())}`;
9347
+ const events = [];
9348
+ let result = {
9349
+ outcome: "in-progress",
9350
+ summary: "The push started but no final result was recorded."
9351
+ };
9258
9352
  let finished = false;
9259
- return {
9260
- finish(outputs, status) {
9261
- if (finished) return;
9262
- finished = true;
9263
- try {
9264
- const now = /* @__PURE__ */ new Date();
9353
+ let path;
9354
+ const flush = () => {
9355
+ try {
9356
+ if (!path) {
9265
9357
  const dir = join10(sessionDir, "import");
9266
9358
  mkdirSync3(dir, { recursive: true });
9267
- const runId = `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
9268
- const content = render2(runId, inputs, outputs, status, Date.now() - startedAt, now);
9269
- writeFileSync(join10(dir, nextFilename(dir, now)), content, { mode: 384 });
9270
- } catch {
9359
+ path = join10(dir, nextFilename(dir, startedAt));
9271
9360
  }
9361
+ writeFileSync(path, render2(runId, inputs, events, startedAt, result, Date.now() - startedAt.getTime()), {
9362
+ mode: 384
9363
+ });
9364
+ } catch {
9365
+ }
9366
+ };
9367
+ flush();
9368
+ return {
9369
+ event(title, options = {}) {
9370
+ if (finished) return;
9371
+ const at = /* @__PURE__ */ new Date();
9372
+ events.push({ at, sinceStartMs: at.getTime() - startedAt.getTime(), title, ...options });
9373
+ flush();
9374
+ },
9375
+ finish(final) {
9376
+ if (finished) return;
9377
+ finished = true;
9378
+ result = final;
9379
+ const at = /* @__PURE__ */ new Date();
9380
+ events.push({
9381
+ at,
9382
+ sinceStartMs: at.getTime() - startedAt.getTime(),
9383
+ title: OUTCOME_LABEL[final.outcome].replace(/^\S+\s/, ""),
9384
+ note: final.summary
9385
+ });
9386
+ flush();
9272
9387
  }
9273
9388
  };
9274
9389
  }
9275
- var DEBUG_SESSION_DIR_ENV, NOOP_RUN, SECRET_VALUE;
9390
+ var DEBUG_SESSION_DIR_ENV, NOOP_RUN, OUTCOME_LABEL, MAX_BLOCK_CHARS, SECRET_VALUE;
9276
9391
  var init_push_debug_log = __esm({
9277
9392
  "packages/experience-design-system-cli-legacy/src/lib/push-debug-log.ts"() {
9278
9393
  "use strict";
9279
9394
  init_client();
9280
9395
  DEBUG_SESSION_DIR_ENV = "EDS_DEBUG_SESSION_DIR";
9281
- NOOP_RUN = { finish: () => void 0 };
9396
+ NOOP_RUN = { event: () => void 0, finish: () => void 0 };
9397
+ OUTCOME_LABEL = {
9398
+ "in-progress": "\u23F3 In progress (the process ended before the push finished)",
9399
+ pushed: "\u2705 Pushed",
9400
+ partial: "\u26A0\uFE0F Partly pushed (some items failed)",
9401
+ failed: "\u274C Push failed",
9402
+ "preview-failed": "\u274C Preview failed (nothing was sent to apply)",
9403
+ "nothing-to-push": "\u2139\uFE0F Nothing to push (the server says the space already matches)",
9404
+ skipped: "\u23ED\uFE0F Skipped",
9405
+ superseded: "\u21A9\uFE0F Superseded by a newer attempt"
9406
+ };
9407
+ MAX_BLOCK_CHARS = 1e5;
9282
9408
  SECRET_VALUE = /CFPAT-[A-Za-z0-9_-]{20,}|^Bearer\s+\S+/;
9283
9409
  }
9284
9410
  });
@@ -20208,17 +20334,17 @@ function buildCycleUnits(slotCycles) {
20208
20334
  const groups = /* @__PURE__ */ new Map();
20209
20335
  for (const node of parent.keys()) {
20210
20336
  const root = find(node);
20211
- let group = groups.get(root);
20212
- if (!group) {
20213
- group = /* @__PURE__ */ new Set();
20214
- groups.set(root, group);
20337
+ let group2 = groups.get(root);
20338
+ if (!group2) {
20339
+ group2 = /* @__PURE__ */ new Set();
20340
+ groups.set(root, group2);
20215
20341
  }
20216
- group.add(node);
20342
+ group2.add(node);
20217
20343
  }
20218
20344
  const out = /* @__PURE__ */ new Map();
20219
- for (const group of groups.values()) {
20220
- for (const node of group) {
20221
- out.set(node, group);
20345
+ for (const group2 of groups.values()) {
20346
+ for (const node of group2) {
20347
+ out.set(node, group2);
20222
20348
  }
20223
20349
  }
20224
20350
  return out;
@@ -21712,10 +21838,10 @@ function swapValues(values, firstIndex, secondIndex) {
21712
21838
  [next[firstIndex], next[secondIndex]] = [next[secondIndex], next[firstIndex]];
21713
21839
  return next;
21714
21840
  }
21715
- function parseToState(json) {
21841
+ function parseToState(json2) {
21716
21842
  let parsed;
21717
21843
  try {
21718
- parsed = JSON.parse(json);
21844
+ parsed = JSON.parse(json2);
21719
21845
  } catch (e) {
21720
21846
  return {
21721
21847
  state: { componentDescription: "", props: [], slots: [] },
@@ -22568,11 +22694,11 @@ function FieldEditor({
22568
22694
  setEditorState(next);
22569
22695
  onChange(serializeState(next, value));
22570
22696
  };
22571
- const canonicalize = React14.useCallback((json) => {
22697
+ const canonicalize = React14.useCallback((json2) => {
22572
22698
  try {
22573
- return JSON.stringify(JSON.parse(json));
22699
+ return JSON.stringify(JSON.parse(json2));
22574
22700
  } catch {
22575
- return `__unparseable__:${json}`;
22701
+ return `__unparseable__:${json2}`;
22576
22702
  }
22577
22703
  }, []);
22578
22704
  const initialStateRef = React14.useRef(initialState);
@@ -23146,14 +23272,14 @@ function FieldEditor({
23146
23272
  })();
23147
23273
  const rows = [];
23148
23274
  rows.push({ kind: "component-description" });
23149
- for (const group of propGroups.filter((candidate) => candidate.kind !== "hidden")) {
23150
- if (group.indexes.length === 0) continue;
23275
+ for (const group2 of propGroups.filter((candidate) => candidate.kind !== "hidden")) {
23276
+ if (group2.indexes.length === 0) continue;
23151
23277
  rows.push({
23152
23278
  kind: "header",
23153
- label: `${group.label} (${group.indexes.length}) `,
23154
- section: group.kind
23279
+ label: `${group2.label} (${group2.indexes.length}) `,
23280
+ section: group2.kind
23155
23281
  });
23156
- group.indexes.forEach((idx) => rows.push({ kind: "prop", idx }));
23282
+ group2.indexes.forEach((idx) => rows.push({ kind: "prop", idx }));
23157
23283
  }
23158
23284
  if (slots.length > 0) {
23159
23285
  rows.push({
@@ -23163,7 +23289,7 @@ function FieldEditor({
23163
23289
  });
23164
23290
  slots.forEach((_, i) => rows.push({ kind: "slot", idx: i }));
23165
23291
  }
23166
- const hiddenGroup = propGroups.find((group) => group.kind === "hidden");
23292
+ const hiddenGroup = propGroups.find((group2) => group2.kind === "hidden");
23167
23293
  if (hiddenGroup && hiddenGroup.indexes.length > 0) {
23168
23294
  rows.push({
23169
23295
  kind: "header",
@@ -27287,6 +27413,7 @@ function WizardApp({
27287
27413
  tokensPath: ""
27288
27414
  });
27289
27415
  const allowEmptyDeleteAllRef = useRef10(false);
27416
+ const pushDebugRef = useRef10(null);
27290
27417
  const generateChildRef = useRef10(null);
27291
27418
  const generationCachePreflightRef = useRef10(null);
27292
27419
  const selectionToReviewStartedAtRef = useRef10(null);
@@ -28341,12 +28468,30 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
28341
28468
  void runSaveAndPush();
28342
28469
  };
28343
28470
  const runPreview = async (extractSessionId, tokensPath, spaceId, environmentId, cmaToken, host2) => {
28471
+ const resolvedHost = resolveWizardHost(host2);
28472
+ pushDebugRef.current?.finish({
28473
+ outcome: "superseded",
28474
+ summary: "A new push attempt started before this one finished."
28475
+ });
28476
+ const pushDebug = startPushDebugRun({
28477
+ space_id: spaceId,
28478
+ environment_id: environmentId,
28479
+ host: resolvedHost,
28480
+ cma_token: cmaToken,
28481
+ extract_session_id: extractSessionId,
28482
+ tokens_file: tokensPath || null,
28483
+ delete_everything_not_listed: allowEmptyDeleteAllRef.current
28484
+ });
28485
+ pushDebugRef.current = pushDebug;
28344
28486
  if (shouldBypassPreview(state)) {
28487
+ pushDebug.finish({
28488
+ outcome: "skipped",
28489
+ summary: "Credentials were skipped, so nothing is previewed or pushed. Files were saved only."
28490
+ });
28345
28491
  update(buildSkippedPreviewTransition());
28346
28492
  return;
28347
28493
  }
28348
28494
  update({ step: "previewing" });
28349
- const resolvedHost = resolveWizardHost(host2);
28350
28495
  try {
28351
28496
  const client2 = new ImportApiClient({
28352
28497
  cmaToken,
@@ -28354,6 +28499,7 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
28354
28499
  environmentId,
28355
28500
  host: resolvedHost
28356
28501
  });
28502
+ pushDebug.event("Preview started", { note: `POST ${resolvedHost}/\u2026/design_systems/imports/preview` });
28357
28503
  let components = [];
28358
28504
  if (extractSessionId) {
28359
28505
  const db = openPipelineDb();
@@ -28369,7 +28515,16 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
28369
28515
  tokens = await readTokensFromPath("tokens", tokensPath);
28370
28516
  }
28371
28517
  let cdf = buildCDF3(components, toCDFTokens(tokens), { deleteAll: allowEmptyDeleteAllRef.current });
28518
+ pushDebug.event("Built the CDF to send", {
28519
+ note: `${summarizeCdf(cdf).length} entries`,
28520
+ data: { entries: summarizeCdf(cdf), tokens_loaded: tokens.length }
28521
+ });
28372
28522
  let preview = await client2.previewImport(cdf);
28523
+ pushDebug.event("Server previewed the CDF", {
28524
+ note: "what the server would create, change, leave alone or remove",
28525
+ data: summarizePreview(preview),
28526
+ requestId: client2.getLastRequestId()
28527
+ });
28373
28528
  if (extractSessionId) {
28374
28529
  let needsRepreview = false;
28375
28530
  const db = openPipelineDb();
@@ -28389,15 +28544,27 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
28389
28544
  if (seededDefaults > 0) needsRepreview = true;
28390
28545
  }
28391
28546
  if (needsRepreview) {
28547
+ pushDebug.event("Re-previewing", {
28548
+ note: "the server listed components as removed or changed that exist locally, so defaults were filled in"
28549
+ });
28392
28550
  components = loadCDFComponents(db, extractSessionId);
28393
28551
  cdf = buildCDF3(components, toCDFTokens(tokens), { deleteAll: allowEmptyDeleteAllRef.current });
28394
28552
  preview = await client2.previewImport(cdf);
28553
+ pushDebug.event("Server previewed the updated CDF", {
28554
+ data: summarizePreview(preview),
28555
+ requestId: client2.getLastRequestId()
28556
+ });
28395
28557
  }
28396
28558
  } finally {
28397
28559
  db.close();
28398
28560
  }
28399
28561
  }
28400
28562
  if (isEmptyPreview(preview)) {
28563
+ pushDebug.finish({
28564
+ outcome: "nothing-to-push",
28565
+ summary: "The server says every component and token in the CDF already matches what is in this space, so no apply request was sent. If the space looks empty, check that this is the space and environment you are viewing.",
28566
+ details: { preview: summarizePreview(preview), request_id: client2.getLastRequestId() }
28567
+ });
28401
28568
  update({
28402
28569
  step: "done",
28403
28570
  serverPreview: preview,
@@ -28409,6 +28576,9 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
28409
28576
  });
28410
28577
  return;
28411
28578
  }
28579
+ pushDebug.event("Waiting for confirmation", {
28580
+ note: "the preview shows changes, so the wizard asks before pushing"
28581
+ });
28412
28582
  update({
28413
28583
  step: "preview-gate",
28414
28584
  serverPreview: preview,
@@ -28417,6 +28587,11 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
28417
28587
  ...clearedValidationErrorState()
28418
28588
  });
28419
28589
  } catch (e) {
28590
+ pushDebug.finish({
28591
+ outcome: "preview-failed",
28592
+ summary: e instanceof ApiError ? `The preview request was rejected with HTTP ${e.status}.` : `The preview failed before the server answered: ${e instanceof Error ? e.message : String(e)}`,
28593
+ details: e instanceof ApiError ? { status: e.status, body: (e.body ?? "").slice(0, 4e3) } : { error: e instanceof Error ? e.message : String(e) }
28594
+ });
28420
28595
  if (e instanceof ApiError) {
28421
28596
  if (e.status === 401 || e.status === 403) {
28422
28597
  let bodyMsg = "";
@@ -28479,7 +28654,18 @@ If using a custom host configuration, make sure the space exists on that host.`
28479
28654
  }
28480
28655
  };
28481
28656
  const runPush = async (cdf, spaceId, environmentId, cmaToken, host2, acknowledgeBreakingChanges, preview) => {
28657
+ const pushDebug = pushDebugRef.current ?? startPushDebugRun({
28658
+ space_id: spaceId,
28659
+ environment_id: environmentId,
28660
+ host: resolveWizardHost(host2),
28661
+ cma_token: cmaToken
28662
+ });
28663
+ pushDebugRef.current = pushDebug;
28482
28664
  if (shouldRefusePush(state)) {
28665
+ pushDebug.finish({
28666
+ outcome: "skipped",
28667
+ summary: "Credentials were skipped, so the push was refused. Files were saved only."
28668
+ });
28483
28669
  update(buildSkippedPushTransition());
28484
28670
  return;
28485
28671
  }
@@ -28487,6 +28673,11 @@ If using a custom host configuration, make sure the space exists on that host.`
28487
28673
  const hasComponentChanges = preview.components.new.length > 0 || preview.components.changed.length > 0 || preview.components.removed.length > 0;
28488
28674
  const hasTokenChanges = preview.tokens.new.length > 0 || preview.tokens.changed.length > 0 || preview.tokens.removed.length > 0;
28489
28675
  if (!hasComponentChanges && !hasTokenChanges) {
28676
+ pushDebug.finish({
28677
+ outcome: "nothing-to-push",
28678
+ summary: "The preview had no new, changed or removed items, so no apply request was sent.",
28679
+ details: { preview: summarizePreview(preview) }
28680
+ });
28490
28681
  update({
28491
28682
  step: "done",
28492
28683
  pushResult: {
@@ -28499,6 +28690,11 @@ If using a custom host configuration, make sure the space exists on that host.`
28499
28690
  }
28500
28691
  const cycles = detectSlotCycles(extractComponents(cdf));
28501
28692
  if (cycles.length > 0) {
28693
+ pushDebug.finish({
28694
+ outcome: "failed",
28695
+ summary: "The push was blocked locally because components slot each other in a cycle.",
28696
+ details: { cycles: formatSlotCycleReport(cycles) }
28697
+ });
28502
28698
  update({
28503
28699
  step: "error",
28504
28700
  errorStep: "apply",
@@ -28509,6 +28705,11 @@ If using a custom host configuration, make sure the space exists on that host.`
28509
28705
  }
28510
28706
  const unresolvedSlotReferences = validateSlotReferences2(extractComponents(cdf));
28511
28707
  if (unresolvedSlotReferences.length > 0) {
28708
+ pushDebug.finish({
28709
+ outcome: "failed",
28710
+ summary: "The push was blocked locally because a slot refers to a component that is not in the CDF.",
28711
+ details: { unresolved: formatUnresolvedSlotReferences(unresolvedSlotReferences) }
28712
+ });
28512
28713
  update({
28513
28714
  step: "error",
28514
28715
  errorStep: "apply",
@@ -28518,27 +28719,13 @@ If using a custom host configuration, make sure the space exists on that host.`
28518
28719
  return;
28519
28720
  }
28520
28721
  update({ step: "pushing", pushProgress: null, errorAllowBreakingChangeAcknowledgment: false });
28521
- const cdfEntries = Object.entries(cdf).filter(([key]) => !key.startsWith("$") && key !== "allowDeletions");
28522
- const pushDebug = startPushDebugRun({
28523
- space_id: spaceId,
28524
- environment_id: environmentId,
28525
- host: resolveWizardHost(host2),
28526
- cma_token: cmaToken,
28527
- acknowledge_breaking_changes: acknowledgeBreakingChanges,
28528
- cdf_keys: cdfEntries.map(([key]) => key),
28529
- cdf_entry_count: cdfEntries.length,
28530
- preview: preview ? {
28531
- components: {
28532
- new: preview.components.new.length,
28533
- changed: preview.components.changed.length,
28534
- removed: preview.components.removed.length
28535
- },
28536
- tokens: {
28537
- new: preview.tokens.new.length,
28538
- changed: preview.tokens.changed.length,
28539
- removed: preview.tokens.removed.length
28540
- }
28541
- } : null
28722
+ pushDebug.event("Apply started", {
28723
+ note: `POST ${resolveWizardHost(host2)}/\u2026/design_systems/imports/apply`,
28724
+ data: {
28725
+ acknowledge_breaking_changes: acknowledgeBreakingChanges,
28726
+ sending: summarizeCdf(cdf),
28727
+ expected: preview ? summarizePreview(preview) : null
28728
+ }
28542
28729
  });
28543
28730
  try {
28544
28731
  const resolvedHost = resolveWizardHost(host2);
@@ -28549,6 +28736,11 @@ If using a custom host configuration, make sure the space exists on that host.`
28549
28736
  host: resolvedHost
28550
28737
  });
28551
28738
  let operation = await client2.applyImport(cdf, { acknowledgeBreakingChanges });
28739
+ pushDebug.event("Server accepted the apply request", {
28740
+ note: `operation ${operation.sys.id} is ${operation.sys.status}`,
28741
+ data: { operation_id: operation.sys.id, status: operation.sys.status, summary: operation.summary },
28742
+ requestId: client2.getLastRequestId()
28743
+ });
28552
28744
  try {
28553
28745
  logStep({
28554
28746
  applyResponse: {
@@ -28565,9 +28757,15 @@ If using a custom host configuration, make sure the space exists on that host.`
28565
28757
  pushProgress: { kind: "queued", operationId: operation.sys.id }
28566
28758
  });
28567
28759
  let pollCount = 0;
28760
+ let lastPolledStatus = "";
28568
28761
  operation = await client2.pollOperation(operation.sys.id, {
28569
28762
  onProgress: (op) => {
28570
28763
  pollCount++;
28764
+ const polled = `${op.sys.status} ${op.summary ? `${op.summary.total - op.summary.pending}/${op.summary.total}` : ""}`;
28765
+ if (polled !== lastPolledStatus) {
28766
+ lastPolledStatus = polled;
28767
+ pushDebug.event("Operation status changed", { note: polled.trim(), requestId: client2.getLastRequestId() });
28768
+ }
28571
28769
  const s = op.summary;
28572
28770
  if (s) {
28573
28771
  const done = s.total - s.pending;
@@ -28672,27 +28870,29 @@ If using a custom host configuration, make sure the space exists on that host.`
28672
28870
  );
28673
28871
  }
28674
28872
  }
28675
- pushDebug.finish(
28676
- {
28873
+ const failedItems = items.filter((item) => item.status === "failed");
28874
+ const pushedCount = items.filter((item) => item.status === "succeeded").length;
28875
+ pushDebug.finish({
28876
+ outcome: pushSucceeded ? "pushed" : pushedCount > 0 ? "partial" : "failed",
28877
+ summary: pushSucceeded ? items.length > 0 ? `The server reports ${pushedCount} of ${items.length} items applied.` : `The operation finished as ${operation.sys.status}, but the server returned no per-item results, so the counts come from the preview.` : `The operation finished as ${operation.sys.status}; ${failedItems.length} item(s) failed.`,
28878
+ details: {
28677
28879
  operation_id: operation.sys.id,
28678
28880
  operation_status: operation.sys.status,
28679
- summary: operation.summary,
28680
- item_count: items.length,
28881
+ server_summary: operation.summary,
28681
28882
  items: items.map((item) => ({
28682
- entityType: item.entityType,
28883
+ type: item.entityType,
28683
28884
  id: item.id,
28684
28885
  action: item.action,
28685
28886
  status: item.status,
28686
28887
  ...item.error ? { error: formatEdsiError(item.error) } : {}
28687
28888
  })),
28688
- push_result: {
28889
+ shown_to_user: {
28689
28890
  component_types: pushResult.componentTypes,
28690
28891
  design_tokens: pushResult.designTokens
28691
28892
  },
28692
- succeeded: pushSucceeded
28693
- },
28694
- pushSucceeded ? "success" : "error"
28695
- );
28893
+ request_id: client2.getLastRequestId()
28894
+ }
28895
+ });
28696
28896
  update({ step: "done", pushResult });
28697
28897
  } catch (e) {
28698
28898
  let msg;
@@ -28703,13 +28903,14 @@ If using a custom host configuration, make sure the space exists on that host.`
28703
28903
  } else {
28704
28904
  msg = "Push failed";
28705
28905
  }
28706
- pushDebug.finish(
28707
- {
28708
- error: msg,
28709
- ...e instanceof ApiError ? { status: e.status, body: (e.body ?? "").slice(0, 2e3) } : {}
28710
- },
28711
- "error"
28712
- );
28906
+ pushDebug.finish({
28907
+ outcome: "failed",
28908
+ summary: e instanceof ApiError ? `The apply request failed with HTTP ${e.status}.` : `The apply request failed before the server answered: ${msg}`,
28909
+ details: {
28910
+ message: msg,
28911
+ ...e instanceof ApiError ? { status: e.status, body: (e.body ?? "").slice(0, 4e3) } : {}
28912
+ }
28913
+ });
28713
28914
  update({
28714
28915
  step: "error",
28715
28916
  errorStep: "apply",
@@ -1,11 +1,29 @@
1
+ import type { ServerPreviewResponse } from '@contentful/experience-design-system-types';
1
2
  export declare const DEBUG_SESSION_DIR_ENV = "EDS_DEBUG_SESSION_DIR";
2
- export type PushDebugStatus = 'success' | 'error';
3
+ export type PushOutcome = 'in-progress' | 'pushed' | 'partial' | 'failed' | 'preview-failed' | 'nothing-to-push' | 'skipped' | 'superseded';
4
+ export interface PushDebugResult {
5
+ outcome: PushOutcome;
6
+ /** One plain-English sentence that says what happened and why. */
7
+ summary: string;
8
+ details?: Record<string, unknown>;
9
+ }
10
+ export interface PushDebugEventOptions {
11
+ note?: string;
12
+ data?: Record<string, unknown>;
13
+ requestId?: string;
14
+ }
3
15
  export interface PushDebugRun {
4
- finish(outputs: Record<string, unknown>, status: PushDebugStatus): void;
16
+ event(title: string, options?: PushDebugEventOptions): void;
17
+ finish(result: PushDebugResult): void;
5
18
  }
19
+ /** The server's preview, reduced to the names in each group so it is easy to read. */
20
+ export declare function summarizePreview(preview: ServerPreviewResponse): Record<string, unknown>;
21
+ /** The entries of a CDF that will be sent: name, type and the properties and slots each has. */
22
+ export declare function summarizeCdf(cdf: Record<string, unknown>): Array<Record<string, unknown>>;
6
23
  /**
7
- * Records the inputs and outputs of the push step in the v2 debug session folder.
8
- * It does nothing unless the v2 CLI set EDS_DEBUG_SESSION_DIR, which it only does
9
- * when Debug Mode is on. Logging never throws.
24
+ * Records the push step (preview, confirmation and apply) in the v2 debug session folder.
25
+ * The file is rewritten after every event, so a push that dies partway still leaves a log.
26
+ * It does nothing unless the v2 CLI set EDS_DEBUG_SESSION_DIR, which it only does when
27
+ * Debug Mode is on. Logging never throws.
10
28
  */
11
29
  export declare function startPushDebugRun(inputs: Record<string, unknown>): PushDebugRun;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-cli",
3
- "version": "2.35.1-dev-build-c4a4d1cd.0",
3
+ "version": "2.35.1-dev-build-57c625cc.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/experience-design-system-cli",
3
- "version": "2.35.1-dev-build-c4a4d1cd.0",
3
+ "version": "2.35.1-dev-build-57c625cc.0",
4
4
  "description": "Contentful Experiences design system import CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -41,7 +41,7 @@
41
41
  "svelte": "^5.56.4",
42
42
  "ts-morph": "^27.0.2",
43
43
  "typescript": "^5.9.3",
44
- "@contentful/experience-design-system-types": "2.35.1-dev-build-c4a4d1cd.0"
44
+ "@contentful/experience-design-system-types": "2.35.1-dev-build-57c625cc.0"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@tsconfig/node24": "^24.0.4",