@wix/himalaya-cli 0.947.0 → 0.949.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/cli.mjs CHANGED
@@ -21494,12 +21494,13 @@ var init_listGestures = __esm({
21494
21494
  } else setOffset(Math.abs(offset) >= SWIPE_OPEN * 0.5 ? Math.sign(offset) * SWIPE_OPEN : 0);
21495
21495
  startX.current = null;
21496
21496
  };
21497
- const actionBtn = (a, i, edge) => /* @__PURE__ */ jsx5(
21497
+ const actionBtn = (a, i, edge, hidden) => /* @__PURE__ */ jsx5(
21498
21498
  "button",
21499
21499
  {
21500
21500
  type: "button",
21501
21501
  "data-himalaya-swipe-action": true,
21502
21502
  "data-himalaya-swipe-edge": edge,
21503
+ tabIndex: hidden ? -1 : void 0,
21503
21504
  onClick: () => fireAndClose(a.action),
21504
21505
  style: {
21505
21506
  border: "none",
@@ -21517,8 +21518,8 @@ var init_listGestures = __esm({
21517
21518
  `${edge}-${i}`
21518
21519
  );
21519
21520
  return /* @__PURE__ */ jsxs2("div", { style: { position: "relative", overflow: "hidden" }, children: [
21520
- leading.length > 0 && /* @__PURE__ */ jsx5("div", { "aria-hidden": offset <= 0, style: { position: "absolute", inset: 0, display: "flex", justifyContent: "flex-start" }, children: leading.map((a, i) => actionBtn(a, i, "leading")) }),
21521
- trailing.length > 0 && /* @__PURE__ */ jsx5("div", { "aria-hidden": offset >= 0, style: { position: "absolute", inset: 0, display: "flex", justifyContent: "flex-end" }, children: trailing.map((a, i) => actionBtn(a, i, "trailing")) }),
21521
+ leading.length > 0 && /* @__PURE__ */ jsx5("div", { "aria-hidden": offset <= 0, style: { position: "absolute", inset: 0, display: "flex", justifyContent: "flex-start" }, children: leading.map((a, i) => actionBtn(a, i, "leading", offset <= 0)) }),
21522
+ trailing.length > 0 && /* @__PURE__ */ jsx5("div", { "aria-hidden": offset >= 0, style: { position: "absolute", inset: 0, display: "flex", justifyContent: "flex-end" }, children: trailing.map((a, i) => actionBtn(a, i, "trailing", offset >= 0)) }),
21522
21523
  /* @__PURE__ */ jsx5(
21523
21524
  "div",
21524
21525
  {
@@ -22076,6 +22077,14 @@ function ensurePressStyles() {
22076
22077
  '[data-himalaya-press]{transition:transform var(--hm-press-dur,160ms) var(--hm-press-ease,cubic-bezier(0.2,0,0,1)),filter var(--hm-press-dur,160ms) var(--hm-press-ease,cubic-bezier(0.2,0,0,1))}[data-himalaya-press="scale"]:active,[data-himalaya-press="auto"]:active,[data-himalaya-press="scaleHighlight"]:active{transform:scale(0.96)}[data-himalaya-press="scaleHighlight"]:active,[data-himalaya-press="highlight"]:active{filter:brightness(1.08)}[data-himalaya-press="lift"]:active{transform:translateY(-4px) scale(1.02)}@media (hover:hover){[data-himalaya-tap]{transition:filter 120ms ease}[data-himalaya-tap]:hover{filter:brightness(0.97)}[data-himalaya-press="scale"]:hover,[data-himalaya-press="auto"]:hover,[data-himalaya-press="scaleHighlight"]:hover{transform:scale(0.985)}[data-himalaya-press="lift"]:hover{transform:translateY(-2px) scale(1.01)}}';
22077
22078
  document.head.appendChild(el);
22078
22079
  }
22080
+ function ensureFocusStyles() {
22081
+ if (focusStylesInjected || typeof document === "undefined") return;
22082
+ focusStylesInjected = true;
22083
+ const el = document.createElement("style");
22084
+ el.setAttribute("data-himalaya-focus-ring", "");
22085
+ el.textContent = FOCUS_RING_CSS;
22086
+ document.head.appendChild(el);
22087
+ }
22079
22088
  function ensureHListStyles() {
22080
22089
  if (hListStylesInjected || typeof document === "undefined") return;
22081
22090
  hListStylesInjected = true;
@@ -23219,6 +23228,13 @@ function renderNodeInner(node, ctx) {
23219
23228
  extra["data-hm-measure-bind"] = JSON.stringify(bind);
23220
23229
  }
23221
23230
  }
23231
+ {
23232
+ const accessibilityLabel = node?.modifiers?.accessibilityLabel ?? node?.modifiers?.accessibility_label;
23233
+ if (accessibilityLabel != null) {
23234
+ const resolved2 = resolveScalarStatic(accessibilityLabel, ctx);
23235
+ if (resolved2 != null && String(resolved2).trim()) extra["aria-label"] = String(resolved2);
23236
+ }
23237
+ }
23222
23238
  const tap = node?.modifiers?.onTap ?? node?.modifiers?.on_tap;
23223
23239
  const tapDisabled = normalize(node).props?.disabled === true || normalize(node).props?.loading === true || node?.modifiers?.disabled === true || node?.modifiers?.hitTestable === false || node?.modifiers?.hit_testable === false;
23224
23240
  if (tap && ctx.onAction && !tapDisabled) {
@@ -23242,11 +23258,6 @@ function renderNodeInner(node, ctx) {
23242
23258
  ctx.onAction(resolveItemDeep2(tap, ctx));
23243
23259
  };
23244
23260
  }
23245
- const accessibilityLabel = node?.modifiers?.accessibilityLabel ?? node?.modifiers?.accessibility_label;
23246
- if (accessibilityLabel != null) {
23247
- const resolved2 = resolveScalarStatic(accessibilityLabel, ctx);
23248
- if (resolved2 != null && String(resolved2).trim()) extra["aria-label"] = String(resolved2);
23249
- }
23250
23261
  ensurePressStyles();
23251
23262
  extra["data-himalaya-tap"] = "1";
23252
23263
  }
@@ -23304,6 +23315,7 @@ function boundPaddingInsets(modifiers, ctx) {
23304
23315
  return out;
23305
23316
  }
23306
23317
  function renderNode(node, ctx) {
23318
+ ensureFocusStyles();
23307
23319
  const bindings = directServiceBindings(node);
23308
23320
  return bindings.length > 0 && ctx.provider ? /* @__PURE__ */ jsx6(ReactiveDirectScalars, { node, ctx, bindings }) : renderNodeInner(node, ctx);
23309
23321
  }
@@ -23979,7 +23991,7 @@ function renderInner(node, ctx) {
23979
23991
  }
23980
23992
  }
23981
23993
  }
23982
- var useIsomorphicLayoutEffect, ResponsiveGrid, SPLIT_EXPANDED_MIN_WIDTH, SPLIT_COLUMN_GAP, ResponsiveSplitView, ABSOLUTE_URL_RE, appearKeyframesInjected, pressStylesInjected, hListStylesInjected, listAnimateRuntimeInstalled, transitionKeyframesInjected, countUpRuntimeInjected, MEASURE_PREFIX, measureRuntimeInjected, revealRuntimeInjected, vectorAnimStylesInjected, scrollProgressRuntimeInjected, confettiRuntimeInjected, lottieRuntimeInjected, riveRuntimeInjected, gradientKeyframesInjected, parallaxRuntimeInjected, spinKeyframesInjected, marqueeKeyframesInjected, alignItems, zJustifyItems, hAlignItems, bodyFont, kids, rowKids, staggeredKids, asTextL10n, asBoundText, useBoundString, InterpolatedTextView, txt, selectFragmentCase, fragmentValueHash, fragmentSlotContent, FragmentSlotNode, WorkerSubtreeNode, resolveItemDeep2, resolveSwipeActions, resolveModBindings, resolvedComponentId, directServiceBindings, ReactiveDirectScalars, HiddenGate, KEYBOARD_INPUT_MODES, AUTOCAPITALIZE_VALUES, ENTER_KEY_HINTS, AUTOGROW_CEILING, EditableField, MenuNode, LoadMoreSentinel, FieldErrorNode, FormView, MediaSlotProvider, MEDIA_ITEM_BINDABLE, MediaPlayerView, VideoNode, PdfViewNode, WebViewNode, InteractivePicker, InteractiveDatePicker, InteractiveSearchField, InteractiveStepper, INTERACTIVE_ROLES, ALWAYS_INTERACTIVE_COMPONENT_TYPES, controlNode, ToggleNode, SliderNode, SelectionControlNode, TabsNode, SegmentedControlNode, DisclosureGroupNode, GridNode, SplitViewNode, TextNode, ImageNode, AvatarNode, IconNode, ButtonNode, OtpInputNode, ProgressBarNode, ActivityIndicatorNode, BottomSheetNode, ChipsInputNode, ChipNode, TableNode, GaugeRing, GaugeNode, RatingNode, AvatarStripNode, CHART_STROKE_CYCLE, chartStrokeAt, chartBarCenter, ChartNode, donutSliceOpacity, DonutChartNode, LegendMarker, LegendNode, cellAlign, DataTableNode, voiceNoteState, voiceNoteDelivery, VOICE_NOTE_DEFAULT_BARS, clampBarCount, VoiceNoteNode, TimelineNode, WheelPickerNode, ColorPickerNode, FilterChipsNode, TILE_PX, MAX_MERCATOR_LAT, DEFAULT_TILE_MAX_ZOOM, CIRCLE_SEGMENTS, METRES_PER_DEG_LAT, MARKER_HIT_RADIUS, SHAPE_HIT_RADIUS, MapNode, CollapsingHeaderNode, UnsupportedOnSurface, CALENDAR_DATE_ONLY_RE, CAL_DEFAULT_MAX_DOTS, CAL_AGENDA_INITIAL_DAYS, CAL_AGENDA_PAGE_DAYS, CAL_DEFAULT_SNAP_MINUTES, CAL_UNASSIGNED_LANE_ID, MonthCalendarNode, TimeGridNode, AgendaNode, WebRenderer;
23994
+ var useIsomorphicLayoutEffect, ResponsiveGrid, SPLIT_EXPANDED_MIN_WIDTH, SPLIT_COLUMN_GAP, ResponsiveSplitView, ABSOLUTE_URL_RE, appearKeyframesInjected, pressStylesInjected, FOCUS_RING_CSS, focusStylesInjected, hListStylesInjected, listAnimateRuntimeInstalled, transitionKeyframesInjected, countUpRuntimeInjected, MEASURE_PREFIX, measureRuntimeInjected, revealRuntimeInjected, vectorAnimStylesInjected, scrollProgressRuntimeInjected, confettiRuntimeInjected, lottieRuntimeInjected, riveRuntimeInjected, gradientKeyframesInjected, parallaxRuntimeInjected, spinKeyframesInjected, marqueeKeyframesInjected, alignItems, zJustifyItems, hAlignItems, bodyFont, kids, rowKids, staggeredKids, asTextL10n, asBoundText, useBoundString, InterpolatedTextView, txt, selectFragmentCase, fragmentValueHash, fragmentSlotContent, FragmentSlotNode, WorkerSubtreeNode, resolveItemDeep2, resolveSwipeActions, resolveModBindings, resolvedComponentId, directServiceBindings, ReactiveDirectScalars, HiddenGate, KEYBOARD_INPUT_MODES, AUTOCAPITALIZE_VALUES, ENTER_KEY_HINTS, AUTOGROW_CEILING, EditableField, MenuNode, LoadMoreSentinel, FieldErrorNode, FormView, MediaSlotProvider, MEDIA_ITEM_BINDABLE, MediaPlayerView, VideoNode, PdfViewNode, WebViewNode, InteractivePicker, InteractiveDatePicker, InteractiveSearchField, InteractiveStepper, INTERACTIVE_ROLES, ALWAYS_INTERACTIVE_COMPONENT_TYPES, controlNode, ToggleNode, SliderNode, SelectionControlNode, TabsNode, SegmentedControlNode, DisclosureGroupNode, GridNode, SplitViewNode, TextNode, ImageNode, AvatarNode, IconNode, ButtonNode, OtpInputNode, ProgressBarNode, ActivityIndicatorNode, BottomSheetNode, ChipsInputNode, ChipNode, TableNode, GaugeRing, GaugeNode, RatingNode, AvatarStripNode, CHART_STROKE_CYCLE, chartStrokeAt, chartBarCenter, ChartNode, donutSliceOpacity, DonutChartNode, LegendMarker, LegendNode, cellAlign, DataTableNode, voiceNoteState, voiceNoteDelivery, VOICE_NOTE_DEFAULT_BARS, clampBarCount, VoiceNoteNode, TimelineNode, WheelPickerNode, ColorPickerNode, FilterChipsNode, TILE_PX, MAX_MERCATOR_LAT, DEFAULT_TILE_MAX_ZOOM, CIRCLE_SEGMENTS, METRES_PER_DEG_LAT, MARKER_HIT_RADIUS, SHAPE_HIT_RADIUS, MapNode, CollapsingHeaderNode, UnsupportedOnSurface, CALENDAR_DATE_ONLY_RE, CAL_DEFAULT_MAX_DOTS, CAL_AGENDA_INITIAL_DAYS, CAL_AGENDA_PAGE_DAYS, CAL_DEFAULT_SNAP_MINUTES, CAL_UNASSIGNED_LANE_ID, MonthCalendarNode, TimeGridNode, AgendaNode, WebRenderer;
23983
23995
  var init_renderNode = __esm({
23984
23996
  "../../core/web-renderer/src/renderNode.tsx"() {
23985
23997
  "use strict";
@@ -24063,6 +24075,8 @@ var init_renderNode = __esm({
24063
24075
  ABSOLUTE_URL_RE = /^([a-zA-Z][a-zA-Z0-9+.-]*:|\/\/)/;
24064
24076
  appearKeyframesInjected = false;
24065
24077
  pressStylesInjected = false;
24078
+ FOCUS_RING_CSS = ':where(button,a,[href],input,select,textarea,[role="button"],[tabindex]):focus-visible{outline:2px solid var(--himi-accent,#116DFF);outline-offset:2px;border-radius:4px}';
24079
+ focusStylesInjected = false;
24066
24080
  hListStylesInjected = false;
24067
24081
  listAnimateRuntimeInstalled = false;
24068
24082
  transitionKeyframesInjected = false;
@@ -27324,11 +27338,13 @@ function renderDescriptorToHtml(payload, tokens, scheme = "light", provider = nu
27324
27338
  ...typeof width === "number" && Number.isFinite(width) && width > 0 ? { sizeClass: sizeClassFromWidth(width), containerWidth: width } : {},
27325
27339
  ...rtl ? { isRTL: true } : {}
27326
27340
  });
27341
+ const FOCUS_STYLE_MARKUP = `<style data-himalaya-focus-ring>${FOCUS_RING_CSS}</style>`;
27342
+ const withFocusRing = (markup) => markup ? FOCUS_STYLE_MARKUP + markup : markup;
27327
27343
  const header = chrome?.stickyHeader;
27328
27344
  const footer = chrome?.stickyFooter;
27329
27345
  const dir = rtl ? { dir: "rtl" } : {};
27330
27346
  if (header || footer) {
27331
- return renderToStaticMarkup(
27347
+ return withFocusRing(renderToStaticMarkup(
27332
27348
  React6.createElement(
27333
27349
  "div",
27334
27350
  { "data-testid": "screen-host", ...dir },
@@ -27344,16 +27360,16 @@ function renderDescriptorToHtml(payload, tokens, scheme = "light", provider = nu
27344
27360
  renderNode(footer, ctx)
27345
27361
  ) : null
27346
27362
  )
27347
- );
27363
+ ));
27348
27364
  }
27349
27365
  if (rtl) {
27350
- return renderToStaticMarkup(
27366
+ return withFocusRing(renderToStaticMarkup(
27351
27367
  React6.createElement("div", dir, renderNode(payload, ctx))
27352
- );
27368
+ ));
27353
27369
  }
27354
- return renderToStaticMarkup(
27370
+ return withFocusRing(renderToStaticMarkup(
27355
27371
  React6.createElement(React6.Fragment, null, renderNode(payload, ctx))
27356
- );
27372
+ ));
27357
27373
  }
27358
27374
  var init_renderToHtml = __esm({
27359
27375
  "../../core/web-renderer/src/renderToHtml.tsx"() {
@@ -43283,19 +43299,19 @@ var init_preview_assets_generated = __esm({
43283
43299
  "../../packages/serve/src/preview-assets.generated.ts"() {
43284
43300
  init_preview_assets_format();
43285
43301
  PREVIEW_ASSET_MANIFEST = [
43286
- { key: "assets/index-C40lmxo4.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 983092, sha256: "919193db2182eb6a481f3729dda29af2441d6c46027c7fab508c2abb78f8fc0f" },
43287
- { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 983100, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
43288
- { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1074024, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
43289
- { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1165008, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
43290
- { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1255988, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
43291
- { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1346860, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
43292
- { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 1437840, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
43293
- { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 1546476, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
43294
- { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 1655560, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
43295
- { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 1764608, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
43296
- { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 1872308, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
43297
- { key: "index.html", contentType: "text/html; charset=utf-8", offset: 1960416, length: 4448, sha256: "4cff52eaf77b0c3c09effb2dd0447d78d2b03ecaa68893281b1637510b93d8ad" },
43298
- { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 1964864, length: 13784, sha256: "cfb9465254fab84f0e084bb4542c282758ea29774b5f172840cc0b9e4194ef89" }
43302
+ { key: "assets/index-DlRHv5p2.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 983492, sha256: "89f6530bb02d868a8d28e7a93103bef7e7b83904a5e0fcf4f813c06872191b48" },
43303
+ { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 983500, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
43304
+ { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1074424, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
43305
+ { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1165408, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
43306
+ { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1256388, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
43307
+ { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1347260, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
43308
+ { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 1438240, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
43309
+ { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 1546876, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
43310
+ { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 1655960, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
43311
+ { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 1765008, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
43312
+ { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 1872708, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
43313
+ { key: "index.html", contentType: "text/html; charset=utf-8", offset: 1960816, length: 4448, sha256: "2a2e413e18bb4b278f1f4daee79dce764a17f65f6567a734a69e9a895bc85f70" },
43314
+ { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 1965264, length: 13784, sha256: "cfb9465254fab84f0e084bb4542c282758ea29774b5f172840cc0b9e4194ef89" }
43299
43315
  ];
43300
43316
  }
43301
43317
  });
@@ -51134,6 +51150,18 @@ var ServeCliClient = class {
51134
51150
  removeRelease(app) {
51135
51151
  return this.request("control", "POST", "/v1/admin/release/remove", { body: { app }, headers: this.ctrlHeaders() });
51136
51152
  }
51153
+ /**
51154
+ * Undo a `removeRelease` inside its retention window (POST /v1/admin/release/restore).
51155
+ *
51156
+ * The route is as privileged as the remove was — same scope + role gates — and it is the reason
51157
+ * `removeRelease`'s response advertises `restorable` + `restoreBy`. Shipping the remove without
51158
+ * this leaves that promise unreachable from the CLI, which is how an un-publish starts reading
51159
+ * as final. Refuses with 404 `no_tombstone`, 409 `nothing_to_restore`, or 410 once the window
51160
+ * has closed; the CLI turns each into a named refusal rather than a bare status.
51161
+ */
51162
+ restoreRelease(app) {
51163
+ return this.request("control", "POST", "/v1/admin/release/restore", { body: { app }, headers: this.ctrlHeaders() });
51164
+ }
51137
51165
  /** Write-through an OTA app-config patch (POST /v1/admin/app-config). */
51138
51166
  setAppConfig(app, patch) {
51139
51167
  return this.request("control", "POST", "/v1/admin/app-config", { body: { app, patch }, headers: this.ctrlHeaders() });
@@ -55295,6 +55323,37 @@ function tokenCoversApp(token, app) {
55295
55323
  if (!claims || claims.apps === "*" || !Array.isArray(claims.apps)) return true;
55296
55324
  return claims.apps.includes(app);
55297
55325
  }
55326
+ function credentialKind(token) {
55327
+ const claims = decodeControlTokenClaims(token);
55328
+ if (!claims) return null;
55329
+ if (claims.selfServe) return "self-serve";
55330
+ return claims.sub ? "operator" : "shared";
55331
+ }
55332
+ var KIND_LABEL = {
55333
+ "self-serve": "self-serve",
55334
+ shared: "shared",
55335
+ operator: "operator/provisioned"
55336
+ };
55337
+ var KIND_TIER = {
55338
+ "self-serve": "self-serve",
55339
+ shared: "shared",
55340
+ operator: "employee"
55341
+ };
55342
+ var kindLoginBack = (kind, target) => {
55343
+ if (kind === "self-serve") return `himi login --browser --target ${target}`;
55344
+ if (kind === "operator") return `himi login --dpx --target ${target}`;
55345
+ return void 0;
55346
+ };
55347
+ function credentialSwapNotice(prevToken, nextToken, target) {
55348
+ if (!prevToken) return void 0;
55349
+ const prev = credentialKind(prevToken);
55350
+ const next = credentialKind(nextToken);
55351
+ if (!prev || !next || prev === next) return void 0;
55352
+ const tierLine = `\`himi dist\` will now charge the ${KIND_TIER[next]} tier instead of the ${KIND_TIER[prev]} one.`;
55353
+ const back = kindLoginBack(prev, target);
55354
+ const backLine = back ? ` \`${back}\` switches back.` : "";
55355
+ return `replacing the ${KIND_LABEL[prev]} credential for target "${target}" with a ${KIND_LABEL[next]} one. ${tierLine}${backLine}`;
55356
+ }
55298
55357
  var HARD_CLAIM_REFUSALS = /* @__PURE__ */ new Set(["slug_reserved", "invalid_slug", "account_ambiguous", "not_your_account"]);
55299
55358
  var AUTO_CLAIM_TIMEOUT_MS = 15e3;
55300
55359
  async function autoClaimSlug(opts) {
@@ -59882,6 +59941,7 @@ ${label2}`);
59882
59941
  }
59883
59942
  case "login": {
59884
59943
  const target = targetName();
59944
+ const prevControlToken = loadTargetsFile().targets?.[target]?.controlToken;
59885
59945
  let issue2;
59886
59946
  let ownerIssue;
59887
59947
  try {
@@ -59967,6 +60027,7 @@ ${label2}`);
59967
60027
  exp = JSON.parse(Buffer.from(body2.token.split(".")[0], "base64url").toString("utf8")).exp;
59968
60028
  } catch {
59969
60029
  }
60030
+ const swap2 = credentialSwapNotice(prevControlToken, body2.token, target);
59970
60031
  print({
59971
60032
  ok: true,
59972
60033
  via: "wix",
@@ -59975,6 +60036,7 @@ ${label2}`);
59975
60036
  exp,
59976
60037
  scope: body2.scope,
59977
60038
  storedAt: storedAt2,
60039
+ ...swap2 ? { notice: swap2 } : {},
59978
60040
  ...Array.isArray(body2.scope) && body2.scope.length === 0 ? { hint: "you own no apps yet \u2014 claim one with `himi apps claim <slug>`" } : {}
59979
60041
  });
59980
60042
  return 0;
@@ -60030,6 +60092,7 @@ ${label2}`);
60030
60092
  sub = c.sub;
60031
60093
  } catch {
60032
60094
  }
60095
+ const swap2 = credentialSwapNotice(prevControlToken, result.token, target);
60033
60096
  print({
60034
60097
  ok: true,
60035
60098
  via: "browser",
@@ -60038,6 +60101,7 @@ ${label2}`);
60038
60101
  exp,
60039
60102
  scope,
60040
60103
  storedAt: storedAt2,
60104
+ ...swap2 ? { notice: swap2 } : {},
60041
60105
  ...Array.isArray(scope) && scope.length === 0 ? { hint: "you own no apps yet \u2014 claim one with `himi apps claim <slug>`" } : {}
60042
60106
  });
60043
60107
  return 0;
@@ -60073,7 +60137,8 @@ ${label2}`);
60073
60137
  return 1;
60074
60138
  }
60075
60139
  const storedAt = saveControlToken(target, body.token);
60076
- print({ ok: true, target, exp: body.exp, scope: body.scope, storedAt });
60140
+ const swap = credentialSwapNotice(prevControlToken, body.token, target);
60141
+ print({ ok: true, target, exp: body.exp, scope: body.scope, storedAt, ...swap ? { notice: swap } : {} });
60077
60142
  return 0;
60078
60143
  }
60079
60144
  // --- #814 Stage 3: self-serve app ownership + local token introspection -------
@@ -60726,6 +60791,8 @@ export {
60726
60791
  autoClaimSlug,
60727
60792
  buildDoctorReport,
60728
60793
  compareVersions2 as compareVersions,
60794
+ credentialKind,
60795
+ credentialSwapNotice,
60729
60796
  decodeControlTokenClaims,
60730
60797
  defaultTargetForCommand,
60731
60798
  diagnoseBody,
Binary file
@@ -80,6 +80,49 @@ traffic until its gateway route was deleted on 2026-09-05; it now 404s with no r
80
80
  ```
81
81
  Kill-switch a bad bundle: `himi-serve release revoke --app <app> --integrity <sri> --target bo --control-token "$TOK"`.
82
82
 
83
+ ### Retiring an app
84
+
85
+ `release revoke` kills one bundle; `release remove` unpublishes the **app** — it drops the
86
+ manifest and takes the app out of the `/v1/apps` registry, so devices resolving it stop getting
87
+ a release:
88
+
89
+ ```
90
+ himi-serve release remove --app <app> --yes --target bo --control-token "$TOK"
91
+ himi-serve release restore --app <app> --target bo --control-token "$TOK"
92
+ ```
93
+
94
+ **`--yes` is required**, and nothing is sent without it. Every other release verb is narrower —
95
+ `revoke` needs an integrity, `promote` needs a release, and both leave the app resolvable — so
96
+ this is the one where a typo'd `--app` unpublishes whatever it names.
97
+
98
+ **Whether a remove can be undone is the BACKEND's answer, not a property of the verb.** A store
99
+ that implements `restore` (the cloud store) records a tombstone and the remove reports
100
+ `restorable: true` with a `restoreBy` deadline. A store that does not — including the
101
+ `FileReleaseStore` a local serve-stack runs on, which implements `remove` and no `restore` —
102
+ reports `restorable: false`, and `release restore` answers `501 restore_unsupported`. **There the
103
+ un-publish is permanent.** So read the `restorable` field in the response before treating a remove
104
+ as reversible; the CLI prints the `restoreWith` command line only when the plane says the undo
105
+ exists, and stays silent when it does not.
106
+
107
+ That is also why the confirmation is `--yes` rather than `apps backfill`'s
108
+ rehearse-unless-`--apply`: on a store with restore the cost of getting it wrong is a restore rather
109
+ than a permanent loss, and on a store without one the confirmation is the only thing standing in
110
+ front of an irreversible write.
111
+
112
+ `restore` replays the tombstone inside that window. It takes no `--yes`, since making the recovery
113
+ harder to type than the destructive verb has the asymmetry backwards. It is **not** gated
114
+ identically to `remove`: `remove` is in serve-control's `PUBLISH_CONTENT_PATHS`, so an `owner`-role
115
+ token is refused, while `restore` is not in that set and an owner-scoped token may restore an app
116
+ it owns. Both still require control-plane scope authentication. Past the window it refuses, and each refusal says which case it
117
+ is — nothing recorded (404), recorded but carrying no release to put back (409), or the window
118
+ closed (410, the only way back being `release push`).
119
+
120
+ **This is the general door; `template remove` is the same route narrowed to the
121
+ `himi-template-` namespace.** An app with an *owner* can also be retired owner-side with
122
+ `himi apps release <slug> --yes`, but that needs ownership — so an **unclaimed** app (a QA
123
+ scaffold, anything published before auto-claiming) has nobody to supply it and this is the only
124
+ command that reaches it.
125
+
83
126
  ### Curating templates
84
127
 
85
128
  A starter template is an app in the reserved `himi-template-<name>` namespace, so it is
@@ -110,7 +153,9 @@ name may legally begin with `himi-template-` (the name pattern is lowercase alph
110
153
  inner hyphens), and such a name publishes to a **doubly** prefixed app id — so `--name` cannot
111
154
  express it without becoming ambiguous. The CLI refuses the ambiguous form and points at `--app`. `--app` only accepts ids inside the
112
155
  reserved namespace: a non-template id is refused, so this group cannot unpublish or
113
- kill-switch an ordinary app by mistake — use the `release` group for those.
156
+ kill-switch an ordinary app by mistake — use the `release` group for those, which the refusal
157
+ names by the verb you asked for (`release remove --app <app> --yes` for a remove, `release
158
+ revoke … --integrity <sri>` for a revoke).
114
159
 
115
160
  `remove` unpublishes the app; `revoke` is the reversible kill-switch, and it resolves the
116
161
  bundle integrities from the template's current release manifest so you never paste an SRI. A
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/himalaya-cli",
3
- "version": "0.947.0",
3
+ "version": "0.949.0",
4
4
  "type": "module",
5
5
  "description": "himi — the Himalaya authoring CLI. Build a Tier-5 content package on your own machine, push it to the production serve as a draft, preview it on web + Himi Player, and read worker logs back — the remote dev loop. Wraps @himalaya/serve-cli for transport.",
6
6
  "keywords": [
@@ -64,5 +64,5 @@
64
64
  "artifactId": "himalaya-cli"
65
65
  }
66
66
  },
67
- "falconPackageHash": "e6f6c45f77b9ba2728e1098c0c46b7d7eb3e6fb922394d52a0797dd7"
67
+ "falconPackageHash": "0449b6185090a3685450f4bf6e21424bd545c01791d527f37625af8c"
68
68
  }