@wix/himalaya-cli 0.1025.0 → 0.1027.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/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/dev-server/src/builder.d.ts +9 -0
- package/dist/cli.mjs +1052 -655
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/app-config.md +6 -0
- package/guides/headless-loop.md +3 -1
- package/package.json +2 -2
- package/templates/beauty-salon/dev/index.ts +1476 -553
- package/templates/beauty-salon/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/beauty-salon/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/beauty-salon/tier5-src/_shared/detail-presence.ts +51 -0
- package/templates/beauty-salon/tier5-src/himi-branded-lite-orders/index.ts +4 -1
- package/templates/beauty-salon/tier5-src/wix-spaces-collection-detail/index.ts +9 -9
- package/templates/beauty-salon/tier5-src/wix-spaces-create-post/index.ts +14 -4
- package/templates/beauty-salon/tier5-src/wix-spaces-plan-detail/index.ts +7 -9
- package/templates/beauty-salon/tier5-src/wix-spaces-subscription-detail/index.ts +12 -11
- package/templates/beauty-salon/tier5-src/wix-spaces-view-profile/index.ts +22 -12
- package/templates/beauty-salon-owner/dev/index.ts +857 -458
- package/templates/beauty-salon-owner/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/beauty-salon-owner/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/branded-lite/config.ts +3 -1
- package/templates/branded-lite/dev/index.ts +6123 -2565
- package/templates/branded-lite/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/branded-lite/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/branded-lite/tier5-src/_shared/detail-presence.ts +51 -0
- package/templates/branded-lite/tier5-src/himi-branded-lite-orders/index.ts +4 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-portfolio-project/index.ts +7 -2
- package/templates/branded-lite/tier5-src/himi-branded-lite-simple-detail/index.ts +4 -3
- package/templates/branded-lite/tier5-src/wix-spaces-chat-thread/index.ts +17 -4
- package/templates/branded-lite/tier5-src/wix-spaces-collection-detail/index.ts +9 -9
- package/templates/branded-lite/tier5-src/wix-spaces-coupon-detail/index.ts +7 -9
- package/templates/branded-lite/tier5-src/wix-spaces-create-post/index.ts +14 -4
- package/templates/branded-lite/tier5-src/wix-spaces-food-order-detail/index.ts +6 -3
- package/templates/branded-lite/tier5-src/wix-spaces-form-detail/index.ts +7 -9
- package/templates/branded-lite/tier5-src/wix-spaces-forum-post/index.ts +7 -9
- package/templates/branded-lite/tier5-src/wix-spaces-invoice-detail/index.ts +7 -9
- package/templates/branded-lite/tier5-src/wix-spaces-member-detail/index.ts +8 -8
- package/templates/branded-lite/tier5-src/wix-spaces-photo-albums/index.ts +8 -2
- package/templates/branded-lite/tier5-src/wix-spaces-plan-detail/index.ts +7 -9
- package/templates/branded-lite/tier5-src/wix-spaces-subscription-detail/index.ts +12 -11
- package/templates/branded-lite/tier5-src/wix-spaces-view-profile/index.ts +22 -12
- package/templates/community-club/dev/index.ts +582 -239
- package/templates/community-club/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/community-club/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/community-club/tier5-src/wix-spaces-create-post/index.ts +14 -4
- package/templates/community-club/tier5-src/wix-spaces-view-profile/index.ts +22 -12
- package/templates/community-club-owner/dev/index.ts +857 -458
- package/templates/community-club-owner/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/community-club-owner/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/events-meetups/dev/index.ts +547 -226
- package/templates/events-meetups/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/events-meetups/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/events-meetups/tier5-src/wix-spaces-create-post/index.ts +14 -4
- package/templates/events-meetups/tier5-src/wix-spaces-view-profile/index.ts +22 -12
- package/templates/events-meetups-owner/dev/index.ts +815 -458
- package/templates/events-meetups-owner/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/events-meetups-owner/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/gym-fitness/dev/index.ts +1609 -569
- package/templates/gym-fitness/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/gym-fitness/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/gym-fitness/tier5-src/_shared/detail-presence.ts +51 -0
- package/templates/gym-fitness/tier5-src/himi-branded-lite-orders/index.ts +4 -1
- package/templates/gym-fitness/tier5-src/wix-spaces-collection-detail/index.ts +9 -9
- package/templates/gym-fitness/tier5-src/wix-spaces-create-post/index.ts +14 -4
- package/templates/gym-fitness/tier5-src/wix-spaces-plan-detail/index.ts +7 -9
- package/templates/gym-fitness/tier5-src/wix-spaces-subscription-detail/index.ts +12 -11
- package/templates/gym-fitness/tier5-src/wix-spaces-view-profile/index.ts +22 -12
- package/templates/gym-fitness-owner/dev/index.ts +758 -338
- package/templates/gym-fitness-owner/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/gym-fitness-owner/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/himi-chat/dev/index.ts +26 -1
- package/templates/nonprofit-cause/dev/index.ts +978 -341
- package/templates/nonprofit-cause/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/nonprofit-cause/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/nonprofit-cause/tier5-src/_shared/detail-presence.ts +51 -0
- package/templates/nonprofit-cause/tier5-src/wix-spaces-create-post/index.ts +14 -4
- package/templates/nonprofit-cause/tier5-src/wix-spaces-plan-detail/index.ts +7 -9
- package/templates/nonprofit-cause/tier5-src/wix-spaces-subscription-detail/index.ts +12 -11
- package/templates/nonprofit-cause/tier5-src/wix-spaces-view-profile/index.ts +22 -12
- package/templates/nonprofit-cause-owner/dev/index.ts +716 -338
- package/templates/nonprofit-cause-owner/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/nonprofit-cause-owner/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/owner-lite/dev/index.ts +758 -338
- package/templates/owner-lite/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/owner-lite/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/podcast-creator/dev/index.ts +1111 -399
- package/templates/podcast-creator/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/podcast-creator/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/podcast-creator/tier5-src/_shared/detail-presence.ts +51 -0
- package/templates/podcast-creator/tier5-src/himi-branded-lite-simple-detail/index.ts +4 -3
- package/templates/podcast-creator/tier5-src/wix-spaces-create-post/index.ts +14 -4
- package/templates/podcast-creator/tier5-src/wix-spaces-plan-detail/index.ts +7 -9
- package/templates/podcast-creator/tier5-src/wix-spaces-subscription-detail/index.ts +12 -11
- package/templates/podcast-creator/tier5-src/wix-spaces-view-profile/index.ts +22 -12
- package/templates/podcast-creator-owner/dev/index.ts +857 -458
- package/templates/podcast-creator-owner/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/podcast-creator-owner/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/portfolio-creative/dev/index.ts +964 -345
- package/templates/portfolio-creative/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/portfolio-creative/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/portfolio-creative/tier5-src/_shared/detail-presence.ts +51 -0
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-orders/index.ts +4 -1
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-portfolio-project/index.ts +7 -2
- package/templates/portfolio-creative/tier5-src/wix-spaces-collection-detail/index.ts +9 -9
- package/templates/portfolio-creative/tier5-src/wix-spaces-create-post/index.ts +14 -4
- package/templates/portfolio-creative/tier5-src/wix-spaces-view-profile/index.ts +22 -12
- package/templates/portfolio-creative-owner/dev/index.ts +857 -458
- package/templates/portfolio-creative-owner/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/portfolio-creative-owner/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/restaurant/dev/index.ts +738 -284
- package/templates/restaurant/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/restaurant/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/restaurant/tier5-src/_shared/detail-presence.ts +51 -0
- package/templates/restaurant/tier5-src/wix-spaces-create-post/index.ts +14 -4
- package/templates/restaurant/tier5-src/wix-spaces-food-order-detail/index.ts +6 -3
- package/templates/restaurant/tier5-src/wix-spaces-view-profile/index.ts +22 -12
- package/templates/restaurant-owner/dev/index.ts +758 -338
- package/templates/restaurant-owner/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/restaurant-owner/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/retail-store/dev/index.ts +768 -298
- package/templates/retail-store/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/retail-store/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/retail-store/tier5-src/_shared/detail-presence.ts +51 -0
- package/templates/retail-store/tier5-src/himi-branded-lite-orders/index.ts +4 -1
- package/templates/retail-store/tier5-src/wix-spaces-collection-detail/index.ts +9 -9
- package/templates/retail-store/tier5-src/wix-spaces-create-post/index.ts +14 -4
- package/templates/retail-store/tier5-src/wix-spaces-view-profile/index.ts +22 -12
- package/templates/retail-store-owner/dev/index.ts +716 -338
- package/templates/retail-store-owner/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/retail-store-owner/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/surface-showcase/dev/index.ts +27 -0
- package/templates/yoga-studio/dev/index.ts +1147 -390
- package/templates/yoga-studio/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/yoga-studio/tier5-src/_shared/collection-service.ts +28 -3
- package/templates/yoga-studio/tier5-src/_shared/detail-presence.ts +51 -0
- package/templates/yoga-studio/tier5-src/wix-spaces-create-post/index.ts +14 -4
- package/templates/yoga-studio/tier5-src/wix-spaces-plan-detail/index.ts +7 -9
- package/templates/yoga-studio/tier5-src/wix-spaces-subscription-detail/index.ts +12 -11
- package/templates/yoga-studio/tier5-src/wix-spaces-view-profile/index.ts +22 -12
- package/templates/yoga-studio-owner/dev/index.ts +716 -338
- package/templates/yoga-studio-owner/tier5-src/_shared/collection-contract.ts +18 -8
- package/templates/yoga-studio-owner/tier5-src/_shared/collection-service.ts +28 -3
package/dist/cli.mjs
CHANGED
|
@@ -5378,7 +5378,6 @@ function resolveTranslation(value, catalog, sourceCatalog) {
|
|
|
5378
5378
|
var BINDING_SIGILS, BINDING_SIGIL_RE, TRANSLATION_PREFIX, TRANSLATION_KEY_RE;
|
|
5379
5379
|
var init_bindings = __esm({
|
|
5380
5380
|
"../../core/ts/src/bindings.ts"() {
|
|
5381
|
-
"use strict";
|
|
5382
5381
|
BINDING_SIGILS = ["service", "flag", "item", "t"];
|
|
5383
5382
|
BINDING_SIGIL_RE = new RegExp(
|
|
5384
5383
|
`^\\$(?:${BINDING_SIGILS.filter((s) => s !== "t").join("|")})\\b|^\\$t:`
|
|
@@ -20046,7 +20045,6 @@ function shouldRevealError(args) {
|
|
|
20046
20045
|
var EMAIL_RE, URL_HOST_RE, INTEGER_RE, NUMBER_RE;
|
|
20047
20046
|
var init_validation = __esm({
|
|
20048
20047
|
"../../core/ts/src/validation.ts"() {
|
|
20049
|
-
"use strict";
|
|
20050
20048
|
EMAIL_RE = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}$/;
|
|
20051
20049
|
URL_HOST_RE = /^[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*(:[0-9]+)?$/;
|
|
20052
20050
|
INTEGER_RE = /^[+-]?[0-9]+$/;
|
|
@@ -22908,6 +22906,65 @@ var init_controls = __esm({
|
|
|
22908
22906
|
}
|
|
22909
22907
|
});
|
|
22910
22908
|
|
|
22909
|
+
// ../../core/web-renderer/src/a11y/modalStack.ts
|
|
22910
|
+
function pushModalLayer(el) {
|
|
22911
|
+
const layer = { el: typeof el === "function" ? el : () => el };
|
|
22912
|
+
layers.push(layer);
|
|
22913
|
+
sync();
|
|
22914
|
+
return {
|
|
22915
|
+
isTop: () => layers[layers.length - 1] === layer,
|
|
22916
|
+
release: () => {
|
|
22917
|
+
const i = layers.indexOf(layer);
|
|
22918
|
+
if (i < 0) return;
|
|
22919
|
+
layers.splice(i, 1);
|
|
22920
|
+
sync();
|
|
22921
|
+
}
|
|
22922
|
+
};
|
|
22923
|
+
}
|
|
22924
|
+
function topElement() {
|
|
22925
|
+
for (let i = layers.length - 1; i >= 0; i--) {
|
|
22926
|
+
const el = layers[i].el();
|
|
22927
|
+
if (el?.isConnected) return el;
|
|
22928
|
+
}
|
|
22929
|
+
return null;
|
|
22930
|
+
}
|
|
22931
|
+
function sync() {
|
|
22932
|
+
watcher?.disconnect();
|
|
22933
|
+
watcher = null;
|
|
22934
|
+
for (const el of madeInert) el.removeAttribute("inert");
|
|
22935
|
+
madeInert.clear();
|
|
22936
|
+
const top = topElement();
|
|
22937
|
+
if (!top) return;
|
|
22938
|
+
const scope = top.parentElement?.closest(`[${MODAL_SCOPE_ATTR}]`) ?? top.ownerDocument.body;
|
|
22939
|
+
const levels = [];
|
|
22940
|
+
let node = top;
|
|
22941
|
+
while (node !== scope && node.parentElement) {
|
|
22942
|
+
const parent = node.parentElement;
|
|
22943
|
+
levels.push(parent);
|
|
22944
|
+
for (const sibling of Array.from(parent.children)) {
|
|
22945
|
+
if (sibling === node || SKIP.has(sibling.tagName) || sibling.hasAttribute("inert")) continue;
|
|
22946
|
+
sibling.setAttribute("inert", "");
|
|
22947
|
+
madeInert.add(sibling);
|
|
22948
|
+
}
|
|
22949
|
+
node = parent;
|
|
22950
|
+
}
|
|
22951
|
+
const Observer = top.ownerDocument.defaultView?.MutationObserver;
|
|
22952
|
+
if (Observer && levels.length) {
|
|
22953
|
+
watcher = new Observer(() => sync());
|
|
22954
|
+
for (const level of levels) watcher.observe(level, { childList: true });
|
|
22955
|
+
}
|
|
22956
|
+
}
|
|
22957
|
+
var MODAL_SCOPE_ATTR, SKIP, layers, madeInert, watcher;
|
|
22958
|
+
var init_modalStack = __esm({
|
|
22959
|
+
"../../core/web-renderer/src/a11y/modalStack.ts"() {
|
|
22960
|
+
MODAL_SCOPE_ATTR = "data-himi-modal-scope";
|
|
22961
|
+
SKIP = /* @__PURE__ */ new Set(["SCRIPT", "STYLE", "LINK", "META", "TEMPLATE", "NOSCRIPT", "HEAD"]);
|
|
22962
|
+
layers = [];
|
|
22963
|
+
madeInert = /* @__PURE__ */ new Set();
|
|
22964
|
+
watcher = null;
|
|
22965
|
+
}
|
|
22966
|
+
});
|
|
22967
|
+
|
|
22911
22968
|
// ../../core/web-renderer/src/listGestures.tsx
|
|
22912
22969
|
import { useRef, useState as useState2 } from "react";
|
|
22913
22970
|
import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
@@ -23490,7 +23547,6 @@ function validateWorkerSubtree(raw, slotId, policy, actionCatalog) {
|
|
|
23490
23547
|
var WORKER_SUBTREE_CEILINGS, ID_PART, ACTION_ID;
|
|
23491
23548
|
var init_worker_subtree = __esm({
|
|
23492
23549
|
"../../core/ts/src/worker-subtree.ts"() {
|
|
23493
|
-
"use strict";
|
|
23494
23550
|
init_worker_subtree_safe_types_generated();
|
|
23495
23551
|
WORKER_SUBTREE_CEILINGS = Object.freeze({
|
|
23496
23552
|
maxEncodedBytes: 65536,
|
|
@@ -24160,8 +24216,8 @@ function autoGrowBox(contentHeight, lineHeight, verticalPadding, maxLines) {
|
|
|
24160
24216
|
const cap = Math.max(floor, lineHeight * lines + verticalPadding);
|
|
24161
24217
|
return { height: Math.max(floor, Math.min(contentHeight, cap)), scrolls: contentHeight > cap };
|
|
24162
24218
|
}
|
|
24163
|
-
function wrapModalMenu(modal, label2, placement, menu) {
|
|
24164
|
-
return modal ? /* @__PURE__ */ jsx6("div", { role: "dialog", "aria-modal": "true", "aria-label": label2, style: placement, children: menu }) : menu;
|
|
24219
|
+
function wrapModalMenu(modal, label2, placement, ref, menu) {
|
|
24220
|
+
return modal ? /* @__PURE__ */ jsx6("div", { ref, role: "dialog", "aria-modal": "true", "aria-label": label2, style: placement, children: menu }) : menu;
|
|
24165
24221
|
}
|
|
24166
24222
|
function bindMediaSlot(value, sessionId) {
|
|
24167
24223
|
if (typeof value === "string") {
|
|
@@ -24776,9 +24832,37 @@ function ensureInitialFocusRuntime() {
|
|
|
24776
24832
|
restoreFocusOnDismiss(presentedScope, active);
|
|
24777
24833
|
}
|
|
24778
24834
|
el.focus();
|
|
24835
|
+
if (document.activeElement === el) enterAuthoredOrderOnTab(el);
|
|
24779
24836
|
}
|
|
24780
24837
|
}, 0);
|
|
24781
24838
|
}
|
|
24839
|
+
function enterAuthoredOrderOnTab(target) {
|
|
24840
|
+
const doc = target.ownerDocument;
|
|
24841
|
+
const scope = target.closest(PRESENTED_SCOPE);
|
|
24842
|
+
const root = scope ?? doc;
|
|
24843
|
+
const onKeyDown = (e) => {
|
|
24844
|
+
if (e.key !== "Tab" || e.shiftKey || e.altKey || e.ctrlKey || e.metaKey || e.defaultPrevented || e.target !== target) return;
|
|
24845
|
+
if (target.tabIndex > 0) return;
|
|
24846
|
+
const ordered = Array.from(root.querySelectorAll("[tabindex]")).filter((c) => c.tabIndex > 0 && c.closest(PRESENTED_SCOPE) === scope).sort((a, b) => a.tabIndex - b.tabIndex);
|
|
24847
|
+
for (const c of ordered) {
|
|
24848
|
+
c.focus();
|
|
24849
|
+
if (doc.activeElement === c) {
|
|
24850
|
+
e.preventDefault();
|
|
24851
|
+
e.stopPropagation();
|
|
24852
|
+
return;
|
|
24853
|
+
}
|
|
24854
|
+
}
|
|
24855
|
+
};
|
|
24856
|
+
const onBlur = () => setTimeout(() => {
|
|
24857
|
+
if (doc.activeElement !== target) disarm();
|
|
24858
|
+
}, 0);
|
|
24859
|
+
const disarm = () => {
|
|
24860
|
+
target.removeEventListener("keydown", onKeyDown);
|
|
24861
|
+
target.removeEventListener("blur", onBlur);
|
|
24862
|
+
};
|
|
24863
|
+
target.addEventListener("keydown", onKeyDown);
|
|
24864
|
+
target.addEventListener("blur", onBlur);
|
|
24865
|
+
}
|
|
24782
24866
|
function ariaModal(modal, dflt) {
|
|
24783
24867
|
const on3 = modal === true || modal === false ? modal : dflt;
|
|
24784
24868
|
return on3 ? "true" : void 0;
|
|
@@ -25747,6 +25831,7 @@ var init_renderNode = __esm({
|
|
|
25747
25831
|
init_icons();
|
|
25748
25832
|
init_icon_catalog_generated();
|
|
25749
25833
|
init_controls();
|
|
25834
|
+
init_modalStack();
|
|
25750
25835
|
init_listGestures();
|
|
25751
25836
|
init_worker_subtree();
|
|
25752
25837
|
init_preview_surfaces();
|
|
@@ -26277,6 +26362,7 @@ var init_renderNode = __esm({
|
|
|
26277
26362
|
const popupPlacement = { position: "absolute", top: "100%", right: 0, zIndex: 20, marginTop: 4 };
|
|
26278
26363
|
const anchorRef = React5.useRef(null);
|
|
26279
26364
|
const menuRef = React5.useRef(null);
|
|
26365
|
+
const dialogRef = React5.useRef(null);
|
|
26280
26366
|
const itemsKey = items.map((it, i) => `${it?.id ?? i}:${it?.disabled ? 0 : 1}`).join("|");
|
|
26281
26367
|
React5.useEffect(() => {
|
|
26282
26368
|
if (!open || !modal) return;
|
|
@@ -26286,7 +26372,9 @@ var init_renderNode = __esm({
|
|
|
26286
26372
|
}, [open, modal, itemsKey]);
|
|
26287
26373
|
React5.useEffect(() => {
|
|
26288
26374
|
if (!open || !modal) return;
|
|
26375
|
+
const layer = pushModalLayer(() => dialogRef.current);
|
|
26289
26376
|
return () => {
|
|
26377
|
+
layer.release();
|
|
26290
26378
|
const active = document.activeElement;
|
|
26291
26379
|
if (active == null || active === document.body || !document.contains(active)) anchorRef.current?.focus();
|
|
26292
26380
|
};
|
|
@@ -26324,11 +26412,11 @@ var init_renderNode = __esm({
|
|
|
26324
26412
|
setOpen((v) => !v);
|
|
26325
26413
|
}
|
|
26326
26414
|
},
|
|
26327
|
-
style: { display: "inline-flex", alignItems: "center", cursor: "pointer" },
|
|
26415
|
+
style: { display: "inline-flex", alignItems: "center", justifyContent: "center", minWidth: 44, minHeight: 44, cursor: "pointer" },
|
|
26328
26416
|
children: props.anchor ? renderNode(props.anchor, ctx) : iconSvg("more", { size: 20, color: C("textSecondary", "#636b78") })
|
|
26329
26417
|
}
|
|
26330
26418
|
),
|
|
26331
|
-
open && wrapModalMenu(modal, anchorLabel, popupPlacement, /* @__PURE__ */ jsx6(
|
|
26419
|
+
open && wrapModalMenu(modal, anchorLabel, popupPlacement, dialogRef, /* @__PURE__ */ jsx6(
|
|
26332
26420
|
"div",
|
|
26333
26421
|
{
|
|
26334
26422
|
ref: menuRef,
|
|
@@ -27390,7 +27478,7 @@ var init_renderNode = __esm({
|
|
|
27390
27478
|
const tAlign = props.textAlign === "center" ? "center" : props.textAlign === "trailing" ? "right" : props.textAlign === "justify" ? "justify" : props.textAlign === "leading" ? "left" : void 0;
|
|
27391
27479
|
const tDecor = props.decoration === "strikethrough" ? "line-through" : props.decoration === "underline" ? "underline" : void 0;
|
|
27392
27480
|
const ln = typeof props.lineSpacing === "number" ? pxToRem((f.line ?? 1.4) * f.size + props.lineSpacing) : f.line;
|
|
27393
|
-
return /* @__PURE__ */ jsx6("div", { ...countAttrs, style: { fontFamily: fontStack(f.family, ctx.idiom), fontSize: f.remSize, fontWeight: f.weight, lineHeight: ln, letterSpacing: f.letterSpacing, color: C(resolveScalarStatic(props.color, ctx) ?? "textPrimary", "#13171e"), whiteSpace: "pre-wrap", overflowWrap: "anywhere", wordBreak: "break-word", minWidth: 0, ...tAlign ? { textAlign: tAlign } : {}, ...tDecor ? { textDecoration: tDecor } : {}, ...props.maxLines ? { display: "-webkit-box", WebkitLineClamp: props.maxLines, WebkitBoxOrient: "vertical", overflow: "hidden" } : {}, ...wrap }, children: content == null || content === "" ? collapse ? null : "\xA0" : content });
|
|
27481
|
+
return /* @__PURE__ */ jsx6("div", { ...countAttrs, style: { fontFamily: fontStack(f.family, ctx.idiom), fontSize: f.remSize, fontWeight: f.weight, lineHeight: ln, letterSpacing: f.letterSpacing, color: C(resolveScalarStatic(props.color, ctx) ?? "textPrimary", "#13171e"), whiteSpace: props.maxLines === 1 ? "nowrap" : "pre-wrap", overflowWrap: "anywhere", wordBreak: "break-word", minWidth: 0, ...tAlign ? { textAlign: tAlign } : {}, ...tDecor ? { textDecoration: tDecor } : {}, ...props.maxLines === 1 ? { overflow: "hidden", textOverflow: "ellipsis" } : props.maxLines ? { display: "-webkit-box", WebkitLineClamp: props.maxLines, WebkitBoxOrient: "vertical", overflow: "hidden" } : {}, ...wrap }, children: content == null || content === "" ? collapse ? null : "\xA0" : content });
|
|
27394
27482
|
});
|
|
27395
27483
|
ImageNode = withExtras("ImageNode", ({ props, ctx, wrap }) => {
|
|
27396
27484
|
const C = ctx.color;
|
|
@@ -28266,18 +28354,23 @@ var init_renderNode = __esm({
|
|
|
28266
28354
|
const next = multiSelect ? isSel ? selected.filter((x) => x !== id) : [...selected, id] : isSel ? [] : [id];
|
|
28267
28355
|
ctx.onAction({ ...onChange, args: { ...onChange.args ?? {}, selectedIds: next } });
|
|
28268
28356
|
};
|
|
28269
|
-
return
|
|
28270
|
-
|
|
28271
|
-
|
|
28272
|
-
|
|
28273
|
-
|
|
28274
|
-
|
|
28275
|
-
|
|
28276
|
-
|
|
28277
|
-
|
|
28278
|
-
|
|
28279
|
-
|
|
28280
|
-
|
|
28357
|
+
return (
|
|
28358
|
+
// ONE horizontally scrolling row, like the iOS ScrollView(.horizontal) and the
|
|
28359
|
+
// Android LazyRow. Wrapping here turned a long filter set into a ragged grid and
|
|
28360
|
+
// pushed a sibling count onto two lines (#3080, #3004).
|
|
28361
|
+
/* @__PURE__ */ jsx6("div", { role: "group", style: { display: "flex", gap: 8, flexWrap: "nowrap", overflowX: "auto", scrollbarWidth: "none", width: "100%", minWidth: 0, ...wrap }, children: chips.map((c, i) => {
|
|
28362
|
+
const on3 = selected.includes(c.id);
|
|
28363
|
+
const chipStyle = { display: "flex", flex: "none", whiteSpace: "nowrap", gap: 6, alignItems: "center", fontFamily: bodyFont(ctx), fontWeight: 500, fontSize: 13, border: `1px solid ${on3 ? "transparent" : C("border", "#ddd")}`, background: on3 ? C("accentPrimary", "#116DFF") : "transparent", color: on3 ? C("textOnAccent", "#fff") : C("textSecondary", "#666"), padding: "6px 12px", borderRadius: 999 };
|
|
28364
|
+
const inner = /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
28365
|
+
asText2(c.label),
|
|
28366
|
+
c.count != null && /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
28367
|
+
" ",
|
|
28368
|
+
/* @__PURE__ */ jsx6("span", { style: { opacity: 0.7, fontSize: 11 }, children: c.count })
|
|
28369
|
+
] })
|
|
28370
|
+
] });
|
|
28371
|
+
return interactive ? /* @__PURE__ */ jsx6("button", { type: "button", "aria-pressed": on3, onClick: () => toggle(c.id), style: { all: "unset", cursor: "pointer", boxSizing: "border-box", ...chipStyle }, children: inner }, c.id ?? i) : /* @__PURE__ */ jsx6("span", { style: chipStyle, children: inner }, c.id ?? i);
|
|
28372
|
+
}) })
|
|
28373
|
+
);
|
|
28281
28374
|
});
|
|
28282
28375
|
TILE_PX = 256;
|
|
28283
28376
|
MAX_MERCATOR_LAT = 85.05112878;
|
|
@@ -32791,18 +32884,18 @@ function startBundleArtifactWatcher(state) {
|
|
|
32791
32884
|
});
|
|
32792
32885
|
};
|
|
32793
32886
|
try {
|
|
32794
|
-
const
|
|
32887
|
+
const watcher2 = watch(TIER5_ROOT2, { persistent: false }, (_event, filename) => {
|
|
32795
32888
|
const bundle = builtBundleName(filename);
|
|
32796
32889
|
if (!bundle) return;
|
|
32797
32890
|
pending.add(bundle);
|
|
32798
32891
|
if (timer) clearTimeout(timer);
|
|
32799
32892
|
timer = setTimeout(flush, 120);
|
|
32800
32893
|
});
|
|
32801
|
-
|
|
32894
|
+
watcher2.on("error", (err) => {
|
|
32802
32895
|
console.warn(`[himalaya-dev] bundle watcher stopped: ${err.message}`);
|
|
32803
32896
|
});
|
|
32804
32897
|
console.log(`[himalaya-dev] watching built bundles: ${TIER5_ROOT2}`);
|
|
32805
|
-
return
|
|
32898
|
+
return watcher2;
|
|
32806
32899
|
} catch (err) {
|
|
32807
32900
|
console.warn(`[himalaya-dev] bundle watcher unavailable: ${err.message}`);
|
|
32808
32901
|
return void 0;
|
|
@@ -32837,7 +32930,7 @@ function startBundleSourceWatcher(state) {
|
|
|
32837
32930
|
building = false;
|
|
32838
32931
|
};
|
|
32839
32932
|
try {
|
|
32840
|
-
const
|
|
32933
|
+
const watcher2 = watch(TIER5_SRC_ROOT, { persistent: false, recursive: true }, (_event, filename) => {
|
|
32841
32934
|
if (!filename || !/\.(ts|tsx)$/.test(filename)) return;
|
|
32842
32935
|
const name = filename.split(sep7)[0];
|
|
32843
32936
|
if (!name || name.startsWith(".")) return;
|
|
@@ -32845,11 +32938,11 @@ function startBundleSourceWatcher(state) {
|
|
|
32845
32938
|
if (timer) clearTimeout(timer);
|
|
32846
32939
|
timer = setTimeout(flush, 200);
|
|
32847
32940
|
});
|
|
32848
|
-
|
|
32941
|
+
watcher2.on("error", (err) => {
|
|
32849
32942
|
console.warn(`[himalaya-dev] bundle source watcher stopped: ${err.message}`);
|
|
32850
32943
|
});
|
|
32851
32944
|
console.log(`[himalaya-dev] watching T5 bundle sources: ${TIER5_SRC_ROOT}`);
|
|
32852
|
-
return
|
|
32945
|
+
return watcher2;
|
|
32853
32946
|
} catch (err) {
|
|
32854
32947
|
console.warn(`[himalaya-dev] bundle source watcher unavailable: ${err.message}`);
|
|
32855
32948
|
return void 0;
|
|
@@ -33017,7 +33110,7 @@ function startAppSourceWatcher(state) {
|
|
|
33017
33110
|
}
|
|
33018
33111
|
};
|
|
33019
33112
|
try {
|
|
33020
|
-
const
|
|
33113
|
+
const watcher2 = watch(appDir2, { persistent: false, recursive: true }, (_event, filename) => {
|
|
33021
33114
|
if (!filename) return;
|
|
33022
33115
|
const rel = String(filename).split(sep7).join("/");
|
|
33023
33116
|
if (!classifyAppPath(rel)) return;
|
|
@@ -33025,11 +33118,11 @@ function startAppSourceWatcher(state) {
|
|
|
33025
33118
|
if (timer) clearTimeout(timer);
|
|
33026
33119
|
timer = setTimeout(flush, 200);
|
|
33027
33120
|
});
|
|
33028
|
-
|
|
33121
|
+
watcher2.on("error", (err) => {
|
|
33029
33122
|
console.warn(`[himalaya-dev] app source watcher stopped: ${err.message}`);
|
|
33030
33123
|
});
|
|
33031
33124
|
console.log(`[himalaya-dev] watching app source: ${appDir2}`);
|
|
33032
|
-
return
|
|
33125
|
+
return watcher2;
|
|
33033
33126
|
} catch (err) {
|
|
33034
33127
|
console.warn(`[himalaya-dev] app source watcher unavailable: ${err.message}`);
|
|
33035
33128
|
return void 0;
|
|
@@ -35699,10 +35792,10 @@ function cmsAnswer(seed2, method, bare, body) {
|
|
|
35699
35792
|
pagingMetadata: { count: rows.length, tooManyToCount: false }
|
|
35700
35793
|
};
|
|
35701
35794
|
}
|
|
35702
|
-
function layeredTransport(
|
|
35703
|
-
const rules =
|
|
35704
|
-
const cms =
|
|
35705
|
-
const canned =
|
|
35795
|
+
function layeredTransport(layers2) {
|
|
35796
|
+
const rules = layers2.rules?.length ? [...layers2.rules] : null;
|
|
35797
|
+
const cms = layers2.cmsSeed && Object.keys(layers2.cmsSeed).length ? layers2.cmsSeed : null;
|
|
35798
|
+
const canned = layers2.canned && Object.keys(layers2.canned).length ? layers2.canned : null;
|
|
35706
35799
|
const label2 = [rules && "mocked", cms && "cms", canned && "canned"].filter(Boolean).join("+") || "offline";
|
|
35707
35800
|
const call = async (method, path2, body) => {
|
|
35708
35801
|
const m = String(method).toUpperCase();
|
|
@@ -39032,6 +39125,332 @@ var init_net_freeze = __esm({
|
|
|
39032
39125
|
}
|
|
39033
39126
|
});
|
|
39034
39127
|
|
|
39128
|
+
// src/studio-page.ts
|
|
39129
|
+
function renderStudioHtml(initial) {
|
|
39130
|
+
const accent = initial.app.palette.find((p) => p.name === "accentPrimary")?.hex ?? "#3b6fd8";
|
|
39131
|
+
return `<!doctype html>
|
|
39132
|
+
<html lang="en">
|
|
39133
|
+
<head>
|
|
39134
|
+
<meta charset="utf-8">
|
|
39135
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
39136
|
+
<title>${escapeHtml(initial.app.name)} \xB7 build board</title>
|
|
39137
|
+
<link rel="icon" id="fav" href="data:,">
|
|
39138
|
+
<style>
|
|
39139
|
+
:root{--bg:#f6f5f2;--card:#fff;--ink:#1c1c1a;--muted:#6b6a64;--faint:#a3a19a;--line:#e6e3dc;--ok:#1f7a4d;--okbg:#e3f3ea;--warn:#8a5a00;--warnbg:#fbefd6;--bad:#a12a2a;--badbg:#fbe4e4;--accent:${accent};--shadow:0 1px 2px rgba(0,0,0,.04),0 4px 16px rgba(0,0,0,.04)}
|
|
39140
|
+
@media (prefers-color-scheme:dark){:root{--bg:#121211;--card:#1c1c1a;--ink:#ecebe6;--muted:#a3a19a;--faint:#6b6a64;--line:#2c2b28;--okbg:#15301f;--ok:#7fd3a2;--warnbg:#33270f;--warn:#f0c46b;--badbg:#3a1616;--bad:#f09a9a;--shadow:none}}
|
|
39141
|
+
*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--ink);font:14px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif}
|
|
39142
|
+
.wrap{max-width:1180px;margin:0 auto;padding:20px 20px 60px}
|
|
39143
|
+
header{display:flex;align-items:center;gap:12px;margin-bottom:16px}
|
|
39144
|
+
.icon{width:40px;height:40px;border-radius:10px;background:var(--accent);object-fit:cover;flex:none}
|
|
39145
|
+
h1{font-size:20px;font-weight:600;margin:0}.sub{color:var(--muted);font-size:13px}
|
|
39146
|
+
.right{margin-left:auto;text-align:right}.clock{font-size:22px;font-variant-numeric:tabular-nums;font-weight:600}
|
|
39147
|
+
.live{display:inline-flex;align-items:center;gap:6px;color:var(--muted);font-size:12px}.dot{width:8px;height:8px;border-radius:50%;background:var(--ok)}.stale .dot{background:var(--faint)}
|
|
39148
|
+
.steps{display:grid;grid-template-columns:repeat(8,1fr);gap:6px;margin:4px 0 16px}.step .bar{height:6px;border-radius:3px;background:var(--line)}.step.done .bar{background:var(--ok)}.step.cur .bar{background:var(--accent)}
|
|
39149
|
+
.step .lbl{font-size:11px;color:var(--faint);margin-top:4px;text-transform:capitalize}.step.cur .lbl{color:var(--ink);font-weight:600}
|
|
39150
|
+
.card{background:var(--card);border:1px solid var(--line);border-radius:14px;padding:14px 16px;box-shadow:var(--shadow)}
|
|
39151
|
+
.now{display:flex;gap:12px;align-items:flex-start;margin-bottom:16px}.now .msg{font-size:16px}.now .meta{color:var(--muted);font-size:12px}
|
|
39152
|
+
.grid{display:grid;grid-template-columns:320px 1fr;gap:16px;align-items:start}@media (max-width:860px){.grid{grid-template-columns:1fr}.steps .lbl{display:none}}
|
|
39153
|
+
h2{font-size:12px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.04em;margin:0 0 10px}
|
|
39154
|
+
.phone{width:100%;max-width:300px;aspect-ratio:390/844;border-radius:34px;border:9px solid #111;background:#fff;overflow:hidden;margin:0 auto;display:block}
|
|
39155
|
+
.phone img,.phone iframe{width:100%;height:100%;object-fit:cover;object-position:top;border:0;display:block;cursor:zoom-in}
|
|
39156
|
+
.phone.vpf{position:relative}.phone iframe.vp{position:absolute;top:0;left:0;width:390px;height:844px;transform-origin:0 0;transform:scale(var(--k,.72));cursor:auto}
|
|
39157
|
+
.cap{text-align:center;color:var(--muted);font-size:12px;margin-top:8px}
|
|
39158
|
+
.film{display:flex;gap:6px;overflow-x:auto;margin-top:12px;padding-bottom:4px}.film img{width:48px;aspect-ratio:390/844;object-fit:cover;object-position:top;border-radius:8px;border:1px solid var(--line);cursor:zoom-in}
|
|
39159
|
+
.chips{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:16px}.chip{font-size:12px;padding:5px 10px;border-radius:999px;background:var(--card);border:1px solid var(--line);color:var(--muted)}
|
|
39160
|
+
.chip.ok{background:var(--okbg);color:var(--ok);border-color:transparent}.chip.warn{background:var(--warnbg);color:var(--warn);border-color:transparent}.chip.bad{background:var(--badbg);color:var(--bad);border-color:transparent}
|
|
39161
|
+
.wall{display:grid;grid-template-columns:repeat(auto-fill,minmax(112px,1fr));gap:14px}
|
|
39162
|
+
.shot{text-align:center}.shot .frame{aspect-ratio:390/844;border-radius:16px;border:5px solid #111;overflow:hidden;background:#fff}.shot img{width:100%;height:100%;object-fit:cover;object-position:top;display:block;cursor:zoom-in}
|
|
39163
|
+
.shot .id{font-size:12px;margin-top:6px;word-break:break-all}.badge{display:inline-block;font-size:10px;padding:1px 7px;border-radius:999px;margin-top:3px}.badge.new{background:var(--okbg);color:var(--ok)}.badge.chg{background:var(--warnbg);color:var(--warn)}
|
|
39164
|
+
.section{margin-bottom:16px}.brand{display:flex;gap:14px;align-items:center;flex-wrap:wrap}.brand .site{width:220px;border-radius:10px;border:1px solid var(--line);cursor:zoom-in}
|
|
39165
|
+
.sw{display:flex;gap:6px}.sw span{width:22px;height:22px;border-radius:50%;border:1px solid var(--line)}
|
|
39166
|
+
.nav{display:flex;flex-wrap:wrap;gap:6px}.nav span{font-size:12px;padding:3px 8px;border-radius:6px;background:var(--bg);border:1px solid var(--line)}
|
|
39167
|
+
.log{list-style:none;margin:0;padding:0}.log li{display:flex;gap:10px;padding:10px 0;border-top:1px solid var(--line)}.log li:first-child{border-top:0}
|
|
39168
|
+
.log .t{color:var(--faint);font-size:12px;min-width:64px;font-variant-numeric:tabular-nums}.log .s{font-size:11px;color:var(--muted);text-transform:capitalize}.log .imgs{display:flex;gap:6px;margin-top:6px}.log .imgs img{height:72px;border-radius:8px;border:1px solid var(--line);cursor:zoom-in}
|
|
39169
|
+
.empty{color:var(--faint);font-size:13px;padding:8px 0}
|
|
39170
|
+
#lb{position:fixed;inset:0;background:rgba(0,0,0,.72);display:none;align-items:center;justify-content:center;z-index:9;cursor:zoom-out}#lb img{max-height:92vh;max-width:92vw;border-radius:14px;background:#fff}
|
|
39171
|
+
.enter{animation:enter .7s cubic-bezier(.2,.8,.2,1) both}@keyframes enter{from{opacity:0;transform:translateY(10px) scale(.94);filter:grayscale(1)}to{opacity:1;transform:none;filter:none}}
|
|
39172
|
+
.changed .frame{animation:chg .9s ease both}@keyframes chg{35%{opacity:.25;transform:scale(.96)}100%{opacity:1;transform:none}}
|
|
39173
|
+
.step.fresh .bar{animation:fill .7s ease both;transform-origin:left}@keyframes fill{from{transform:scaleX(0)}to{transform:scaleX(1)}}
|
|
39174
|
+
.slidein{animation:slide .45s cubic-bezier(.2,.8,.2,1) both}@keyframes slide{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}
|
|
39175
|
+
.phone.pulse{animation:pulse 1s ease-out}.phone.pulse.bad{animation-name:pulsebad}@keyframes pulse{from{outline:3px solid var(--ok);outline-offset:0}to{outline:3px solid transparent;outline-offset:10px}}@keyframes pulsebad{from{outline:3px solid var(--bad);outline-offset:0}to{outline:3px solid transparent;outline-offset:10px}}
|
|
39176
|
+
.toast{display:block;width:max-content;max-width:100%;margin:8px auto 0;font-size:12px;padding:4px 10px;border-radius:999px;background:var(--okbg);color:var(--ok);animation:toast 3.4s ease both}.toast.bad{background:var(--badbg);color:var(--bad)}@keyframes toast{0%{opacity:0;transform:translateY(4px)}10%,80%{opacity:1;transform:none}100%{opacity:0}}
|
|
39177
|
+
.icon,.step.cur .bar{transition:background-color .8s}.sw.pop span{animation:pop .6s ease both}@keyframes pop{50%{transform:scale(1.25)}}
|
|
39178
|
+
.quiet{color:var(--warn)}.quiet .dot{background:var(--warn)}.idle .dot{background:var(--faint)}
|
|
39179
|
+
.tog{font:inherit;font-size:12px;color:var(--muted);background:none;border:1px solid var(--line);border-radius:999px;padding:2px 9px;margin:6px 0 0 6px;cursor:pointer}.tog.on{color:var(--ink);border-color:var(--ink)}
|
|
39180
|
+
#fx{position:fixed;inset:0;width:100%;height:100%;pointer-events:none;z-index:8}
|
|
39181
|
+
@media (max-width:560px){header{flex-wrap:wrap}.right{margin-left:0;width:100%;text-align:left;display:flex;flex-wrap:wrap;align-items:center;gap:4px 12px}.right .clock{font-size:18px}.tog{margin:0 6px 0 0}}
|
|
39182
|
+
.scrub{display:flex;align-items:center;gap:8px;margin:-6px 0 4px}.scrub[hidden]{display:none}.scrub input{flex:1;min-width:0}
|
|
39183
|
+
.scrub .rd{font-size:12px;color:var(--muted);min-width:160px;font-variant-numeric:tabular-nums}
|
|
39184
|
+
.marks{position:relative;height:8px;margin:0 9px 12px}.marks span{position:absolute;top:0;width:7px;height:7px;border-radius:50%;background:var(--faint);transform:translateX(-50%)}.marks .ms{background:var(--warn)}.marks .bad{background:var(--bad)}
|
|
39185
|
+
.viewing{font-size:13px;padding:6px 10px;border-radius:8px;background:var(--warnbg);color:var(--warn);margin:0 0 12px}.viewing[hidden]{display:none}.viewing a{color:inherit}
|
|
39186
|
+
.newdot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--bad);margin-left:6px;vertical-align:middle}.newdot[hidden]{display:none}
|
|
39187
|
+
#focus[hidden],#still[hidden]{display:none}
|
|
39188
|
+
.reveal{position:fixed;inset:0;z-index:7;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.5)}.reveal[hidden]{display:none}
|
|
39189
|
+
.rv{background:var(--card);border-radius:16px;padding:18px;max-width:760px;width:calc(100% - 32px)}.rv h3{margin:0;font-size:18px}.rv .row{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px;margin-top:12px}
|
|
39190
|
+
.rv figure{margin:0}.rv figcaption{font-size:12px;color:var(--muted);margin-bottom:6px}.rv .site img{width:100%;border-radius:10px;border:1px solid var(--line)}
|
|
39191
|
+
.rv .ph{position:relative;aspect-ratio:390/844;max-height:60vh;border-radius:22px;border:6px solid #111;overflow:hidden;background:#fff;margin:0 auto}.rv .ph img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:top}
|
|
39192
|
+
.rv .after{clip-path:inset(0 100% 0 0);transition:clip-path 1.4s cubic-bezier(.6,0,.2,1)}.rv.on .after{clip-path:inset(0 0 0 0)}
|
|
39193
|
+
@media (prefers-reduced-motion:reduce){.rv .after{transition:none}.enter,.changed .frame,.step.fresh .bar,.slidein,.phone.pulse,.sw.pop span,.toast{animation:none}.icon,.step.cur .bar{transition:none}}
|
|
39194
|
+
</style>
|
|
39195
|
+
</head>
|
|
39196
|
+
<body>
|
|
39197
|
+
<div class="wrap">
|
|
39198
|
+
<header><img class="icon" id="icon" alt=""><div><h1 id="name"></h1><div class="sub">Build board \xB7 updates itself as the app is built</div></div>
|
|
39199
|
+
<div class="right"><div class="clock" id="clock">00:00</div><div class="live" id="live"><span class="dot"></span><span id="updated">live</span></div>
|
|
39200
|
+
<div><span class="live idle" id="agent"><span class="dot"></span><span id="agentt">Waiting for the agent</span></span></div>
|
|
39201
|
+
<div><button class="tog" id="snd" type="button" aria-pressed="false">Sound off</button><button class="tog" id="say" type="button" aria-pressed="false" hidden>Read aloud: off</button><button class="tog" id="ntf" type="button" aria-pressed="false" hidden>Notices off</button></div></div></header>
|
|
39202
|
+
<div class="steps" id="steps"></div>
|
|
39203
|
+
<div class="scrub" id="scrub" hidden><button class="tog" id="replay" type="button">Replay</button><input type="range" id="slider" min="0" max="1" step="1" value="1" aria-label="Build timeline"><span class="rd" id="readout"></span><button class="tog" id="golive" type="button">Live<span class="newdot" id="newdot" hidden></span></button></div>
|
|
39204
|
+
<div class="marks" id="marks"></div>
|
|
39205
|
+
<div class="viewing" id="viewing" hidden>Viewing <span id="viewingt"></span> \xB7 <a href="#" id="backlive">Back to live</a></div>
|
|
39206
|
+
<div class="card now"><div style="flex:1"><div class="meta" id="nowmeta">Now</div><div class="msg" id="nowmsg"></div></div></div>
|
|
39207
|
+
<div class="grid">
|
|
39208
|
+
<div><div class="card"><h2 id="focuslbl">Latest</h2><div id="focus"></div><div id="still" hidden></div><div class="film" id="film"></div>
|
|
39209
|
+
<button class="tog" id="pop" type="button" hidden>Pop out phone</button></div></div>
|
|
39210
|
+
<div>
|
|
39211
|
+
<div class="chips" id="chips"></div>
|
|
39212
|
+
<div class="card section"><h2>Screens</h2><div class="wall" id="wall"></div></div>
|
|
39213
|
+
<div class="card section" id="brandcard"><h2>Brand</h2><div class="brand" id="brand"></div></div>
|
|
39214
|
+
<div class="card section" id="navcard"><h2>Navigation the test crawl followed</h2><div class="nav" id="nav"></div></div>
|
|
39215
|
+
<div class="card section"><h2>Postcards</h2><ul class="log" id="log"></ul></div>
|
|
39216
|
+
</div></div></div>
|
|
39217
|
+
<div id="lb"><img alt=""></div>
|
|
39218
|
+
<div class="reveal" id="reveal" hidden role="dialog" aria-labelledby="rvh"><div class="rv" id="rv"><div style="display:flex;justify-content:space-between;align-items:center;gap:12px"><h3 id="rvh">Your brand, in your app</h3><button class="tog" id="rvx" type="button">Close</button></div><div class="row" id="rvrow"></div></div></div>
|
|
39219
|
+
<canvas id="fx" aria-hidden="true"></canvas>
|
|
39220
|
+
<script>window.__himiInitial = ${scriptJson(initial)};</script>
|
|
39221
|
+
<script>
|
|
39222
|
+
(function(){
|
|
39223
|
+
var cur=null, lastSeen=Date.now();
|
|
39224
|
+
function $(id){return document.getElementById(id)}
|
|
39225
|
+
function el(tag,cls,txt){var e=document.createElement(tag);if(cls)e.className=cls;if(txt!=null)e.textContent=txt;return e}
|
|
39226
|
+
function clear(e){while(e.firstChild)e.removeChild(e.firstChild)}
|
|
39227
|
+
function nowMs(){return asOf||Date.now()}
|
|
39228
|
+
function ago(ts){var s=Math.max(0,Math.round((nowMs()-Date.parse(ts))/1000));if(s<60)return s+"s ago";var m=Math.round(s/60);if(m<60)return m+" min ago";return Math.round(m/60)+" h ago"}
|
|
39229
|
+
function hhmm(ts){var d=new Date(ts);return d.toLocaleTimeString([], {hour:"2-digit",minute:"2-digit"})}
|
|
39230
|
+
function recent(ts){return nowMs()-Date.parse(ts)<10*60*1000}
|
|
39231
|
+
function zoomable(img){img.addEventListener("click",function(){var lb=$("lb");lb.firstChild.src=img.src;lb.style.display="flex"})}
|
|
39232
|
+
function img(src,cls){var i=el("img",cls);i.src=src;i.alt="";i.loading="lazy";zoomable(i);return i}
|
|
39233
|
+
function chip(txt,kind){return el("span","chip"+(kind?" "+kind:""),txt)}
|
|
39234
|
+
function render(s){
|
|
39235
|
+
var sn=s.current?s.current.stepNumber:0;document.title=(sn?"("+sn+"/8) ":"")+s.app.name+" \xB7 build board";favicon(sn,!!(s.live&&s.live.buildError));$("name").textContent=s.app.name;
|
|
39236
|
+
if(s.app.icon){$("icon").src=s.app.icon}else{$("icon").removeAttribute("src")}
|
|
39237
|
+
var steps=$("steps");clear(steps);var n=s.current?s.current.stepNumber:0;
|
|
39238
|
+
s.steps.forEach(function(name,i){var d=el("div","step"+(i+1<n?" done":i+1===n?" cur":""));d.appendChild(el("div","bar"));d.appendChild(el("div","lbl",(i+1)+". "+name));steps.appendChild(d)});
|
|
39239
|
+
var last=s.journal[0];
|
|
39240
|
+
$("nowmsg").textContent=last?last.message:"Waiting for the first postcard.";
|
|
39241
|
+
$("nowmeta").textContent=last?("Now \xB7 "+(last.step?("step "+last.stepNumber+" of 8, "+last.step+" \xB7 "):"")+ago(last.ts)):"Now";
|
|
39242
|
+
var film=$("film");clear(film);
|
|
39243
|
+
if(!rewinding){var n0=s.timelineFrames||0;$("scrub").hidden=n0<2;$("slider").max=String(Math.max(1,n0-1));$("slider").value=$("slider").max}
|
|
39244
|
+
if(rewinding){paintStill(s)}else{$("still").hidden=true;$("focus").hidden=false;var focus=$("focus");
|
|
39245
|
+
/* The live frame is KEPT across renders while its URL and its run are unchanged (a restarted run on
|
|
39246
|
+
the same port is a different server, and the old frame would never see its builds). A new iframe is a full page
|
|
39247
|
+
load of the preview: every postcard, rebuild and the once-a-minute re-render used to throw away
|
|
39248
|
+
the in-place repaint, the preview's scroll and wherever the owner had navigated inside it. */
|
|
39249
|
+
if(pip&&(!s.live||pip.frame.getAttribute("src")!==s.live.url||pip.frame.getAttribute("data-run")!==s.live.runId))bringBack();
|
|
39250
|
+
if(pip){paintStrip(s)}else{
|
|
39251
|
+
var kept=s.live?focus.querySelector("iframe"):null;if(kept&&(kept.getAttribute("src")!==s.live.url||kept.getAttribute("data-run")!==s.live.runId))kept=null;
|
|
39252
|
+
if(kept){while(focus.lastChild&&focus.lastChild!==kept.parentNode)focus.removeChild(focus.lastChild)}else clear(focus);
|
|
39253
|
+
if(s.live){$("focuslbl").textContent="Live preview";if(!kept){var f=el("div","phone vpf");var fr=document.createElement("iframe");fr.className="vp";fr.setAttribute("width","390");fr.setAttribute("height","844");fr.setAttribute("data-run",s.live.runId);fr.src=s.live.url;fr.title="Live preview";f.appendChild(fr);focus.appendChild(f)}fit();if(s.live.buildError){var be=el("div","chip bad",null);be.style.display="block";be.style.marginTop="8px";be.textContent="Last edit did not build, still showing the last good version: "+s.live.buildError;focus.appendChild(be)}focus.appendChild(el("div","cap",(s.live.watching?"Repaints as the app is edited \xB7 ":"The build this run started with; himi run --watch repaints on every edit \xB7 ")+s.live.url))}
|
|
39254
|
+
else if(s.focus&&s.focus.frames.length){var fl=s.focus.frames;$("focuslbl").textContent="Latest \xB7 "+s.focus.id;var p=el("div","phone");p.appendChild(img(fl[fl.length-1].img));focus.appendChild(p);focus.appendChild(el("div","cap",fl.length+(fl.length===1?" version":" versions")+" so far"))}
|
|
39255
|
+
else{$("focuslbl").textContent="Latest";focus.appendChild(el("div","empty","The first render appears here."))}
|
|
39256
|
+
if(s.focus&&s.focus.frames.length>1)s.focus.frames.forEach(function(fm){film.appendChild(img(fm.img))});}}
|
|
39257
|
+
var chips=$("chips");clear(chips);var h=s.health;
|
|
39258
|
+
if(h.validate)chips.appendChild(chip(h.validate.ok?"Validate passing":"Validate: "+h.validate.errors+" errors",h.validate.ok?"ok":"bad"));
|
|
39259
|
+
if(h.test){var t=h.test;var moved=t.prevGaps!=null&&t.prevGaps!==t.gaps;var tc=chip("Test crawl: "+t.screens+" screens, "+t.actions+" actions, "+(moved?"gaps "+t.prevGaps+" \u2192 ":""),t.ok?"ok":"bad");var gn=el("span",null,String(t.gaps));gn.id="gapn";tc.appendChild(gn);if(!moved)tc.appendChild(document.createTextNode(" gaps"));chips.appendChild(tc)}
|
|
39260
|
+
h.ux.forEach(function(u){chips.appendChild(chip("UX drive "+u.platform+": "+u.status,u.status==="passed"?"ok":u.status==="failed"?"bad":"warn"))});
|
|
39261
|
+
if(h.push)chips.appendChild(chip((h.push.draft?"Draft published":"Published live")+" \xB7 "+h.push.releaseId.slice(0,10),h.push.draft?"warn":"ok"));
|
|
39262
|
+
if(!chips.firstChild)chips.appendChild(chip("Checks appear here as validate, test and push run"));
|
|
39263
|
+
var wall=$("wall");clear(wall);
|
|
39264
|
+
if(!s.screens.length)wall.appendChild(el("div","empty","Screens appear here as they render."));
|
|
39265
|
+
s.screens.forEach(function(sc){var d=el("div","shot");d.setAttribute("data-id",sc.id);var fr=el("div","frame");fr.appendChild(img(sc.img));d.appendChild(fr);d.appendChild(el("div","id",sc.id));
|
|
39266
|
+
if(recent(sc.firstSeen)&&sc.versions===1)d.appendChild(el("span","badge new","New"));else if(recent(sc.changedAt)&&sc.versions>1)d.appendChild(el("span","badge chg","Changed"));wall.appendChild(d)});
|
|
39267
|
+
var brand=$("brand");clear(brand);$("brandcard").style.display=(s.brand.site||s.app.palette.length)?"":"none";
|
|
39268
|
+
if(s.brand.site){var si=img(s.brand.site,"site");brand.appendChild(si)}
|
|
39269
|
+
if(s.brand.site&&s.focus&&s.focus.frames.length){brand.appendChild(el("span","sub","\u2192"));var pf=el("div","shot");pf.style.width="90px";var ff=el("div","frame");ff.appendChild(img(s.focus.frames[s.focus.frames.length-1].img));pf.appendChild(ff);brand.appendChild(pf)}
|
|
39270
|
+
if(s.app.palette.length){var sw=el("div","sw");s.app.palette.forEach(function(c){var d=el("span");d.style.background=c.hex;d.title=c.name+" "+c.hex;sw.appendChild(d)});brand.appendChild(sw)}
|
|
39271
|
+
var nav=$("nav");clear(nav);$("navcard").style.display=s.nav.length?"":"none";s.nav.forEach(function(e){nav.appendChild(el("span",null,e.from+" \u2192 "+e.to))});
|
|
39272
|
+
var log=$("log");clear(log);if(!s.journal.length)log.appendChild(el("li","empty","Postcards the agent journals appear here."));
|
|
39273
|
+
s.journal.forEach(function(j){var li=el("li");li.appendChild(el("div","t",hhmm(j.ts)));var body=el("div");body.appendChild(el("div",null,j.message));if(j.step)body.appendChild(el("div","s","step "+j.stepNumber+" \xB7 "+j.step));
|
|
39274
|
+
if(j.images.length){var row=el("div","imgs");j.images.forEach(function(u){row.appendChild(img(u))});body.appendChild(row)}li.appendChild(body);log.appendChild(li)});
|
|
39275
|
+
paintPop(s);
|
|
39276
|
+
}
|
|
39277
|
+
/* Motion, sound and notices answer a CHANGE, never a redraw: effects() compares what is on the page
|
|
39278
|
+
now with what it showed last, so opening the board, the once-a-minute redraw and the two-second
|
|
39279
|
+
poll of an unchanged state do nothing, and each effect names a real event. */
|
|
39280
|
+
var seen=null,actx=null,sound=false,notices=false;
|
|
39281
|
+
var tlStates=null,rewinding=false,replaying=false,asOf=0,replayTimer=null;
|
|
39282
|
+
function foldAll(frames){var out=[],st=null,meta={};(frames||[]).forEach(function(f){
|
|
39283
|
+
var ns={step:null,now:null,screens:{},palette:[],checks:{validate:null,test:null,push:null},build:null};
|
|
39284
|
+
if(!f.key&&st){ns.step=st.step;ns.now=st.now;for(var k in st.screens)ns.screens[k]=st.screens[k];ns.palette=st.palette;ns.checks=st.checks;ns.build=st.build}
|
|
39285
|
+
if("step" in f)ns.step=f.step;if("now" in f)ns.now=f.now;if(f.palette)ns.palette=f.palette;if(f.checks)ns.checks=f.checks;if("build" in f)ns.build=f.build;
|
|
39286
|
+
var sc=f.screens||{};for(var id in sc){if(sc[id]===null)delete ns.screens[id];else ns.screens[id]=sc[id]}
|
|
39287
|
+
for(var j in ns.screens){var m=meta[j];if(!m)meta[j]={first:f.ts,changed:f.ts,img:ns.screens[j],n:1};else if(m.img!==ns.screens[j]){m.changed=f.ts;m.img=ns.screens[j];m.n++}}
|
|
39288
|
+
var copy={};for(var q in meta)copy[q]={first:meta[q].first,changed:meta[q].changed,n:meta[q].n};
|
|
39289
|
+
ns.meta=copy;ns.ts=f.ts;ns.reveal=f.reveal||null;out.push(ns);st=ns});return out}
|
|
39290
|
+
function viewAt(i){var st=tlStates[i],b=cur;
|
|
39291
|
+
var screens=Object.keys(st.screens).sort().map(function(id){var m=st.meta[id];return{id:id,img:st.screens[id],firstSeen:m.first,changedAt:m.changed,versions:m.n}});
|
|
39292
|
+
var t=st.checks.test,prevGaps=null;for(var k=i-1;k>=0&&t;k--){var pt=tlStates[k].checks.test;if(pt&&pt.gaps!==t.gaps){prevGaps=pt.gaps;break}}
|
|
39293
|
+
var fid=b.focus?b.focus.id:null,fimg=fid&&st.screens[fid];
|
|
39294
|
+
return{v:"tl-"+i,generatedAt:st.ts,app:{name:b.app.name,icon:b.app.icon,palette:st.palette.map(function(p){return{name:p[0],hex:p[1]}})},steps:b.steps,
|
|
39295
|
+
current:st.step?{step:st.step.name,stepNumber:st.step.n,of:8}:null,startedAt:b.startedAt,
|
|
39296
|
+
journal:journalAt(st,b),screens:screens,focus:fimg?{id:fid,frames:[{ts:st.ts,img:fimg}]}:null,
|
|
39297
|
+
health:{validate:st.checks.validate?{ok:st.checks.validate.ok,errors:st.checks.validate.errors,warnings:0,at:st.ts}:null,
|
|
39298
|
+
test:t?{ok:t.ok,screens:t.screens,actions:t.actions,gaps:t.gaps,prevGaps:prevGaps,errors:0,at:st.ts}:null,ux:[],
|
|
39299
|
+
push:st.checks.push?{app:"",releaseId:st.checks.push.releaseId,draft:st.checks.push.draft,at:st.ts}:null},
|
|
39300
|
+
brand:b.brand,nav:b.nav,live:null,pastBuild:st.build,reveal:st.reveal?{at:st.ts,site:st.reveal.site,before:st.reveal.before,after:st.reveal.after}:null,timelineFrames:b.timelineFrames}}
|
|
39301
|
+
/* The board keeps only the newest postcards; the timeline remembers the one showing at each moment. */
|
|
39302
|
+
function journalAt(st,b){var jr=b.journal.filter(function(x){return x.ts<=st.ts});if(st.now&&(!jr[0]||jr[0].ts!==st.now.ts))jr.unshift({ts:st.now.ts,message:st.now.message,images:st.now.images,step:st.step?st.step.name:null,stepNumber:st.step?st.step.n:null});return jr}
|
|
39303
|
+
function loadTimeline(cb){window.__himiTimeline=function(frames){tlStates=foldAll(frames);cb()};var sc=document.createElement("script");sc.src="timeline.js?t="+Date.now();sc.onload=sc.onerror=function(){sc.remove()};document.head.appendChild(sc)}
|
|
39304
|
+
function readout(i){var st=tlStates[i],t0=Date.parse(tlStates[0].ts);return hhmm(st.ts)+(st.step?" \xB7 step "+st.step.n+", "+st.step.name:"")+" \xB7 "+Math.round((Date.parse(st.ts)-t0)/60000)+" min in"}
|
|
39305
|
+
function marks(){var m=$("marks");clear(m);var n=tlStates.length;tlStates.forEach(function(st,i){var p=tlStates[i-1],kind=null;
|
|
39306
|
+
if(st.build&&st.build.ok===false&&(!p||p.build!==st.build))kind="bad";
|
|
39307
|
+
else if(st.reveal||(st.checks.push&&(!p||!p.checks.push||p.checks.push.releaseId!==st.checks.push.releaseId))||(st.step&&st.step.n===8&&(!p||!p.step||p.step.n<8)))kind="ms";
|
|
39308
|
+
else if(st.now&&(!p||!p.now||p.now.ts!==st.now.ts))kind="";
|
|
39309
|
+
if(kind===null)return;var d=el("span",kind||null);d.style.left=(n>1?i/(n-1)*100:0)+"%";m.appendChild(d)})}
|
|
39310
|
+
function paintStill(s){$("focus").hidden=true;var still=$("still");still.hidden=false;clear(still);$("focuslbl").textContent="Home at "+hhmm(s.generatedAt);
|
|
39311
|
+
if(s.focus&&s.focus.frames.length){var p=el("div","phone");p.appendChild(img(s.focus.frames[0].img));still.appendChild(p)}else still.appendChild(el("div","empty","No picture of the home screen yet at this moment."))}
|
|
39312
|
+
function rewindTo(i){if(!tlStates||tlStates.length<2)return null;i=Math.max(0,Math.min(tlStates.length-1,i));rewinding=true;asOf=Date.parse(tlStates[i].ts);
|
|
39313
|
+
var sl=$("slider");sl.max=String(tlStates.length-1);sl.value=String(i);var r=readout(i);$("readout").textContent=r;sl.setAttribute("aria-valuetext",r);
|
|
39314
|
+
$("viewing").hidden=false;$("viewingt").textContent=hhmm(tlStates[i].ts);var s=viewAt(i);render(s);return s}
|
|
39315
|
+
function enterRewind(i){loadTimeline(function(){if(!tlStates||tlStates.length<2)return;marks();rewindTo(i==null?tlStates.length-1:i<0?tlStates.length-1+i:i)})}
|
|
39316
|
+
function stopReplay(){replaying=false;if(replayTimer){clearTimeout(replayTimer);replayTimer=null}$("replay").textContent="Replay"}
|
|
39317
|
+
function toLive(){stopReplay();rewinding=false;asOf=0;$("viewing").hidden=true;$("newdot").hidden=true;$("still").hidden=true;$("focus").hidden=false;$("readout").textContent="";seen=snap(cur);if(seen.accent)document.documentElement.style.setProperty("--accent",seen.accent);render(cur)}
|
|
39318
|
+
/* The replay plan: about 30 s whatever the build's length. Frames that carry a milestone (a step,
|
|
39319
|
+
a draft, a failed build, the reveal) always play; the rest are sampled down to 120 moments; gaps
|
|
39320
|
+
follow real time, 150 ms-1.5 s each, and are scaled down so the whole never runs past 30 s. */
|
|
39321
|
+
function replayPlan(){var n=tlStates.length,keep={0:1};keep[n-1]=1;
|
|
39322
|
+
for(var i=1;i<n;i++){var st=tlStates[i],p=tlStates[i-1];if(st.reveal||(st.step&&(!p.step||p.step.n!==st.step.n))||(st.checks.push&&(!p.checks.push||p.checks.push.releaseId!==st.checks.push.releaseId))||(st.build&&st.build.ok===false&&p.build!==st.build))keep[i]=1}
|
|
39323
|
+
var idx=[],MAX=120;if(n<=MAX){for(var a=0;a<n;a++)idx.push(a)}else{var room=MAX-Object.keys(keep).length;for(var k=1;k<=room;k++)keep[Math.round(k*(n-1)/(room+1))]=1;idx=Object.keys(keep).map(Number).sort(function(x,y){return x-y})}
|
|
39324
|
+
var t0=Date.parse(tlStates[0].ts),span=Math.max(1,Date.parse(tlStates[n-1].ts)-t0),gaps=[],sum=0;
|
|
39325
|
+
for(var q=1;q<idx.length;q++){var g=Math.min(1500,Math.max(150,(Date.parse(tlStates[idx[q]].ts)-Date.parse(tlStates[idx[q-1]].ts))/span*30000));gaps.push(g);sum+=g}
|
|
39326
|
+
var f=sum>30000?30000/sum:1;return{idx:idx,gaps:gaps.map(function(x){return x*f}),total:sum*f}}
|
|
39327
|
+
function replay(){loadTimeline(function(){if(!tlStates||tlStates.length<2)return;marks();replaying=true;$("replay").textContent="Pause";
|
|
39328
|
+
var scale=window.__himiReplayScale!=null?window.__himiReplayScale:1,plan=replayPlan();window.__himiReplayPlan={idx:plan.idx,totalMs:plan.total};
|
|
39329
|
+
seen=snap(rewindTo(0));var q=0;
|
|
39330
|
+
(function next(){if(!replaying)return;q++;if(q>=plan.idx.length){toLive();return}
|
|
39331
|
+
replayTimer=setTimeout(function(){var s=rewindTo(plan.idx[q]);if(s)effects(s);next()},plan.gaps[q-1]*scale)})()})}
|
|
39332
|
+
/* The floating phone: the ONE live frame moves into an always-on-top window (Document Picture-in-
|
|
39333
|
+
Picture; a small ordinary window elsewhere) and back. Two copies would run the app twice and
|
|
39334
|
+
drift apart as the owner taps; the cost of moving is one reload per move. */
|
|
39335
|
+
var pip=null;
|
|
39336
|
+
function canPip(){return !!window.documentPictureInPicture}
|
|
39337
|
+
function paintStrip(s){if(!pip)return;pip.strip.firstChild.textContent=s.current?s.current.stepNumber+"/8 \xB7 "+s.current.step:"";pip.strip.lastChild.textContent=s.journal[0]?s.journal[0].message:""}
|
|
39338
|
+
function fitPip(){if(!pip)return;var w=pip.w.innerWidth,h=pip.w.innerHeight-44;if(w>0&&h>0)pip.frame.style.transform="scale("+Math.min(w/390,h/844)+")"}
|
|
39339
|
+
function mountPip(w,fr){var d=w.document;d.title=cur.app.name+" \xB7 phone";
|
|
39340
|
+
var st=d.createElement("style");st.textContent="html,body{margin:0;height:100%;background:#111;font:12px -apple-system,Segoe UI,Roboto,sans-serif}.pp{position:absolute;top:0;left:0;right:0;bottom:44px;overflow:hidden}.pp iframe{position:absolute;top:0;left:0;width:390px;height:844px;border:0;transform-origin:0 0}.pp.pulse{outline:3px solid #1f7a4d;outline-offset:-3px}.pp.bad{outline-color:#a12a2a}.strip{position:absolute;left:0;right:0;bottom:0;height:44px;padding:4px 10px;box-sizing:border-box;background:#fff;color:#1c1c1a}.strip div:first-child{color:#6b6a64}.strip div:last-child{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}";
|
|
39341
|
+
d.head.appendChild(st);var box=d.createElement("div");box.className="pp";d.body.appendChild(box);
|
|
39342
|
+
var home=fr.parentNode;box.appendChild(fr);
|
|
39343
|
+
var strip=d.createElement("div");strip.className="strip";strip.appendChild(d.createElement("div"));strip.appendChild(d.createElement("div"));d.body.appendChild(strip);
|
|
39344
|
+
pip={w:w,box:box,frame:fr,strip:strip,home:home};
|
|
39345
|
+
var note=el("div","empty","Phone popped out \xB7 ");var back=el("a",null,"Bring back");back.href="#";back.addEventListener("click",function(e){e.preventDefault();bringBack()});note.appendChild(back);note.id="away";home.appendChild(note);
|
|
39346
|
+
w.addEventListener("resize",fitPip);w.addEventListener("pagehide",bringBack);fitPip();paintStrip(cur);paintPop(cur)}
|
|
39347
|
+
var pipRefused=false;
|
|
39348
|
+
function openWindow(fr,afterPip){var w=window.open("","himiPhone","width=340,height=760");if(!w){$("pop").textContent=afterPip?"Open in a window":"Pop-up blocked";return}mountPip(w,fr)}
|
|
39349
|
+
/* A browser can expose Document PiP and still refuse the window (an embedded webview does): fall
|
|
39350
|
+
back to the small window rather than a click that does nothing and says nothing. The refusal may
|
|
39351
|
+
have spent the click's user activation, so a popup opened from it can be blocked: then the button
|
|
39352
|
+
offers the window, and the next click opens it directly with an activation of its own. */
|
|
39353
|
+
function popOut(){var fr=$("focus").querySelector("iframe.vp");if(!fr||pip)return;
|
|
39354
|
+
if(canPip()&&!pipRefused){Promise.resolve().then(function(){return window.documentPictureInPicture.requestWindow({width:320,height:740})}).then(function(w){mountPip(w,fr)},function(){pipRefused=true;openWindow(fr,true)})}
|
|
39355
|
+
else openWindow(fr)}
|
|
39356
|
+
function bringBack(){if(!pip)return;var p=pip;pip=null;var away=document.getElementById("away");if(away&&away.parentNode)away.parentNode.removeChild(away);
|
|
39357
|
+
p.frame.style.transform="";if(p.home&&p.home.isConnected!==false)p.home.appendChild(p.frame);else if(p.frame.parentNode)p.frame.parentNode.removeChild(p.frame);try{p.w.close()}catch(e){}fit();paintPop(cur)}
|
|
39358
|
+
function paintPop(s){var b=$("pop");b.hidden=!(s&&s.live)||rewinding;b.textContent=pip?"Bring back":canPip()&&!pipRefused?"Pop out phone":"Open in a window"}
|
|
39359
|
+
/* The brand reveal (decided board-side, played here only when it ARRIVES as a change) and opt-in
|
|
39360
|
+
read aloud: postcards and milestones, never rebuild messages, the newer cancelling the older. */
|
|
39361
|
+
var revealTimer=null,speakOn=false;try{speakOn=localStorage.getItem("himiStudioSpeak")==="1"}catch(e){}
|
|
39362
|
+
function fig(cap,cls){var f=el("figure",cls||null);f.appendChild(el("figcaption",null,cap));return f}
|
|
39363
|
+
function phoneImg(srcs){var ph=el("div","ph");srcs.forEach(function(p){var i=el("img",p[1]||null);i.src=p[0];i.alt="";ph.appendChild(i)});return ph}
|
|
39364
|
+
function showReveal(r){var row=$("rvrow"),rv=$("rv");clear(row);rv.classList.remove("on");
|
|
39365
|
+
if(r.site){var fs=fig("Your website","site");var si=el("img");si.src=r.site;si.alt="";fs.appendChild(si);row.appendChild(fs)}
|
|
39366
|
+
var same=!r.before||r.before===r.after;
|
|
39367
|
+
if(same){var f1=fig("Your app, your brand");f1.appendChild(phoneImg([[r.after]]));row.appendChild(f1)}
|
|
39368
|
+
else if(reduced()){var fb=fig("Your app, before");fb.appendChild(phoneImg([[r.before]]));row.appendChild(fb);var fa=fig("Your app, your brand");fa.appendChild(phoneImg([[r.after]]));row.appendChild(fa)}
|
|
39369
|
+
else{var fw=fig("Your app");fw.appendChild(phoneImg([[r.before],[r.after,"after"]]));row.appendChild(fw);setTimeout(function(){rv.classList.add("on")},700)}
|
|
39370
|
+
var box=$("reveal");box.hidden=false;box.setAttribute("data-shown",String((+box.getAttribute("data-shown")||0)+1));clearTimeout(revealTimer);revealTimer=setTimeout(hideReveal,6000)}
|
|
39371
|
+
function hideReveal(){$("reveal").hidden=true;clearTimeout(revealTimer)}
|
|
39372
|
+
function speak(t){if(!speakOn||!t)return;try{var ss=window.speechSynthesis;if(!ss||!window.SpeechSynthesisUtterance)return;ss.cancel();var u=new SpeechSynthesisUtterance(t);u.lang=navigator.language||"en";ss.speak(u)}catch(e){}}try{sound=localStorage.getItem("himiStudioSound")==="1";notices=localStorage.getItem("himiStudioNotify")==="1"}catch(e){}
|
|
39373
|
+
var raf=window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(f){return setTimeout(function(){f(Date.now())},16)};
|
|
39374
|
+
function now(){return window.performance&&performance.now?performance.now():Date.now()}
|
|
39375
|
+
function reduced(){try{return matchMedia("(prefers-reduced-motion: reduce)").matches}catch(e){return false}}
|
|
39376
|
+
function tone(f,t,d,v,type){if(!sound)return;try{if(!actx){var AC=window.AudioContext||window.webkitAudioContext;if(!AC)return;actx=new AC()}var o=actx.createOscillator(),g=actx.createGain(),n=actx.currentTime+(t||0),dd=d||.18;o.type=type||"sine";o.frequency.value=f;g.gain.setValueAtTime(0,n);g.gain.linearRampToValueAtTime(v||.05,n+.01);g.gain.exponentialRampToValueAtTime(.0001,n+dd);o.connect(g);g.connect(actx.destination);o.start(n);o.stop(n+dd+.05)}catch(e){}}
|
|
39377
|
+
var SND={tick:function(){tone(1320,0,.05,.025,"triangle")},post:function(){tone(880,0,.08,.03)},step:function(){tone(523);tone(784,.12)},win:function(){tone(523);tone(659,.1);tone(784,.2);tone(1047,.3,.35)},fail:function(){tone(160,0,.3,.05,"sawtooth")}};
|
|
39378
|
+
/* Notices are the BOARD's opt-in, not just the browser's: a permission granted to this origin once
|
|
39379
|
+
(an earlier board, another run) must not switch them on, and the toggle must switch them off. */
|
|
39380
|
+
function notify(title,body){if(replaying)return;try{if(notices&&"Notification" in window&&Notification.permission==="granted"&&document.hidden)new Notification(title,{body:body})}catch(e){}}
|
|
39381
|
+
function accentNow(){return (getComputedStyle(document.documentElement).getPropertyValue("--accent")||"").trim()||"#3b6fd8"}
|
|
39382
|
+
/* The preview lays out at a real phone's viewport (390 x 844 CSS px) and is scaled into the frame.
|
|
39383
|
+
Sized to the frame itself it was ~280px wide: narrower than any phone, so screens overflowed
|
|
39384
|
+
sideways and scrolled horizontally. */
|
|
39385
|
+
function fit(){var ph=$("focus").querySelector(".phone.vpf");if(!ph)return;var w=ph.clientWidth,h=ph.clientHeight;if(w&&h)ph.style.setProperty("--k",String(Math.min(w/390,h/844)))}
|
|
39386
|
+
window.addEventListener("resize",fit);
|
|
39387
|
+
function favicon(n,bad){try{var c=document.createElement("canvas");c.width=c.height=32;var x=c.getContext&&c.getContext("2d");if(!x)return;x.lineWidth=5;x.strokeStyle="rgba(128,128,128,.35)";x.beginPath();x.arc(16,16,12,0,6.2832);x.stroke();x.strokeStyle=accentNow();x.beginPath();x.arc(16,16,12,-1.5708,-1.5708+6.2832*n/8);x.stroke();if(bad){x.fillStyle="#d33";x.beginPath();x.arc(25,7,6,0,6.2832);x.fill()}$("fav").href=c.toDataURL("image/png")}catch(e){}}
|
|
39388
|
+
function burst(){var c=$("fx");c.setAttribute("data-bursts",String((+c.getAttribute("data-bursts")||0)+1));if(reduced())return;var x=c.getContext&&c.getContext("2d");if(!x)return;var W=c.width=innerWidth,H=c.height=innerHeight,cols=["#1f7a4d","#3b6fd8","#e0a030","#d4537e",accentNow()],P=[];for(var i=0;i<120;i++)P.push({x:W/2,y:H*.35,vx:(Math.random()-.5)*14,vy:-Math.random()*12-4,c:cols[i%cols.length],r:Math.random()*6.28});var t0=now();(function f(){x.clearRect(0,0,W,H);P.forEach(function(p){p.x+=p.vx;p.y+=p.vy;p.vy+=.35;p.r+=.2;x.save();x.translate(p.x,p.y);x.rotate(p.r);x.fillStyle=p.c;x.fillRect(-4,-2,8,4);x.restore()});if(now()-t0<2200)raf(f);else x.clearRect(0,0,W,H)})()}
|
|
39389
|
+
function countTo(e,a,b){if(!e)return;if(reduced()){e.textContent=String(b);return}var t0=now();(function f(){var k=Math.min(1,(now()-t0)/900);e.textContent=String(Math.round(a+(b-a)*k));if(k<1)raf(f)})()}
|
|
39390
|
+
function snap(s){var sc={},acc=null;s.screens.forEach(function(x){sc[x.id]=x.img});s.app.palette.forEach(function(p){if(p.name==="accentPrimary")acc=p.hex});return{screens:sc,step:s.current?s.current.stepNumber:0,top:s.journal[0]?s.journal[0].ts:null,build:s.live&&s.live.lastBuild?s.live.lastBuild.at:s.pastBuild?s.pastBuild.at:null,run:s.live?s.live.runId:s.pastBuild?s.pastBuild.run:null,push:s.health.push?s.health.push.releaseId:null,gaps:s.health.test?s.health.test.gaps:null,accent:acc,reveal:s.reveal?s.reveal.at:null}}
|
|
39391
|
+
function buildLine(b){if(!b.ok)return "Build failed \xB7 still showing the last good version";var what=b.screens.length?b.screens.slice(0,3).join(", ")+(b.screens.length>3?" +"+(b.screens.length-3):""):b.tokens?"design tokens":b.config?"app config":"no visible change";return "Rebuilt"+(b.ms!=null?" in "+(b.ms/1000).toFixed(1)+" s":"")+" \xB7 "+what}
|
|
39392
|
+
function effects(s){var is=snap(s),was=seen;seen=is;if(is.accent)document.documentElement.style.setProperty("--accent",is.accent);
|
|
39393
|
+
/* The phone (kept across renders) and the Now line outlive a render: clear what they played last. */
|
|
39394
|
+
var stage=rewinding?$("still"):$("focus"),ph=stage.querySelector(".phone"),nm=$("nowmsg");if(ph)ph.classList.remove("pulse","bad");nm.classList.remove("slidein");if(!was)return;
|
|
39395
|
+
var ticked=false;[].forEach.call($("wall").children,function(d){var id=d.getAttribute("data-id");if(!id)return;if(!(id in was.screens)){d.classList.add("enter");ticked=true}else if(was.screens[id]!==is.screens[id]){d.classList.add("changed");ticked=true}});if(ticked)SND.tick();
|
|
39396
|
+
if(is.top&&is.top!==was.top){void nm.offsetWidth;nm.classList.add("slidein");var li=$("log").firstChild;if(li&&li.classList)li.classList.add("slidein");SND.post()}
|
|
39397
|
+
if(is.step>was.step){var cs=$("steps").children[is.step-1];if(cs)cs.classList.add("fresh");SND.step();notify(s.app.name+" \xB7 step "+is.step+" of 8",s.journal[0]?s.journal[0].message:s.steps[is.step-1])}
|
|
39398
|
+
/* A rebuild is a later build of the SAME run: a run appearing, or restarting, records its first
|
|
39399
|
+
build too, and nothing was rebuilt then. */
|
|
39400
|
+
if(is.build&&was.build&&is.run===was.run&&is.build!==was.build){var b=s.live&&s.live.lastBuild||s.pastBuild;if(ph){void ph.offsetWidth;ph.classList.add("pulse");if(!b.ok)ph.classList.add("bad")}if(pip){pip.box.classList.remove("pulse","bad");void pip.box.offsetWidth;pip.box.classList.add("pulse");if(!b.ok)pip.box.classList.add("bad");pip.strip.lastChild.textContent=buildLine(b)}var tt=el("div","toast"+(b.ok?"":" bad"),buildLine(b));stage.appendChild(tt);setTimeout(function(){if(tt.parentNode)tt.parentNode.removeChild(tt)},3500);if(b.ok)SND.tick();else{SND.fail();notify(s.app.name+" \xB7 build failed",s.live&&s.live.buildError||"")}}
|
|
39401
|
+
if(was.gaps!=null&&is.gaps!=null&&is.gaps!==was.gaps)countTo($("gapn"),was.gaps,is.gaps);
|
|
39402
|
+
if(is.accent&&was.accent&&is.accent!==was.accent){var sw=$("brand").querySelector(".sw");if(sw)sw.classList.add("pop");favicon(is.step,!!(s.live&&s.live.buildError))}
|
|
39403
|
+
var published=is.push&&is.push!==was.push,handed=is.step===8&&was.step<8;if(published||handed){burst();SND.win();notify(s.app.name,published?"Draft published":"Handed over")}
|
|
39404
|
+
var said=false;if(is.top&&is.top!==was.top){speak((s.current?"Step "+s.current.stepNumber+", "+s.current.step+". ":"")+(s.journal[0]?s.journal[0].message:""));said=true}
|
|
39405
|
+
if((published||handed)&&!said)speak(published?"Your draft is ready to open on your phone.":"Your app is handed over.");
|
|
39406
|
+
if(is.reveal&&is.reveal!==was.reveal)showReveal(s.reveal);
|
|
39407
|
+
}
|
|
39408
|
+
function activityAt(s){var m=0;function add(v){var d=v?Date.parse(v):0;if(d>m)m=d}if(s.journal[0])add(s.journal[0].ts);s.screens.forEach(function(x){add(x.changedAt)});if(s.live&&s.live.lastBuild)add(s.live.lastBuild.at);["validate","test","push"].forEach(function(k){if(s.health[k])add(s.health[k].at)});return m}
|
|
39409
|
+
function paintToggles(){var sy=$("say");sy.hidden=!("speechSynthesis" in window);sy.textContent="Read aloud: "+(speakOn?"on":"off");sy.className="tog"+(speakOn?" on":"");sy.setAttribute("aria-pressed",String(speakOn));var b=$("snd");b.textContent=sound?"Sound on":"Sound off";b.className="tog"+(sound?" on":"");b.setAttribute("aria-pressed",String(sound));var nb=$("ntf");if(!("Notification" in window)){nb.hidden=true;return}var p=Notification.permission,on=notices&&p==="granted";nb.hidden=p==="denied";nb.textContent=on?"Notices on":"Notices off";nb.className="tog"+(on?" on":"");nb.setAttribute("aria-pressed",String(on))}
|
|
39410
|
+
function setNotices(v){notices=v;try{localStorage.setItem("himiStudioNotify",v?"1":"0")}catch(e){}paintToggles()}
|
|
39411
|
+
$("snd").addEventListener("click",function(){sound=!sound;try{localStorage.setItem("himiStudioSound",sound?"1":"0")}catch(e){}if(sound){try{if(actx&&actx.resume)actx.resume()}catch(e){}SND.post()}paintToggles()});
|
|
39412
|
+
/* The click acts on what the button SAYS (the effective state), so a remembered opt-in whose browser
|
|
39413
|
+
permission was since reset reads "off" and one click asks for permission, not two. */
|
|
39414
|
+
$("ntf").addEventListener("click",function(){try{var p=Notification.permission;if(notices&&p==="granted"){setNotices(false);return}if(p==="granted"){setNotices(true);return}if(Notification.permission==="default")Promise.resolve(Notification.requestPermission()).then(function(p){setNotices(p==="granted")})}catch(e){}});
|
|
39415
|
+
document.addEventListener("click",function(){try{if(actx&&actx.state==="suspended")actx.resume()}catch(e){}},{once:true});
|
|
39416
|
+
paintToggles();
|
|
39417
|
+
$("slider").addEventListener("input",function(){var i=+this.value;if(replaying)stopReplay();if(!rewinding||!tlStates)enterRewind(i);else rewindTo(i)});
|
|
39418
|
+
$("replay").addEventListener("click",function(){if(replaying){stopReplay();return}replay()});
|
|
39419
|
+
$("golive").addEventListener("click",toLive);
|
|
39420
|
+
$("rvx").addEventListener("click",hideReveal);$("reveal").addEventListener("click",function(e){if(e.target===this)hideReveal()});
|
|
39421
|
+
$("say").addEventListener("click",function(){speakOn=!speakOn;try{localStorage.setItem("himiStudioSpeak",speakOn?"1":"0")}catch(e){}paintToggles();if(speakOn)speak("Read aloud is on.")});
|
|
39422
|
+
$("pop").addEventListener("click",function(){if(pip)bringBack();else popOut()});
|
|
39423
|
+
$("backlive").addEventListener("click",function(e){e.preventDefault();toLive()});
|
|
39424
|
+
document.addEventListener("keydown",function(e){if($("scrub").hidden)return;var tg=e.target,tn=tg&&tg.tagName;
|
|
39425
|
+
if(e.key==="Escape"&&rewinding){toLive();return}
|
|
39426
|
+
if((e.key==="ArrowLeft"||e.key==="ArrowRight")&&!(tg&&tg.id==="slider")){var d=e.key==="ArrowRight"?1:-1;if(!rewinding){if(d<0)enterRewind(d)}else rewindTo(+$("slider").value+d);e.preventDefault()}
|
|
39427
|
+
if(e.key===" "&&tn!=="BUTTON"&&tn!=="INPUT"){e.preventDefault();$("replay").click()}});
|
|
39428
|
+
window.__himiStudio=function(s){lastSeen=Date.now();if(!cur||cur.v!==s.v){cur=s;if(rewinding){$("newdot").hidden=false;return}render(s);effects(s)}else{cur.generatedAt=s.generatedAt}};
|
|
39429
|
+
$("lb").addEventListener("click",function(){this.style.display="none"});
|
|
39430
|
+
window.__himiStudio(window.__himiInitial);
|
|
39431
|
+
setInterval(function(){var sc=document.createElement("script");sc.src="state.js?t="+Date.now();sc.onload=sc.onerror=function(){sc.remove()};document.head.appendChild(sc)},2000);
|
|
39432
|
+
var ticks=0;
|
|
39433
|
+
setInterval(function(){if(!cur)return;if(++ticks%60===0&&!rewinding)render(cur);var start=cur.startedAt?Date.parse(cur.startedAt):Date.now();var s=Math.max(0,Math.floor((Date.now()-start)/1000));var hh=Math.floor(s/3600),mm=Math.floor(s%3600/60),ss=s%60;
|
|
39434
|
+
$("clock").textContent=(hh?hh+":":"")+(mm<10&&hh?"0":"")+mm+":"+(ss<10?"0":"")+ss;
|
|
39435
|
+
$("updated").textContent="updated "+ago(cur.generatedAt);$("live").className="live"+(Date.now()-lastSeen>10000?" stale":"");
|
|
39436
|
+
var a=activityAt(cur),q=a?Date.now()-a:0,done=cur.current&&cur.current.stepNumber===8;
|
|
39437
|
+
$("agent").className="live"+(!a?" idle":done?"":q>5*60*1000?" quiet":"");$("agentt").textContent=!a?"Waiting for the agent":done?"Handed over":q>5*60*1000?"Quiet for "+Math.floor(q/60000)+" min":"Agent active"},1000);
|
|
39438
|
+
})();
|
|
39439
|
+
</script>
|
|
39440
|
+
</body>
|
|
39441
|
+
</html>
|
|
39442
|
+
`;
|
|
39443
|
+
}
|
|
39444
|
+
function escapeHtml(s) {
|
|
39445
|
+
return s.replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c]);
|
|
39446
|
+
}
|
|
39447
|
+
var scriptJson;
|
|
39448
|
+
var init_studio_page = __esm({
|
|
39449
|
+
"src/studio-page.ts"() {
|
|
39450
|
+
scriptJson = (value) => JSON.stringify(value).replace(/</g, "\\u003c").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
39451
|
+
}
|
|
39452
|
+
});
|
|
39453
|
+
|
|
39035
39454
|
// src/progress.ts
|
|
39036
39455
|
var progress_exports = {};
|
|
39037
39456
|
__export(progress_exports, {
|
|
@@ -39278,6 +39697,152 @@ var init_progress = __esm({
|
|
|
39278
39697
|
}
|
|
39279
39698
|
});
|
|
39280
39699
|
|
|
39700
|
+
// src/studio-timeline.ts
|
|
39701
|
+
import { existsSync as existsSync39, readFileSync as readFileSync42 } from "node:fs";
|
|
39702
|
+
import { join as join36 } from "node:path";
|
|
39703
|
+
function stateOf(view) {
|
|
39704
|
+
const j = view.journal[0];
|
|
39705
|
+
const h = view.health;
|
|
39706
|
+
const b = view.live?.lastBuild ?? null;
|
|
39707
|
+
return {
|
|
39708
|
+
step: view.current ? { n: view.current.stepNumber, name: view.current.step } : null,
|
|
39709
|
+
now: j ? { ts: j.ts, message: j.message, images: j.images } : null,
|
|
39710
|
+
screens: Object.fromEntries(view.screens.map((s) => [s.id, s.img])),
|
|
39711
|
+
palette: view.app.palette.map((p) => [p.name, p.hex]),
|
|
39712
|
+
checks: {
|
|
39713
|
+
validate: h.validate ? { ok: h.validate.ok, errors: h.validate.errors } : null,
|
|
39714
|
+
test: h.test ? { screens: h.test.screens, actions: h.test.actions, gaps: h.test.gaps, ok: h.test.ok } : null,
|
|
39715
|
+
push: h.push ? { draft: h.push.draft, releaseId: h.push.releaseId } : null
|
|
39716
|
+
},
|
|
39717
|
+
build: b && view.live ? { ok: b.ok, ms: b.ms, screens: b.screens, at: b.at, run: view.live.runId } : null
|
|
39718
|
+
};
|
|
39719
|
+
}
|
|
39720
|
+
function frameFor(state, prev, ts2, v, key2) {
|
|
39721
|
+
if (key2 || !prev) return { ts: ts2, v, key: true, ...state };
|
|
39722
|
+
const f = { ts: ts2, v };
|
|
39723
|
+
if (!same(state.step, prev.step)) f.step = state.step;
|
|
39724
|
+
if (!same(state.now, prev.now)) f.now = state.now;
|
|
39725
|
+
const screens = {};
|
|
39726
|
+
for (const [id, img] of Object.entries(state.screens)) if (prev.screens[id] !== img) screens[id] = img;
|
|
39727
|
+
for (const id of Object.keys(prev.screens)) if (!(id in state.screens)) screens[id] = null;
|
|
39728
|
+
if (Object.keys(screens).length) f.screens = screens;
|
|
39729
|
+
if (!same(state.palette, prev.palette)) f.palette = state.palette;
|
|
39730
|
+
if (!same(state.checks, prev.checks)) f.checks = state.checks;
|
|
39731
|
+
if (!same(state.build, prev.build)) f.build = state.build;
|
|
39732
|
+
return f;
|
|
39733
|
+
}
|
|
39734
|
+
function fold(prev, f) {
|
|
39735
|
+
const base = f.key || !prev ? EMPTY : prev;
|
|
39736
|
+
const screens = f.key ? {} : { ...base.screens };
|
|
39737
|
+
for (const [id, img] of Object.entries(f.screens ?? {})) {
|
|
39738
|
+
if (img === null) delete screens[id];
|
|
39739
|
+
else screens[id] = img;
|
|
39740
|
+
}
|
|
39741
|
+
return {
|
|
39742
|
+
step: "step" in f ? f.step ?? null : base.step,
|
|
39743
|
+
now: "now" in f ? f.now ?? null : base.now,
|
|
39744
|
+
screens,
|
|
39745
|
+
palette: f.palette ?? base.palette,
|
|
39746
|
+
checks: f.checks ?? base.checks,
|
|
39747
|
+
build: "build" in f ? f.build ?? null : base.build
|
|
39748
|
+
};
|
|
39749
|
+
}
|
|
39750
|
+
function validFrame(f) {
|
|
39751
|
+
if (!isObj(f) || !isStr(f.ts) || !isStr(f.v)) return false;
|
|
39752
|
+
if (f.key !== void 0 && f.key !== true) return false;
|
|
39753
|
+
if ("step" in f && !nullOr(f.step, (x) => typeof x.n === "number" && isStr(x.name))) return false;
|
|
39754
|
+
if ("now" in f && !nullOr(f.now, (x) => isStr(x.ts) && isStr(x.message) && strs(x.images))) return false;
|
|
39755
|
+
if ("screens" in f && !(isObj(f.screens) && Object.values(f.screens).every((x) => x === null || isStr(x)))) return false;
|
|
39756
|
+
if ("palette" in f && !(Array.isArray(f.palette) && f.palette.every((p) => Array.isArray(p) && p.length === 2 && p.every(isStr)))) return false;
|
|
39757
|
+
if ("checks" in f) {
|
|
39758
|
+
const c = f.checks;
|
|
39759
|
+
if (!isObj(c)) return false;
|
|
39760
|
+
if (!nullOr(c.validate ?? null, (x) => typeof x.ok === "boolean" && typeof x.errors === "number")) return false;
|
|
39761
|
+
if (!nullOr(c.test ?? null, (x) => ["screens", "actions", "gaps"].every((k) => typeof x[k] === "number") && typeof x.ok === "boolean")) return false;
|
|
39762
|
+
if (!nullOr(c.push ?? null, (x) => typeof x.draft === "boolean" && isStr(x.releaseId))) return false;
|
|
39763
|
+
}
|
|
39764
|
+
if ("build" in f && !nullOr(f.build, (x) => typeof x.ok === "boolean" && (x.ms === null || typeof x.ms === "number") && strs(x.screens) && isStr(x.at) && isStr(x.run))) return false;
|
|
39765
|
+
if ("reveal" in f && !(isObj(f.reveal) && (f.reveal.site === null || isStr(f.reveal.site)) && isStr(f.reveal.before) && isStr(f.reveal.after))) return false;
|
|
39766
|
+
return true;
|
|
39767
|
+
}
|
|
39768
|
+
function readTimeline(dir) {
|
|
39769
|
+
const file = join36(dir, TIMELINE_FILE);
|
|
39770
|
+
if (!existsSync39(file)) return [];
|
|
39771
|
+
const out = [];
|
|
39772
|
+
for (const line of readFileSync42(file, "utf8").split("\n")) {
|
|
39773
|
+
if (!line.trim()) continue;
|
|
39774
|
+
try {
|
|
39775
|
+
const f = JSON.parse(line);
|
|
39776
|
+
if (validFrame(f)) out.push(f);
|
|
39777
|
+
} catch {
|
|
39778
|
+
}
|
|
39779
|
+
}
|
|
39780
|
+
const first = out.findIndex((f) => f.key === true);
|
|
39781
|
+
return first < 0 ? [] : out.slice(first);
|
|
39782
|
+
}
|
|
39783
|
+
function trim(frames) {
|
|
39784
|
+
if (frames.length <= MAX_FRAMES) return frames;
|
|
39785
|
+
for (let i = 1; i < frames.length; i++) if (frames[i].key && frames.length - i <= MAX_FRAMES) return frames.slice(i);
|
|
39786
|
+
return frames.slice(-MAX_FRAMES);
|
|
39787
|
+
}
|
|
39788
|
+
function writeTimelineJs(dir, frames) {
|
|
39789
|
+
writeFileAtomic(join36(dir, TIMELINE_JS), `window.__himiTimeline && window.__himiTimeline(${scriptJson(frames)});
|
|
39790
|
+
`);
|
|
39791
|
+
}
|
|
39792
|
+
function appendFrame(dir, view, reveal = null) {
|
|
39793
|
+
const frames = readTimeline(dir);
|
|
39794
|
+
const last = frames[frames.length - 1];
|
|
39795
|
+
if (last && last.v === view.v && !reveal) {
|
|
39796
|
+
if (!existsSync39(join36(dir, TIMELINE_JS))) writeTimelineJs(dir, frames);
|
|
39797
|
+
return frames.length;
|
|
39798
|
+
}
|
|
39799
|
+
let prev = null;
|
|
39800
|
+
for (const f of frames) prev = fold(prev, f);
|
|
39801
|
+
const frame = frameFor(stateOf(view), prev, view.generatedAt, view.v, frames.length % KEYFRAME_EVERY === 0);
|
|
39802
|
+
if (reveal) frame.reveal = reveal;
|
|
39803
|
+
const kept = trim([...frames, frame]);
|
|
39804
|
+
writeFileAtomic(join36(dir, TIMELINE_FILE), kept.map((f) => JSON.stringify(f)).join("\n") + "\n");
|
|
39805
|
+
writeTimelineJs(dir, kept);
|
|
39806
|
+
return kept.length;
|
|
39807
|
+
}
|
|
39808
|
+
function brandLanded(view, first) {
|
|
39809
|
+
const was = accentOf(first?.palette);
|
|
39810
|
+
const is = accentOf(view.app.palette);
|
|
39811
|
+
return was !== null && is !== null && was !== is || view.journal.some((j) => j.step === "brand");
|
|
39812
|
+
}
|
|
39813
|
+
function revealFor(view, memory) {
|
|
39814
|
+
if (memory.revealedAt || !memory.brandSeenAt || !view.focus || !view.focus.frames.length) return null;
|
|
39815
|
+
const latest = view.focus.frames[view.focus.frames.length - 1];
|
|
39816
|
+
if (latest.ts < memory.brandSeenAt) return null;
|
|
39817
|
+
const firstVersion = memory.timeline.find((t) => t.id === view.focus.id);
|
|
39818
|
+
const before = firstVersion ? `../history/${firstVersion.sha}.${firstVersion.ext}` : latest.img;
|
|
39819
|
+
return { site: view.brand.site, before, after: latest.img };
|
|
39820
|
+
}
|
|
39821
|
+
var TIMELINE_FILE, TIMELINE_JS, MAX_FRAMES, KEYFRAME_EVERY, same, EMPTY, isStr, isObj, strs, nullOr, accentOf;
|
|
39822
|
+
var init_studio_timeline = __esm({
|
|
39823
|
+
"src/studio-timeline.ts"() {
|
|
39824
|
+
init_progress();
|
|
39825
|
+
init_studio_page();
|
|
39826
|
+
TIMELINE_FILE = join36(".himi", "studio", "timeline.jsonl");
|
|
39827
|
+
TIMELINE_JS = join36(".himi", "studio", "timeline.js");
|
|
39828
|
+
MAX_FRAMES = 2e3;
|
|
39829
|
+
KEYFRAME_EVERY = 50;
|
|
39830
|
+
same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
39831
|
+
EMPTY = { step: null, now: null, screens: {}, palette: [], checks: { validate: null, test: null, push: null }, build: null };
|
|
39832
|
+
isStr = (x) => typeof x === "string";
|
|
39833
|
+
isObj = (x) => typeof x === "object" && x !== null && !Array.isArray(x);
|
|
39834
|
+
strs = (x) => Array.isArray(x) && x.every(isStr);
|
|
39835
|
+
nullOr = (x, ok) => x === null || isObj(x) && ok(x);
|
|
39836
|
+
accentOf = (palette2) => {
|
|
39837
|
+
for (const p of palette2 ?? []) {
|
|
39838
|
+
const [name, hex2] = Array.isArray(p) ? p : [p.name, p.hex];
|
|
39839
|
+
if (name === "accentPrimary") return hex2;
|
|
39840
|
+
}
|
|
39841
|
+
return null;
|
|
39842
|
+
};
|
|
39843
|
+
}
|
|
39844
|
+
});
|
|
39845
|
+
|
|
39281
39846
|
// src/studio.ts
|
|
39282
39847
|
var studio_exports = {};
|
|
39283
39848
|
__export(studio_exports, {
|
|
@@ -39296,8 +39861,8 @@ __export(studio_exports, {
|
|
|
39296
39861
|
writeStudioRecord: () => writeStudioRecord
|
|
39297
39862
|
});
|
|
39298
39863
|
import { createHash as createHash20 } from "node:crypto";
|
|
39299
|
-
import { existsSync as
|
|
39300
|
-
import { basename as basename9, extname as extname3, join as
|
|
39864
|
+
import { existsSync as existsSync40, readdirSync as readdirSync20, readFileSync as readFileSync43, realpathSync as realpathSync4, statSync as statSync8 } from "node:fs";
|
|
39865
|
+
import { basename as basename9, extname as extname3, join as join37, relative as relative6, resolve as resolve33, sep as sep9 } from "node:path";
|
|
39301
39866
|
import { pathToFileURL as pathToFileURL7 } from "node:url";
|
|
39302
39867
|
function realInside(dir, abs) {
|
|
39303
39868
|
try {
|
|
@@ -39322,12 +39887,12 @@ function archiveFile(dir, memory, abs) {
|
|
|
39322
39887
|
if (size === 0) return null;
|
|
39323
39888
|
const key2 = relative6(dir, abs);
|
|
39324
39889
|
const hit = memory.files?.[key2];
|
|
39325
|
-
if (hit && hit.size === size && hit.mtimeMs === mtimeMs && hit.ino === ino &&
|
|
39890
|
+
if (hit && hit.size === size && hit.mtimeMs === mtimeMs && hit.ino === ino && existsSync40(join37(dir, HISTORY_DIR, `${hit.sha}.${hit.ext}`))) {
|
|
39326
39891
|
return { sha: hit.sha, ext: hit.ext, file: `${hit.sha}.${hit.ext}` };
|
|
39327
39892
|
}
|
|
39328
39893
|
let archived;
|
|
39329
39894
|
try {
|
|
39330
|
-
archived = archiveBytes(dir,
|
|
39895
|
+
archived = archiveBytes(dir, readFileSync43(real));
|
|
39331
39896
|
} catch {
|
|
39332
39897
|
return null;
|
|
39333
39898
|
}
|
|
@@ -39336,17 +39901,17 @@ function archiveFile(dir, memory, abs) {
|
|
|
39336
39901
|
return { sha: archived.sha256, ext: archived.ext, file: `${archived.sha256}.${archived.ext}` };
|
|
39337
39902
|
}
|
|
39338
39903
|
function loadMemory(dir, now) {
|
|
39339
|
-
const raw = obj(readJson2(
|
|
39904
|
+
const raw = obj(readJson2(join37(dir, MEMORY_FILE)));
|
|
39340
39905
|
if (raw && raw.version === 1 && obj(raw.shots) && Array.isArray(raw.timeline)) return raw;
|
|
39341
39906
|
return { version: 1, createdAt: now, shots: {}, timeline: [] };
|
|
39342
39907
|
}
|
|
39343
39908
|
function observeShots(dir, memory, now) {
|
|
39344
|
-
const shotsDir =
|
|
39909
|
+
const shotsDir = join37(dir, ".himi", "shots");
|
|
39345
39910
|
const seen = /* @__PURE__ */ new Set();
|
|
39346
|
-
const files =
|
|
39911
|
+
const files = existsSync40(shotsDir) ? readdirSync20(shotsDir).filter((f) => /\.(png|jpe?g)$/i.test(f)).sort() : [];
|
|
39347
39912
|
for (const f of files) {
|
|
39348
39913
|
const id = basename9(f, extname3(f));
|
|
39349
|
-
const archived = archiveFile(dir, memory,
|
|
39914
|
+
const archived = archiveFile(dir, memory, join37(shotsDir, f));
|
|
39350
39915
|
if (!archived) continue;
|
|
39351
39916
|
seen.add(id);
|
|
39352
39917
|
const { sha, ext } = archived;
|
|
@@ -39361,14 +39926,14 @@ function observeShots(dir, memory, now) {
|
|
|
39361
39926
|
memory.shots[id] = { ...prev, present: true };
|
|
39362
39927
|
}
|
|
39363
39928
|
}
|
|
39364
|
-
if (
|
|
39929
|
+
if (existsSync40(shotsDir)) {
|
|
39365
39930
|
for (const [id, shot] of Object.entries(memory.shots)) if (!seen.has(id) && shot.present) memory.shots[id] = { ...shot, present: false };
|
|
39366
39931
|
}
|
|
39367
39932
|
if (memory.timeline.length > MAX_TIMELINE) memory.timeline = memory.timeline.slice(-MAX_TIMELINE);
|
|
39368
39933
|
return memory;
|
|
39369
39934
|
}
|
|
39370
39935
|
function palette(dir) {
|
|
39371
|
-
const colors = obj(obj(readJson2(
|
|
39936
|
+
const colors = obj(obj(readJson2(join37(dir, "tokens.json")))?.colors);
|
|
39372
39937
|
if (!colors) return [];
|
|
39373
39938
|
const pick2 = (key2) => {
|
|
39374
39939
|
const v = colors[key2];
|
|
@@ -39378,7 +39943,7 @@ function palette(dir) {
|
|
|
39378
39943
|
return ["accentPrimary", "accentSecondary", "accentSurface", "surfacePrimary", "textPrimary"].map(pick2).filter((x) => !!x);
|
|
39379
39944
|
}
|
|
39380
39945
|
function appIdentity(dir) {
|
|
39381
|
-
const manifest = obj(readJson2(
|
|
39946
|
+
const manifest = obj(readJson2(join37(dir, "himalaya.content.json")));
|
|
39382
39947
|
const name = text(manifest?.name) ?? basename9(resolve33(dir));
|
|
39383
39948
|
const icon = text(manifest?.icon)?.trim();
|
|
39384
39949
|
const iconPath = icon ? resolve33(dir, icon) : null;
|
|
@@ -39386,12 +39951,12 @@ function appIdentity(dir) {
|
|
|
39386
39951
|
return { name, iconFile: real && statSync8(real).isFile() ? iconPath : null };
|
|
39387
39952
|
}
|
|
39388
39953
|
function testRuns(dir) {
|
|
39389
|
-
const att =
|
|
39390
|
-
if (!
|
|
39954
|
+
const att = join37(dir, ".himi", "attestations");
|
|
39955
|
+
if (!existsSync40(att)) return [];
|
|
39391
39956
|
const runs = [];
|
|
39392
39957
|
for (const f of readdirSync20(att)) {
|
|
39393
39958
|
if (!f.endsWith(".json") || f === "latest.json") continue;
|
|
39394
|
-
const r = obj(readJson2(
|
|
39959
|
+
const r = obj(readJson2(join37(att, f)));
|
|
39395
39960
|
if (!r || r.tool !== "himi-test" || typeof r.runId !== "string") continue;
|
|
39396
39961
|
const report2 = obj(r.report);
|
|
39397
39962
|
const coverage = obj(r.coverage);
|
|
@@ -39407,20 +39972,20 @@ function testRuns(dir) {
|
|
|
39407
39972
|
return runs.sort((a, b) => a.runId.localeCompare(b.runId));
|
|
39408
39973
|
}
|
|
39409
39974
|
function siteHome(dir) {
|
|
39410
|
-
for (const pages of [
|
|
39411
|
-
if (!
|
|
39975
|
+
for (const pages of [join37(dir, ".himi", "business-book", "evidence", "pages"), join37(dir, "evidence", "pages")]) {
|
|
39976
|
+
if (!existsSync40(pages)) continue;
|
|
39412
39977
|
const home = readdirSync20(pages).filter((f) => /^home.*\.(png|jpe?g)$/i.test(f)).sort()[0];
|
|
39413
|
-
if (home) return
|
|
39978
|
+
if (home) return join37(pages, home);
|
|
39414
39979
|
}
|
|
39415
39980
|
return null;
|
|
39416
39981
|
}
|
|
39417
39982
|
function uxStatuses(dir) {
|
|
39418
|
-
const platforms = obj(obj(readJson2(
|
|
39983
|
+
const platforms = obj(obj(readJson2(join37(dir, ".himi", "ux-audit.json")))?.platforms);
|
|
39419
39984
|
if (!platforms) return [];
|
|
39420
39985
|
return Object.entries(platforms).map(([platform, rec]) => ({ platform, status: text(obj(rec)?.status) ?? "" })).filter((p) => p.status);
|
|
39421
39986
|
}
|
|
39422
39987
|
function liveRun(dir) {
|
|
39423
|
-
const rec = obj(readJson2(
|
|
39988
|
+
const rec = obj(readJson2(join37(dir, RUN_RECORD)));
|
|
39424
39989
|
const url = text(rec?.url);
|
|
39425
39990
|
const pid = rec?.pid;
|
|
39426
39991
|
if (!url || !/^https?:\/\//i.test(url) || typeof pid !== "number") return null;
|
|
@@ -39470,9 +40035,9 @@ function buildView(dir, memory, now) {
|
|
|
39470
40035
|
const runs = testRuns(dir);
|
|
39471
40036
|
const last = runs[runs.length - 1];
|
|
39472
40037
|
const prev = runs[runs.length - 2];
|
|
39473
|
-
const validate3 = obj(readJson2(
|
|
39474
|
-
const push = obj(readJson2(
|
|
39475
|
-
const edges = readJson2(
|
|
40038
|
+
const validate3 = obj(readJson2(join37(dir, VALIDATE_RECORD)));
|
|
40039
|
+
const push = obj(readJson2(join37(dir, PUSH_RECORD)));
|
|
40040
|
+
const edges = readJson2(join37(dir, EDGES_RECORD));
|
|
39476
40041
|
const nav = [];
|
|
39477
40042
|
if (Array.isArray(edges)) {
|
|
39478
40043
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -39510,9 +40075,11 @@ function buildView(dir, memory, now) {
|
|
|
39510
40075
|
},
|
|
39511
40076
|
brand: { site: siteImg },
|
|
39512
40077
|
nav,
|
|
39513
|
-
live: liveRun(dir)
|
|
40078
|
+
live: liveRun(dir),
|
|
40079
|
+
timelineFrames: 0,
|
|
40080
|
+
reveal: memory.reveal ?? null
|
|
39514
40081
|
};
|
|
39515
|
-
const { generatedAt: _ignored, ...stable } = view;
|
|
40082
|
+
const { generatedAt: _ignored, timelineFrames: _count, ...stable } = view;
|
|
39516
40083
|
const v = createHash20("sha256").update(JSON.stringify(stable)).digest("hex").slice(0, 16);
|
|
39517
40084
|
return { v, ...view };
|
|
39518
40085
|
}
|
|
@@ -39523,16 +40090,33 @@ function writeBoard(dir, now) {
|
|
|
39523
40090
|
if (!realDirIn(dir, STUDIO_DIR)) throw new UnsafeHimiDirError(STUDIO_DIR);
|
|
39524
40091
|
if (!realDirIn(dir, HISTORY_DIR)) throw new UnsafeHimiDirError(HISTORY_DIR);
|
|
39525
40092
|
const memory = observeShots(dir, loadMemory(dir, now), now);
|
|
39526
|
-
|
|
39527
|
-
|
|
39528
|
-
|
|
40093
|
+
let view = buildView(dir, memory, now);
|
|
40094
|
+
let reveal = null;
|
|
40095
|
+
try {
|
|
40096
|
+
if (!memory.brandSeenAt && brandLanded(view, readTimeline(dir)[0])) memory.brandSeenAt = now;
|
|
40097
|
+
reveal = revealFor(view, memory);
|
|
40098
|
+
if (reveal) {
|
|
40099
|
+
memory.revealedAt = now;
|
|
40100
|
+
memory.reveal = { at: now, ...reveal };
|
|
40101
|
+
view = buildView(dir, memory, now);
|
|
40102
|
+
}
|
|
40103
|
+
} catch {
|
|
40104
|
+
reveal = null;
|
|
40105
|
+
}
|
|
40106
|
+
try {
|
|
40107
|
+
view.timelineFrames = appendFrame(dir, view, reveal);
|
|
40108
|
+
} catch {
|
|
40109
|
+
view.timelineFrames = 0;
|
|
40110
|
+
}
|
|
40111
|
+
writeAtomic(join37(dir, MEMORY_FILE), JSON.stringify(memory));
|
|
40112
|
+
writeAtomic(join37(dir, STATE_FILE), `window.__himiStudio && window.__himiStudio(${scriptJson(view)});
|
|
39529
40113
|
`);
|
|
39530
|
-
writeAtomic(
|
|
40114
|
+
writeAtomic(join37(dir, STUDIO_PAGE), renderStudioHtml(view));
|
|
39531
40115
|
return view;
|
|
39532
40116
|
}
|
|
39533
40117
|
function refreshStudio(dir, now = /* @__PURE__ */ new Date()) {
|
|
39534
40118
|
try {
|
|
39535
|
-
if (!
|
|
40119
|
+
if (!existsSync40(join37(dir, STUDIO_PAGE))) return { refreshed: false };
|
|
39536
40120
|
return { refreshed: true, view: writeBoard(dir, now.toISOString()) };
|
|
39537
40121
|
} catch {
|
|
39538
40122
|
return { refreshed: false };
|
|
@@ -39540,225 +40124,38 @@ function refreshStudio(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
39540
40124
|
}
|
|
39541
40125
|
function openStudio(dir, now = /* @__PURE__ */ new Date()) {
|
|
39542
40126
|
const view = writeBoard(dir, now.toISOString());
|
|
39543
|
-
const page =
|
|
40127
|
+
const page = join37(dir, STUDIO_PAGE);
|
|
39544
40128
|
return { page, url: pathToFileURL7(page).href, view };
|
|
39545
40129
|
}
|
|
39546
40130
|
function writeStudioRecord(dir, record2, value) {
|
|
39547
40131
|
try {
|
|
39548
40132
|
if (!realDirIn(dir, ".himi")) return;
|
|
39549
|
-
writeAtomic(
|
|
40133
|
+
writeAtomic(join37(dir, record2), `${JSON.stringify(value, null, 2)}
|
|
39550
40134
|
`);
|
|
39551
40135
|
} catch {
|
|
39552
40136
|
}
|
|
39553
40137
|
}
|
|
39554
|
-
|
|
39555
|
-
const accent = initial.app.palette.find((p) => p.name === "accentPrimary")?.hex ?? "#3b6fd8";
|
|
39556
|
-
return `<!doctype html>
|
|
39557
|
-
<html lang="en">
|
|
39558
|
-
<head>
|
|
39559
|
-
<meta charset="utf-8">
|
|
39560
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
39561
|
-
<title>${escapeHtml(initial.app.name)} \xB7 build board</title>
|
|
39562
|
-
<link rel="icon" id="fav" href="data:,">
|
|
39563
|
-
<style>
|
|
39564
|
-
:root{--bg:#f6f5f2;--card:#fff;--ink:#1c1c1a;--muted:#6b6a64;--faint:#a3a19a;--line:#e6e3dc;--ok:#1f7a4d;--okbg:#e3f3ea;--warn:#8a5a00;--warnbg:#fbefd6;--bad:#a12a2a;--badbg:#fbe4e4;--accent:${accent};--shadow:0 1px 2px rgba(0,0,0,.04),0 4px 16px rgba(0,0,0,.04)}
|
|
39565
|
-
@media (prefers-color-scheme:dark){:root{--bg:#121211;--card:#1c1c1a;--ink:#ecebe6;--muted:#a3a19a;--faint:#6b6a64;--line:#2c2b28;--okbg:#15301f;--ok:#7fd3a2;--warnbg:#33270f;--warn:#f0c46b;--badbg:#3a1616;--bad:#f09a9a;--shadow:none}}
|
|
39566
|
-
*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--ink);font:14px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif}
|
|
39567
|
-
.wrap{max-width:1180px;margin:0 auto;padding:20px 20px 60px}
|
|
39568
|
-
header{display:flex;align-items:center;gap:12px;margin-bottom:16px}
|
|
39569
|
-
.icon{width:40px;height:40px;border-radius:10px;background:var(--accent);object-fit:cover;flex:none}
|
|
39570
|
-
h1{font-size:20px;font-weight:600;margin:0}.sub{color:var(--muted);font-size:13px}
|
|
39571
|
-
.right{margin-left:auto;text-align:right}.clock{font-size:22px;font-variant-numeric:tabular-nums;font-weight:600}
|
|
39572
|
-
.live{display:inline-flex;align-items:center;gap:6px;color:var(--muted);font-size:12px}.dot{width:8px;height:8px;border-radius:50%;background:var(--ok)}.stale .dot{background:var(--faint)}
|
|
39573
|
-
.steps{display:grid;grid-template-columns:repeat(8,1fr);gap:6px;margin:4px 0 16px}.step .bar{height:6px;border-radius:3px;background:var(--line)}.step.done .bar{background:var(--ok)}.step.cur .bar{background:var(--accent)}
|
|
39574
|
-
.step .lbl{font-size:11px;color:var(--faint);margin-top:4px;text-transform:capitalize}.step.cur .lbl{color:var(--ink);font-weight:600}
|
|
39575
|
-
.card{background:var(--card);border:1px solid var(--line);border-radius:14px;padding:14px 16px;box-shadow:var(--shadow)}
|
|
39576
|
-
.now{display:flex;gap:12px;align-items:flex-start;margin-bottom:16px}.now .msg{font-size:16px}.now .meta{color:var(--muted);font-size:12px}
|
|
39577
|
-
.grid{display:grid;grid-template-columns:320px 1fr;gap:16px;align-items:start}@media (max-width:860px){.grid{grid-template-columns:1fr}.steps .lbl{display:none}}
|
|
39578
|
-
h2{font-size:12px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.04em;margin:0 0 10px}
|
|
39579
|
-
.phone{width:100%;max-width:300px;aspect-ratio:390/844;border-radius:34px;border:9px solid #111;background:#fff;overflow:hidden;margin:0 auto;display:block}
|
|
39580
|
-
.phone img,.phone iframe{width:100%;height:100%;object-fit:cover;object-position:top;border:0;display:block;cursor:zoom-in}
|
|
39581
|
-
.phone.vpf{position:relative}.phone iframe.vp{position:absolute;top:0;left:0;width:390px;height:844px;transform-origin:0 0;transform:scale(var(--k,.72));cursor:auto}
|
|
39582
|
-
.cap{text-align:center;color:var(--muted);font-size:12px;margin-top:8px}
|
|
39583
|
-
.film{display:flex;gap:6px;overflow-x:auto;margin-top:12px;padding-bottom:4px}.film img{width:48px;aspect-ratio:390/844;object-fit:cover;object-position:top;border-radius:8px;border:1px solid var(--line);cursor:zoom-in}
|
|
39584
|
-
.chips{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:16px}.chip{font-size:12px;padding:5px 10px;border-radius:999px;background:var(--card);border:1px solid var(--line);color:var(--muted)}
|
|
39585
|
-
.chip.ok{background:var(--okbg);color:var(--ok);border-color:transparent}.chip.warn{background:var(--warnbg);color:var(--warn);border-color:transparent}.chip.bad{background:var(--badbg);color:var(--bad);border-color:transparent}
|
|
39586
|
-
.wall{display:grid;grid-template-columns:repeat(auto-fill,minmax(112px,1fr));gap:14px}
|
|
39587
|
-
.shot{text-align:center}.shot .frame{aspect-ratio:390/844;border-radius:16px;border:5px solid #111;overflow:hidden;background:#fff}.shot img{width:100%;height:100%;object-fit:cover;object-position:top;display:block;cursor:zoom-in}
|
|
39588
|
-
.shot .id{font-size:12px;margin-top:6px;word-break:break-all}.badge{display:inline-block;font-size:10px;padding:1px 7px;border-radius:999px;margin-top:3px}.badge.new{background:var(--okbg);color:var(--ok)}.badge.chg{background:var(--warnbg);color:var(--warn)}
|
|
39589
|
-
.section{margin-bottom:16px}.brand{display:flex;gap:14px;align-items:center;flex-wrap:wrap}.brand .site{width:220px;border-radius:10px;border:1px solid var(--line);cursor:zoom-in}
|
|
39590
|
-
.sw{display:flex;gap:6px}.sw span{width:22px;height:22px;border-radius:50%;border:1px solid var(--line)}
|
|
39591
|
-
.nav{display:flex;flex-wrap:wrap;gap:6px}.nav span{font-size:12px;padding:3px 8px;border-radius:6px;background:var(--bg);border:1px solid var(--line)}
|
|
39592
|
-
.log{list-style:none;margin:0;padding:0}.log li{display:flex;gap:10px;padding:10px 0;border-top:1px solid var(--line)}.log li:first-child{border-top:0}
|
|
39593
|
-
.log .t{color:var(--faint);font-size:12px;min-width:64px;font-variant-numeric:tabular-nums}.log .s{font-size:11px;color:var(--muted);text-transform:capitalize}.log .imgs{display:flex;gap:6px;margin-top:6px}.log .imgs img{height:72px;border-radius:8px;border:1px solid var(--line);cursor:zoom-in}
|
|
39594
|
-
.empty{color:var(--faint);font-size:13px;padding:8px 0}
|
|
39595
|
-
#lb{position:fixed;inset:0;background:rgba(0,0,0,.72);display:none;align-items:center;justify-content:center;z-index:9;cursor:zoom-out}#lb img{max-height:92vh;max-width:92vw;border-radius:14px;background:#fff}
|
|
39596
|
-
.enter{animation:enter .7s cubic-bezier(.2,.8,.2,1) both}@keyframes enter{from{opacity:0;transform:translateY(10px) scale(.94);filter:grayscale(1)}to{opacity:1;transform:none;filter:none}}
|
|
39597
|
-
.changed .frame{animation:chg .9s ease both}@keyframes chg{35%{opacity:.25;transform:scale(.96)}100%{opacity:1;transform:none}}
|
|
39598
|
-
.step.fresh .bar{animation:fill .7s ease both;transform-origin:left}@keyframes fill{from{transform:scaleX(0)}to{transform:scaleX(1)}}
|
|
39599
|
-
.slidein{animation:slide .45s cubic-bezier(.2,.8,.2,1) both}@keyframes slide{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}
|
|
39600
|
-
.phone.pulse{animation:pulse 1s ease-out}.phone.pulse.bad{animation-name:pulsebad}@keyframes pulse{from{outline:3px solid var(--ok);outline-offset:0}to{outline:3px solid transparent;outline-offset:10px}}@keyframes pulsebad{from{outline:3px solid var(--bad);outline-offset:0}to{outline:3px solid transparent;outline-offset:10px}}
|
|
39601
|
-
.toast{display:block;width:max-content;max-width:100%;margin:8px auto 0;font-size:12px;padding:4px 10px;border-radius:999px;background:var(--okbg);color:var(--ok);animation:toast 3.4s ease both}.toast.bad{background:var(--badbg);color:var(--bad)}@keyframes toast{0%{opacity:0;transform:translateY(4px)}10%,80%{opacity:1;transform:none}100%{opacity:0}}
|
|
39602
|
-
.icon,.step.cur .bar{transition:background-color .8s}.sw.pop span{animation:pop .6s ease both}@keyframes pop{50%{transform:scale(1.25)}}
|
|
39603
|
-
.quiet{color:var(--warn)}.quiet .dot{background:var(--warn)}.idle .dot{background:var(--faint)}
|
|
39604
|
-
.tog{font:inherit;font-size:12px;color:var(--muted);background:none;border:1px solid var(--line);border-radius:999px;padding:2px 9px;margin:6px 0 0 6px;cursor:pointer}.tog.on{color:var(--ink);border-color:var(--ink)}
|
|
39605
|
-
#fx{position:fixed;inset:0;width:100%;height:100%;pointer-events:none;z-index:8}
|
|
39606
|
-
@media (max-width:560px){header{flex-wrap:wrap}.right{margin-left:0;width:100%;text-align:left;display:flex;flex-wrap:wrap;align-items:center;gap:4px 12px}.right .clock{font-size:18px}.tog{margin:0 6px 0 0}}
|
|
39607
|
-
@media (prefers-reduced-motion:reduce){.enter,.changed .frame,.step.fresh .bar,.slidein,.phone.pulse,.sw.pop span,.toast{animation:none}.icon,.step.cur .bar{transition:none}}
|
|
39608
|
-
</style>
|
|
39609
|
-
</head>
|
|
39610
|
-
<body>
|
|
39611
|
-
<div class="wrap">
|
|
39612
|
-
<header><img class="icon" id="icon" alt=""><div><h1 id="name"></h1><div class="sub">Build board \xB7 updates itself as the app is built</div></div>
|
|
39613
|
-
<div class="right"><div class="clock" id="clock">00:00</div><div class="live" id="live"><span class="dot"></span><span id="updated">live</span></div>
|
|
39614
|
-
<div><span class="live idle" id="agent"><span class="dot"></span><span id="agentt">Waiting for the agent</span></span></div>
|
|
39615
|
-
<div><button class="tog" id="snd" type="button" aria-pressed="false">Sound off</button><button class="tog" id="ntf" type="button" aria-pressed="false" hidden>Notices off</button></div></div></header>
|
|
39616
|
-
<div class="steps" id="steps"></div>
|
|
39617
|
-
<div class="card now"><div style="flex:1"><div class="meta" id="nowmeta">Now</div><div class="msg" id="nowmsg"></div></div></div>
|
|
39618
|
-
<div class="grid">
|
|
39619
|
-
<div><div class="card"><h2 id="focuslbl">Latest</h2><div id="focus"></div><div class="film" id="film"></div></div></div>
|
|
39620
|
-
<div>
|
|
39621
|
-
<div class="chips" id="chips"></div>
|
|
39622
|
-
<div class="card section"><h2>Screens</h2><div class="wall" id="wall"></div></div>
|
|
39623
|
-
<div class="card section" id="brandcard"><h2>Brand</h2><div class="brand" id="brand"></div></div>
|
|
39624
|
-
<div class="card section" id="navcard"><h2>Navigation the test crawl followed</h2><div class="nav" id="nav"></div></div>
|
|
39625
|
-
<div class="card section"><h2>Postcards</h2><ul class="log" id="log"></ul></div>
|
|
39626
|
-
</div></div></div>
|
|
39627
|
-
<div id="lb"><img alt=""></div>
|
|
39628
|
-
<canvas id="fx" aria-hidden="true"></canvas>
|
|
39629
|
-
<script>window.__himiInitial = ${scriptJson(initial)};</script>
|
|
39630
|
-
<script>
|
|
39631
|
-
(function(){
|
|
39632
|
-
var cur=null, lastSeen=Date.now();
|
|
39633
|
-
function $(id){return document.getElementById(id)}
|
|
39634
|
-
function el(tag,cls,txt){var e=document.createElement(tag);if(cls)e.className=cls;if(txt!=null)e.textContent=txt;return e}
|
|
39635
|
-
function clear(e){while(e.firstChild)e.removeChild(e.firstChild)}
|
|
39636
|
-
function ago(ts){var s=Math.max(0,Math.round((Date.now()-Date.parse(ts))/1000));if(s<60)return s+"s ago";var m=Math.round(s/60);if(m<60)return m+" min ago";return Math.round(m/60)+" h ago"}
|
|
39637
|
-
function hhmm(ts){var d=new Date(ts);return d.toLocaleTimeString([], {hour:"2-digit",minute:"2-digit"})}
|
|
39638
|
-
function recent(ts){return Date.now()-Date.parse(ts)<10*60*1000}
|
|
39639
|
-
function zoomable(img){img.addEventListener("click",function(){var lb=$("lb");lb.firstChild.src=img.src;lb.style.display="flex"})}
|
|
39640
|
-
function img(src,cls){var i=el("img",cls);i.src=src;i.alt="";i.loading="lazy";zoomable(i);return i}
|
|
39641
|
-
function chip(txt,kind){return el("span","chip"+(kind?" "+kind:""),txt)}
|
|
39642
|
-
function render(s){
|
|
39643
|
-
var sn=s.current?s.current.stepNumber:0;document.title=(sn?"("+sn+"/8) ":"")+s.app.name+" \xB7 build board";favicon(sn,!!(s.live&&s.live.buildError));$("name").textContent=s.app.name;
|
|
39644
|
-
if(s.app.icon){$("icon").src=s.app.icon}else{$("icon").removeAttribute("src")}
|
|
39645
|
-
var steps=$("steps");clear(steps);var n=s.current?s.current.stepNumber:0;
|
|
39646
|
-
s.steps.forEach(function(name,i){var d=el("div","step"+(i+1<n?" done":i+1===n?" cur":""));d.appendChild(el("div","bar"));d.appendChild(el("div","lbl",(i+1)+". "+name));steps.appendChild(d)});
|
|
39647
|
-
var last=s.journal[0];
|
|
39648
|
-
$("nowmsg").textContent=last?last.message:"Waiting for the first postcard.";
|
|
39649
|
-
$("nowmeta").textContent=last?("Now \xB7 "+(last.step?("step "+last.stepNumber+" of 8, "+last.step+" \xB7 "):"")+ago(last.ts)):"Now";
|
|
39650
|
-
var focus=$("focus");var film=$("film");clear(film);
|
|
39651
|
-
/* The live frame is KEPT across renders while its URL and its run are unchanged (a restarted run on
|
|
39652
|
-
the same port is a different server, and the old frame would never see its builds). A new iframe is a full page
|
|
39653
|
-
load of the preview: every postcard, rebuild and the once-a-minute re-render used to throw away
|
|
39654
|
-
the in-place repaint, the preview's scroll and wherever the owner had navigated inside it. */
|
|
39655
|
-
var kept=s.live?focus.querySelector("iframe"):null;if(kept&&(kept.getAttribute("src")!==s.live.url||kept.getAttribute("data-run")!==s.live.runId))kept=null;
|
|
39656
|
-
if(kept){while(focus.lastChild&&focus.lastChild!==kept.parentNode)focus.removeChild(focus.lastChild)}else clear(focus);
|
|
39657
|
-
if(s.live){$("focuslbl").textContent="Live preview";if(!kept){var f=el("div","phone vpf");var fr=document.createElement("iframe");fr.className="vp";fr.setAttribute("width","390");fr.setAttribute("height","844");fr.setAttribute("data-run",s.live.runId);fr.src=s.live.url;fr.title="Live preview";f.appendChild(fr);focus.appendChild(f)}fit();if(s.live.buildError){var be=el("div","chip bad",null);be.style.display="block";be.style.marginTop="8px";be.textContent="Last edit did not build, still showing the last good version: "+s.live.buildError;focus.appendChild(be)}focus.appendChild(el("div","cap",(s.live.watching?"Repaints as the app is edited \xB7 ":"The build this run started with; himi run --watch repaints on every edit \xB7 ")+s.live.url))}
|
|
39658
|
-
else if(s.focus&&s.focus.frames.length){var fl=s.focus.frames;$("focuslbl").textContent="Latest \xB7 "+s.focus.id;var p=el("div","phone");p.appendChild(img(fl[fl.length-1].img));focus.appendChild(p);focus.appendChild(el("div","cap",fl.length+(fl.length===1?" version":" versions")+" so far"))}
|
|
39659
|
-
else{$("focuslbl").textContent="Latest";focus.appendChild(el("div","empty","The first render appears here."))}
|
|
39660
|
-
if(s.focus&&s.focus.frames.length>1)s.focus.frames.forEach(function(fm){film.appendChild(img(fm.img))});
|
|
39661
|
-
var chips=$("chips");clear(chips);var h=s.health;
|
|
39662
|
-
if(h.validate)chips.appendChild(chip(h.validate.ok?"Validate passing":"Validate: "+h.validate.errors+" errors",h.validate.ok?"ok":"bad"));
|
|
39663
|
-
if(h.test){var t=h.test;var moved=t.prevGaps!=null&&t.prevGaps!==t.gaps;var tc=chip("Test crawl: "+t.screens+" screens, "+t.actions+" actions, "+(moved?"gaps "+t.prevGaps+" \u2192 ":""),t.ok?"ok":"bad");var gn=el("span",null,String(t.gaps));gn.id="gapn";tc.appendChild(gn);if(!moved)tc.appendChild(document.createTextNode(" gaps"));chips.appendChild(tc)}
|
|
39664
|
-
h.ux.forEach(function(u){chips.appendChild(chip("UX drive "+u.platform+": "+u.status,u.status==="passed"?"ok":u.status==="failed"?"bad":"warn"))});
|
|
39665
|
-
if(h.push)chips.appendChild(chip((h.push.draft?"Draft published":"Published live")+" \xB7 "+h.push.releaseId.slice(0,10),h.push.draft?"warn":"ok"));
|
|
39666
|
-
if(!chips.firstChild)chips.appendChild(chip("Checks appear here as validate, test and push run"));
|
|
39667
|
-
var wall=$("wall");clear(wall);
|
|
39668
|
-
if(!s.screens.length)wall.appendChild(el("div","empty","Screens appear here as they render."));
|
|
39669
|
-
s.screens.forEach(function(sc){var d=el("div","shot");d.setAttribute("data-id",sc.id);var fr=el("div","frame");fr.appendChild(img(sc.img));d.appendChild(fr);d.appendChild(el("div","id",sc.id));
|
|
39670
|
-
if(recent(sc.firstSeen)&&sc.versions===1)d.appendChild(el("span","badge new","New"));else if(recent(sc.changedAt)&&sc.versions>1)d.appendChild(el("span","badge chg","Changed"));wall.appendChild(d)});
|
|
39671
|
-
var brand=$("brand");clear(brand);$("brandcard").style.display=(s.brand.site||s.app.palette.length)?"":"none";
|
|
39672
|
-
if(s.brand.site){var si=img(s.brand.site,"site");brand.appendChild(si)}
|
|
39673
|
-
if(s.brand.site&&s.focus&&s.focus.frames.length){brand.appendChild(el("span","sub","\u2192"));var pf=el("div","shot");pf.style.width="90px";var ff=el("div","frame");ff.appendChild(img(s.focus.frames[s.focus.frames.length-1].img));pf.appendChild(ff);brand.appendChild(pf)}
|
|
39674
|
-
if(s.app.palette.length){var sw=el("div","sw");s.app.palette.forEach(function(c){var d=el("span");d.style.background=c.hex;d.title=c.name+" "+c.hex;sw.appendChild(d)});brand.appendChild(sw)}
|
|
39675
|
-
var nav=$("nav");clear(nav);$("navcard").style.display=s.nav.length?"":"none";s.nav.forEach(function(e){nav.appendChild(el("span",null,e.from+" \u2192 "+e.to))});
|
|
39676
|
-
var log=$("log");clear(log);if(!s.journal.length)log.appendChild(el("li","empty","Postcards the agent journals appear here."));
|
|
39677
|
-
s.journal.forEach(function(j){var li=el("li");li.appendChild(el("div","t",hhmm(j.ts)));var body=el("div");body.appendChild(el("div",null,j.message));if(j.step)body.appendChild(el("div","s","step "+j.stepNumber+" \xB7 "+j.step));
|
|
39678
|
-
if(j.images.length){var row=el("div","imgs");j.images.forEach(function(u){row.appendChild(img(u))});body.appendChild(row)}li.appendChild(body);log.appendChild(li)});
|
|
39679
|
-
}
|
|
39680
|
-
/* Motion, sound and notices answer a CHANGE, never a redraw: effects() compares what is on the page
|
|
39681
|
-
now with what it showed last, so opening the board, the once-a-minute redraw and the two-second
|
|
39682
|
-
poll of an unchanged state do nothing, and each effect names a real event. */
|
|
39683
|
-
var seen=null,actx=null,sound=false,notices=false;try{sound=localStorage.getItem("himiStudioSound")==="1";notices=localStorage.getItem("himiStudioNotify")==="1"}catch(e){}
|
|
39684
|
-
var raf=window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(f){return setTimeout(function(){f(Date.now())},16)};
|
|
39685
|
-
function now(){return window.performance&&performance.now?performance.now():Date.now()}
|
|
39686
|
-
function reduced(){try{return matchMedia("(prefers-reduced-motion: reduce)").matches}catch(e){return false}}
|
|
39687
|
-
function tone(f,t,d,v,type){if(!sound)return;try{if(!actx){var AC=window.AudioContext||window.webkitAudioContext;if(!AC)return;actx=new AC()}var o=actx.createOscillator(),g=actx.createGain(),n=actx.currentTime+(t||0),dd=d||.18;o.type=type||"sine";o.frequency.value=f;g.gain.setValueAtTime(0,n);g.gain.linearRampToValueAtTime(v||.05,n+.01);g.gain.exponentialRampToValueAtTime(.0001,n+dd);o.connect(g);g.connect(actx.destination);o.start(n);o.stop(n+dd+.05)}catch(e){}}
|
|
39688
|
-
var SND={tick:function(){tone(1320,0,.05,.025,"triangle")},post:function(){tone(880,0,.08,.03)},step:function(){tone(523);tone(784,.12)},win:function(){tone(523);tone(659,.1);tone(784,.2);tone(1047,.3,.35)},fail:function(){tone(160,0,.3,.05,"sawtooth")}};
|
|
39689
|
-
/* Notices are the BOARD's opt-in, not just the browser's: a permission granted to this origin once
|
|
39690
|
-
(an earlier board, another run) must not switch them on, and the toggle must switch them off. */
|
|
39691
|
-
function notify(title,body){try{if(notices&&"Notification" in window&&Notification.permission==="granted"&&document.hidden)new Notification(title,{body:body})}catch(e){}}
|
|
39692
|
-
function accentNow(){return (getComputedStyle(document.documentElement).getPropertyValue("--accent")||"").trim()||"#3b6fd8"}
|
|
39693
|
-
/* The preview lays out at a real phone's viewport (390 x 844 CSS px) and is scaled into the frame.
|
|
39694
|
-
Sized to the frame itself it was ~280px wide: narrower than any phone, so screens overflowed
|
|
39695
|
-
sideways and scrolled horizontally. */
|
|
39696
|
-
function fit(){var ph=$("focus").querySelector(".phone.vpf");if(!ph)return;var w=ph.clientWidth,h=ph.clientHeight;if(w&&h)ph.style.setProperty("--k",String(Math.min(w/390,h/844)))}
|
|
39697
|
-
window.addEventListener("resize",fit);
|
|
39698
|
-
function favicon(n,bad){try{var c=document.createElement("canvas");c.width=c.height=32;var x=c.getContext&&c.getContext("2d");if(!x)return;x.lineWidth=5;x.strokeStyle="rgba(128,128,128,.35)";x.beginPath();x.arc(16,16,12,0,6.2832);x.stroke();x.strokeStyle=accentNow();x.beginPath();x.arc(16,16,12,-1.5708,-1.5708+6.2832*n/8);x.stroke();if(bad){x.fillStyle="#d33";x.beginPath();x.arc(25,7,6,0,6.2832);x.fill()}$("fav").href=c.toDataURL("image/png")}catch(e){}}
|
|
39699
|
-
function burst(){var c=$("fx");c.setAttribute("data-bursts",String((+c.getAttribute("data-bursts")||0)+1));if(reduced())return;var x=c.getContext&&c.getContext("2d");if(!x)return;var W=c.width=innerWidth,H=c.height=innerHeight,cols=["#1f7a4d","#3b6fd8","#e0a030","#d4537e",accentNow()],P=[];for(var i=0;i<120;i++)P.push({x:W/2,y:H*.35,vx:(Math.random()-.5)*14,vy:-Math.random()*12-4,c:cols[i%cols.length],r:Math.random()*6.28});var t0=now();(function f(){x.clearRect(0,0,W,H);P.forEach(function(p){p.x+=p.vx;p.y+=p.vy;p.vy+=.35;p.r+=.2;x.save();x.translate(p.x,p.y);x.rotate(p.r);x.fillStyle=p.c;x.fillRect(-4,-2,8,4);x.restore()});if(now()-t0<2200)raf(f);else x.clearRect(0,0,W,H)})()}
|
|
39700
|
-
function countTo(e,a,b){if(!e)return;if(reduced()){e.textContent=String(b);return}var t0=now();(function f(){var k=Math.min(1,(now()-t0)/900);e.textContent=String(Math.round(a+(b-a)*k));if(k<1)raf(f)})()}
|
|
39701
|
-
function snap(s){var sc={},acc=null;s.screens.forEach(function(x){sc[x.id]=x.img});s.app.palette.forEach(function(p){if(p.name==="accentPrimary")acc=p.hex});return{screens:sc,step:s.current?s.current.stepNumber:0,top:s.journal[0]?s.journal[0].ts:null,build:s.live&&s.live.lastBuild?s.live.lastBuild.at:null,run:s.live?s.live.runId:null,push:s.health.push?s.health.push.releaseId:null,gaps:s.health.test?s.health.test.gaps:null,accent:acc}}
|
|
39702
|
-
function buildLine(b){if(!b.ok)return "Build failed \xB7 still showing the last good version";var what=b.screens.length?b.screens.slice(0,3).join(", ")+(b.screens.length>3?" +"+(b.screens.length-3):""):b.tokens?"design tokens":b.config?"app config":"no visible change";return "Rebuilt"+(b.ms!=null?" in "+(b.ms/1000).toFixed(1)+" s":"")+" \xB7 "+what}
|
|
39703
|
-
function effects(s){var is=snap(s),was=seen;seen=is;if(is.accent)document.documentElement.style.setProperty("--accent",is.accent);
|
|
39704
|
-
/* The phone (kept across renders) and the Now line outlive a render: clear what they played last. */
|
|
39705
|
-
var ph=$("focus").querySelector(".phone"),nm=$("nowmsg");if(ph)ph.classList.remove("pulse","bad");nm.classList.remove("slidein");if(!was)return;
|
|
39706
|
-
var ticked=false;[].forEach.call($("wall").children,function(d){var id=d.getAttribute("data-id");if(!id)return;if(!(id in was.screens)){d.classList.add("enter");ticked=true}else if(was.screens[id]!==is.screens[id]){d.classList.add("changed");ticked=true}});if(ticked)SND.tick();
|
|
39707
|
-
if(is.top&&is.top!==was.top){void nm.offsetWidth;nm.classList.add("slidein");var li=$("log").firstChild;if(li&&li.classList)li.classList.add("slidein");SND.post()}
|
|
39708
|
-
if(is.step>was.step){var cs=$("steps").children[is.step-1];if(cs)cs.classList.add("fresh");SND.step();notify(s.app.name+" \xB7 step "+is.step+" of 8",s.journal[0]?s.journal[0].message:s.steps[is.step-1])}
|
|
39709
|
-
/* A rebuild is a later build of the SAME run: a run appearing, or restarting, records its first
|
|
39710
|
-
build too, and nothing was rebuilt then. */
|
|
39711
|
-
if(is.build&&was.build&&is.run===was.run&&is.build!==was.build){var b=s.live.lastBuild;if(ph){void ph.offsetWidth;ph.classList.add("pulse");if(!b.ok)ph.classList.add("bad")}var tt=el("div","toast"+(b.ok?"":" bad"),buildLine(b));$("focus").appendChild(tt);setTimeout(function(){if(tt.parentNode)tt.parentNode.removeChild(tt)},3500);if(b.ok)SND.tick();else{SND.fail();notify(s.app.name+" \xB7 build failed",s.live.buildError||"")}}
|
|
39712
|
-
if(was.gaps!=null&&is.gaps!=null&&is.gaps!==was.gaps)countTo($("gapn"),was.gaps,is.gaps);
|
|
39713
|
-
if(is.accent&&was.accent&&is.accent!==was.accent){var sw=$("brand").querySelector(".sw");if(sw)sw.classList.add("pop");favicon(is.step,!!(s.live&&s.live.buildError))}
|
|
39714
|
-
var published=is.push&&is.push!==was.push,handed=is.step===8&&was.step<8;if(published||handed){burst();SND.win();notify(s.app.name,published?"Draft published":"Handed over")}
|
|
39715
|
-
}
|
|
39716
|
-
function activityAt(s){var m=0;function add(v){var d=v?Date.parse(v):0;if(d>m)m=d}if(s.journal[0])add(s.journal[0].ts);s.screens.forEach(function(x){add(x.changedAt)});if(s.live&&s.live.lastBuild)add(s.live.lastBuild.at);["validate","test","push"].forEach(function(k){if(s.health[k])add(s.health[k].at)});return m}
|
|
39717
|
-
function paintToggles(){var b=$("snd");b.textContent=sound?"Sound on":"Sound off";b.className="tog"+(sound?" on":"");b.setAttribute("aria-pressed",String(sound));var nb=$("ntf");if(!("Notification" in window)){nb.hidden=true;return}var p=Notification.permission,on=notices&&p==="granted";nb.hidden=p==="denied";nb.textContent=on?"Notices on":"Notices off";nb.className="tog"+(on?" on":"");nb.setAttribute("aria-pressed",String(on))}
|
|
39718
|
-
function setNotices(v){notices=v;try{localStorage.setItem("himiStudioNotify",v?"1":"0")}catch(e){}paintToggles()}
|
|
39719
|
-
$("snd").addEventListener("click",function(){sound=!sound;try{localStorage.setItem("himiStudioSound",sound?"1":"0")}catch(e){}if(sound){try{if(actx&&actx.resume)actx.resume()}catch(e){}SND.post()}paintToggles()});
|
|
39720
|
-
/* The click acts on what the button SAYS (the effective state), so a remembered opt-in whose browser
|
|
39721
|
-
permission was since reset reads "off" and one click asks for permission, not two. */
|
|
39722
|
-
$("ntf").addEventListener("click",function(){try{var p=Notification.permission;if(notices&&p==="granted"){setNotices(false);return}if(p==="granted"){setNotices(true);return}if(Notification.permission==="default")Promise.resolve(Notification.requestPermission()).then(function(p){setNotices(p==="granted")})}catch(e){}});
|
|
39723
|
-
document.addEventListener("click",function(){try{if(actx&&actx.state==="suspended")actx.resume()}catch(e){}},{once:true});
|
|
39724
|
-
paintToggles();
|
|
39725
|
-
window.__himiStudio=function(s){lastSeen=Date.now();if(!cur||cur.v!==s.v){cur=s;render(s);effects(s)}else{cur.generatedAt=s.generatedAt}};
|
|
39726
|
-
$("lb").addEventListener("click",function(){this.style.display="none"});
|
|
39727
|
-
window.__himiStudio(window.__himiInitial);
|
|
39728
|
-
setInterval(function(){var sc=document.createElement("script");sc.src="state.js?t="+Date.now();sc.onload=sc.onerror=function(){sc.remove()};document.head.appendChild(sc)},2000);
|
|
39729
|
-
var ticks=0;
|
|
39730
|
-
setInterval(function(){if(!cur)return;if(++ticks%60===0)render(cur);var start=cur.startedAt?Date.parse(cur.startedAt):Date.now();var s=Math.max(0,Math.floor((Date.now()-start)/1000));var hh=Math.floor(s/3600),mm=Math.floor(s%3600/60),ss=s%60;
|
|
39731
|
-
$("clock").textContent=(hh?hh+":":"")+(mm<10&&hh?"0":"")+mm+":"+(ss<10?"0":"")+ss;
|
|
39732
|
-
$("updated").textContent="updated "+ago(cur.generatedAt);$("live").className="live"+(Date.now()-lastSeen>10000?" stale":"");
|
|
39733
|
-
var a=activityAt(cur),q=a?Date.now()-a:0,done=cur.current&&cur.current.stepNumber===8;
|
|
39734
|
-
$("agent").className="live"+(!a?" idle":done?"":q>5*60*1000?" quiet":"");$("agentt").textContent=!a?"Waiting for the agent":done?"Handed over":q>5*60*1000?"Quiet for "+Math.floor(q/60000)+" min":"Agent active"},1000);
|
|
39735
|
-
})();
|
|
39736
|
-
</script>
|
|
39737
|
-
</body>
|
|
39738
|
-
</html>
|
|
39739
|
-
`;
|
|
39740
|
-
}
|
|
39741
|
-
function escapeHtml(s) {
|
|
39742
|
-
return s.replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c]);
|
|
39743
|
-
}
|
|
39744
|
-
var STUDIO_DIR, STUDIO_PAGE, STATE_FILE, MEMORY_FILE, VALIDATE_RECORD, PUSH_RECORD, EDGES_RECORD, RUN_RECORD, MAX_TIMELINE, MAX_JOURNAL, MAX_NAV_EDGES, readJson2, obj, num, text, historyUrl, runTime, scriptJson;
|
|
40138
|
+
var STUDIO_DIR, STUDIO_PAGE, STATE_FILE, MEMORY_FILE, VALIDATE_RECORD, PUSH_RECORD, EDGES_RECORD, RUN_RECORD, MAX_TIMELINE, MAX_JOURNAL, MAX_NAV_EDGES, readJson2, obj, num, text, historyUrl, runTime;
|
|
39745
40139
|
var init_studio = __esm({
|
|
39746
40140
|
"src/studio.ts"() {
|
|
40141
|
+
init_studio_page();
|
|
40142
|
+
init_studio_timeline();
|
|
39747
40143
|
init_progress();
|
|
39748
|
-
|
|
39749
|
-
|
|
39750
|
-
|
|
39751
|
-
|
|
39752
|
-
|
|
39753
|
-
|
|
39754
|
-
|
|
39755
|
-
|
|
40144
|
+
init_studio_page();
|
|
40145
|
+
STUDIO_DIR = join37(".himi", "studio");
|
|
40146
|
+
STUDIO_PAGE = join37(STUDIO_DIR, "index.html");
|
|
40147
|
+
STATE_FILE = join37(STUDIO_DIR, "state.js");
|
|
40148
|
+
MEMORY_FILE = join37(STUDIO_DIR, "memory.json");
|
|
40149
|
+
VALIDATE_RECORD = join37(".himi", "validate.json");
|
|
40150
|
+
PUSH_RECORD = join37(".himi", "last-push.json");
|
|
40151
|
+
EDGES_RECORD = join37(".himi", "test-edges.json");
|
|
40152
|
+
RUN_RECORD = join37(".himi", "run.json");
|
|
39756
40153
|
MAX_TIMELINE = 500;
|
|
39757
40154
|
MAX_JOURNAL = 80;
|
|
39758
40155
|
MAX_NAV_EDGES = 40;
|
|
39759
40156
|
readJson2 = (file) => {
|
|
39760
40157
|
try {
|
|
39761
|
-
return JSON.parse(
|
|
40158
|
+
return JSON.parse(readFileSync43(file, "utf8"));
|
|
39762
40159
|
} catch {
|
|
39763
40160
|
return null;
|
|
39764
40161
|
}
|
|
@@ -39768,7 +40165,6 @@ var init_studio = __esm({
|
|
|
39768
40165
|
text = (v) => typeof v === "string" && v ? v : null;
|
|
39769
40166
|
historyUrl = (fileName) => `../history/${fileName}`;
|
|
39770
40167
|
runTime = (runId) => runId.replace(/-[0-9a-f]+$/i, "");
|
|
39771
|
-
scriptJson = (value) => JSON.stringify(value).replace(/</g, "\\u003c").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
39772
40168
|
}
|
|
39773
40169
|
});
|
|
39774
40170
|
|
|
@@ -40247,11 +40643,11 @@ __export(captcha_exports, {
|
|
|
40247
40643
|
captchaContentInput: () => captchaContentInput,
|
|
40248
40644
|
runCaptcha: () => runCaptcha
|
|
40249
40645
|
});
|
|
40250
|
-
import { readFileSync as
|
|
40646
|
+
import { readFileSync as readFileSync44 } from "node:fs";
|
|
40251
40647
|
import { resolve as resolve34 } from "node:path";
|
|
40252
40648
|
function readObject(path2) {
|
|
40253
40649
|
try {
|
|
40254
|
-
return JSON.parse(
|
|
40650
|
+
return JSON.parse(readFileSync44(path2, "utf8"));
|
|
40255
40651
|
} catch {
|
|
40256
40652
|
return {};
|
|
40257
40653
|
}
|
|
@@ -40395,11 +40791,11 @@ var init_push_setup_apple_credentials = __esm({
|
|
|
40395
40791
|
});
|
|
40396
40792
|
|
|
40397
40793
|
// src/push-onboarding.ts
|
|
40398
|
-
import { existsSync as
|
|
40399
|
-
import { basename as basename10, dirname as dirname22, join as
|
|
40794
|
+
import { existsSync as existsSync41, mkdirSync as mkdirSync18, readFileSync as readFileSync45, statSync as statSync9, writeFileSync as writeFileSync14, chmodSync as chmodSync2 } from "node:fs";
|
|
40795
|
+
import { basename as basename10, dirname as dirname22, join as join38, resolve as resolve35 } from "node:path";
|
|
40400
40796
|
function readJson3(path2) {
|
|
40401
40797
|
try {
|
|
40402
|
-
const parsed = JSON.parse(
|
|
40798
|
+
const parsed = JSON.parse(readFileSync45(path2, "utf8"));
|
|
40403
40799
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
40404
40800
|
} catch {
|
|
40405
40801
|
return {};
|
|
@@ -40407,9 +40803,9 @@ function readJson3(path2) {
|
|
|
40407
40803
|
}
|
|
40408
40804
|
function pushInputsFromContent(dir) {
|
|
40409
40805
|
const root = resolve35(dir);
|
|
40410
|
-
if (!
|
|
40411
|
-
const content = readJson3(
|
|
40412
|
-
const provisioning = readJson3(
|
|
40806
|
+
if (!existsSync41(join38(root, "himalaya.content.json"))) return { initialized: false };
|
|
40807
|
+
const content = readJson3(join38(root, "himalaya.content.json"));
|
|
40808
|
+
const provisioning = readJson3(join38(root, "provisioning.json"));
|
|
40413
40809
|
const native = provisioning.native ?? {};
|
|
40414
40810
|
return {
|
|
40415
40811
|
initialized: true,
|
|
@@ -40484,7 +40880,7 @@ function readKeyFile(path2) {
|
|
|
40484
40880
|
}
|
|
40485
40881
|
let body;
|
|
40486
40882
|
try {
|
|
40487
|
-
body =
|
|
40883
|
+
body = readFileSync45(path2, "utf8");
|
|
40488
40884
|
} catch {
|
|
40489
40885
|
return { ok: false, code: "key_file_unreadable", reason: "cannot read the selected key file; check its path and file permissions" };
|
|
40490
40886
|
}
|
|
@@ -40538,13 +40934,13 @@ function buildPushSetupBody(i, keys) {
|
|
|
40538
40934
|
};
|
|
40539
40935
|
}
|
|
40540
40936
|
function readPushOnboarding(dir) {
|
|
40541
|
-
const path2 =
|
|
40542
|
-
if (!
|
|
40937
|
+
const path2 = join38(resolve35(dir), PUSH_ONBOARDING_PATH);
|
|
40938
|
+
if (!existsSync41(path2)) return { version: 1 };
|
|
40543
40939
|
const parsed = readJson3(path2);
|
|
40544
40940
|
return { version: 1, ...parsed };
|
|
40545
40941
|
}
|
|
40546
40942
|
function writeFile(dir, file) {
|
|
40547
|
-
const path2 =
|
|
40943
|
+
const path2 = join38(resolve35(dir), PUSH_ONBOARDING_PATH);
|
|
40548
40944
|
mkdirSync18(dirname22(path2), { recursive: true, mode: 448 });
|
|
40549
40945
|
writeFileSync14(path2, JSON.stringify(file, null, 2) + "\n", { mode: 384 });
|
|
40550
40946
|
try {
|
|
@@ -40573,8 +40969,8 @@ function recordPushDeferral(dir, d) {
|
|
|
40573
40969
|
return push;
|
|
40574
40970
|
}
|
|
40575
40971
|
function clearPushDeferral(dir) {
|
|
40576
|
-
const path2 =
|
|
40577
|
-
if (!
|
|
40972
|
+
const path2 = join38(resolve35(dir), PUSH_ONBOARDING_PATH);
|
|
40973
|
+
if (!existsSync41(path2)) return;
|
|
40578
40974
|
const { push: _dropped, ...rest } = readPushOnboarding(dir);
|
|
40579
40975
|
writeFile(dir, { ...rest, version: 1 });
|
|
40580
40976
|
}
|
|
@@ -41307,8 +41703,8 @@ __export(template_trim_exports, {
|
|
|
41307
41703
|
routeMatcher: () => routeMatcher,
|
|
41308
41704
|
runTemplateTrim: () => runTemplateTrim
|
|
41309
41705
|
});
|
|
41310
|
-
import { cpSync, existsSync as
|
|
41311
|
-
import { dirname as dirname23, join as
|
|
41706
|
+
import { cpSync, existsSync as existsSync42, mkdirSync as mkdirSync19, readdirSync as readdirSync21, readFileSync as readFileSync46, renameSync as renameSync4, rmSync as rmSync8, statSync as statSync10, writeFileSync as writeFileSync15 } from "node:fs";
|
|
41707
|
+
import { dirname as dirname23, join as join39 } from "node:path";
|
|
41312
41708
|
function routeMatcher(pattern) {
|
|
41313
41709
|
const detail = /^\^([A-Za-z0-9_]+)\(\?:\[_\/\]\(\.\+\)\)\?\$$/.exec(pattern);
|
|
41314
41710
|
if (detail) {
|
|
@@ -42002,20 +42398,20 @@ function homeModulesPass(app, kept, edited) {
|
|
|
42002
42398
|
return { text: patched.src, dropped: patched.droppedModules };
|
|
42003
42399
|
}
|
|
42004
42400
|
function listWorkers(dir) {
|
|
42005
|
-
const root =
|
|
42006
|
-
if (!
|
|
42007
|
-
const dirs = readdirSync21(root).filter((n) => statSync10(
|
|
42401
|
+
const root = join39(dir, "tier5-src");
|
|
42402
|
+
if (!existsSync42(root)) return { dirs: [], files: {} };
|
|
42403
|
+
const dirs = readdirSync21(root).filter((n) => statSync10(join39(root, n)).isDirectory()).sort();
|
|
42008
42404
|
const files = {};
|
|
42009
42405
|
const walk2 = (abs, rel) => {
|
|
42010
42406
|
for (const name of readdirSync21(abs)) {
|
|
42011
42407
|
if (name === "node_modules") continue;
|
|
42012
|
-
const p =
|
|
42408
|
+
const p = join39(abs, name);
|
|
42013
42409
|
const r = `${rel}/${name}`;
|
|
42014
42410
|
if (statSync10(p).isDirectory()) walk2(p, r);
|
|
42015
|
-
else if (/\.(?:[cm]?[jt]sx?|json)$/.test(name)) files[r] =
|
|
42411
|
+
else if (/\.(?:[cm]?[jt]sx?|json)$/.test(name)) files[r] = readFileSync46(p, "utf8");
|
|
42016
42412
|
}
|
|
42017
42413
|
};
|
|
42018
|
-
for (const d of dirs) walk2(
|
|
42414
|
+
for (const d of dirs) walk2(join39(root, d), `tier5-src/${d}`);
|
|
42019
42415
|
return { dirs, files };
|
|
42020
42416
|
}
|
|
42021
42417
|
function csv(v) {
|
|
@@ -42038,16 +42434,16 @@ async function runTemplateTrim(req, deps) {
|
|
|
42038
42434
|
links = req.links;
|
|
42039
42435
|
}
|
|
42040
42436
|
const dir = req.dir;
|
|
42041
|
-
const devPath =
|
|
42042
|
-
const configPath =
|
|
42043
|
-
if (!
|
|
42437
|
+
const devPath = join39(dir, "dev/index.ts");
|
|
42438
|
+
const configPath = join39(dir, "config.ts");
|
|
42439
|
+
if (!existsSync42(devPath) || !existsSync42(configPath)) {
|
|
42044
42440
|
return refuse3(new TrimRefusal(`${dir} has no dev/index.ts + config.ts \u2014 point --content at an app scaffolded with \`himi init --template\``));
|
|
42045
42441
|
}
|
|
42046
42442
|
if (isTemplateSourceTree(dir)) {
|
|
42047
42443
|
return refuse3(new TrimRefusal(`${dir} is a template source tree (its identity is still __HIMI_APP_*__ sentinels) \u2014 trim the app \`himi init --template\` scaffolds from it, not the template itself`));
|
|
42048
42444
|
}
|
|
42049
|
-
const dev =
|
|
42050
|
-
const config =
|
|
42445
|
+
const dev = readFileSync46(devPath, "utf8");
|
|
42446
|
+
const config = readFileSync46(configPath, "utf8");
|
|
42051
42447
|
const workers = listWorkers(dir);
|
|
42052
42448
|
let plan;
|
|
42053
42449
|
try {
|
|
@@ -42057,22 +42453,22 @@ async function runTemplateTrim(req, deps) {
|
|
|
42057
42453
|
throw e;
|
|
42058
42454
|
}
|
|
42059
42455
|
if (req.dryRun) return { code: 0, result: { ok: true, dryRun: true, ...plan.report, validate: null } };
|
|
42060
|
-
const hadHimi =
|
|
42061
|
-
const backupRel =
|
|
42062
|
-
const backup =
|
|
42456
|
+
const hadHimi = existsSync42(join39(dir, ".himi"));
|
|
42457
|
+
const backupRel = join39(".himi", "trim-backup", (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-"));
|
|
42458
|
+
const backup = join39(dir, backupRel);
|
|
42063
42459
|
const originals = [[devPath, "dev/index.ts"], [configPath, "config.ts"]];
|
|
42064
42460
|
const moved = [];
|
|
42065
42461
|
const restore = () => {
|
|
42066
42462
|
for (const [path2, rel] of originals) {
|
|
42067
|
-
const original =
|
|
42068
|
-
if (!
|
|
42463
|
+
const original = readFileSync46(join39(backup, rel));
|
|
42464
|
+
if (!existsSync42(path2) || !readFileSync46(path2).equals(original)) writeFileSync15(path2, original);
|
|
42069
42465
|
}
|
|
42070
|
-
for (const name of [...moved].reverse()) renameSync4(
|
|
42466
|
+
for (const name of [...moved].reverse()) renameSync4(join39(backup, "tier5-src", name), join39(dir, "tier5-src", name));
|
|
42071
42467
|
};
|
|
42072
42468
|
const dropBackup = () => {
|
|
42073
42469
|
rmSync8(backup, { recursive: true, force: true });
|
|
42074
|
-
for (const d of [dirname23(backup),
|
|
42075
|
-
if (d ===
|
|
42470
|
+
for (const d of [dirname23(backup), join39(dir, ".himi")]) {
|
|
42471
|
+
if (d === join39(dir, ".himi") && hadHimi) break;
|
|
42076
42472
|
try {
|
|
42077
42473
|
if (!readdirSync21(d).length) rmSync8(d, { recursive: true });
|
|
42078
42474
|
} catch {
|
|
@@ -42098,9 +42494,9 @@ async function runTemplateTrim(req, deps) {
|
|
|
42098
42494
|
return { code: 1, result: { ok: false, error: `${error} (${message}); every file was restored`, rolledBack: true, ...base(validate4) } };
|
|
42099
42495
|
};
|
|
42100
42496
|
try {
|
|
42101
|
-
mkdirSync19(
|
|
42102
|
-
for (const [path2, rel] of originals) cpSync(path2,
|
|
42103
|
-
if (plan.removedWorkers.length) mkdirSync19(
|
|
42497
|
+
mkdirSync19(join39(backup, "dev"), { recursive: true });
|
|
42498
|
+
for (const [path2, rel] of originals) cpSync(path2, join39(backup, rel));
|
|
42499
|
+
if (plan.removedWorkers.length) mkdirSync19(join39(backup, "tier5-src"), { recursive: true });
|
|
42104
42500
|
} catch (e) {
|
|
42105
42501
|
dropBackup();
|
|
42106
42502
|
return { code: 1, result: { ok: false, error: `could not back up the app before trimming it (${e.message}); nothing was changed`, rolledBack: true, ...base() } };
|
|
@@ -42108,7 +42504,7 @@ async function runTemplateTrim(req, deps) {
|
|
|
42108
42504
|
try {
|
|
42109
42505
|
const moveDir = deps.moveDir ?? renameSync4;
|
|
42110
42506
|
for (const name of plan.removedWorkers) {
|
|
42111
|
-
moveDir(
|
|
42507
|
+
moveDir(join39(dir, "tier5-src", name), join39(backup, "tier5-src", name));
|
|
42112
42508
|
moved.push(name);
|
|
42113
42509
|
}
|
|
42114
42510
|
if (plan.dev !== dev) writeFileSync15(devPath, plan.dev);
|
|
@@ -42119,7 +42515,7 @@ async function runTemplateTrim(req, deps) {
|
|
|
42119
42515
|
let failure;
|
|
42120
42516
|
let validate3;
|
|
42121
42517
|
try {
|
|
42122
|
-
const written = parseApp(
|
|
42518
|
+
const written = parseApp(readFileSync46(devPath, "utf8"), readFileSync46(configPath, "utf8"));
|
|
42123
42519
|
const leftovers = leftoverNavRefs(written.nav.value, plan.removedIds);
|
|
42124
42520
|
if (leftovers.length) failure = { error: "navigation still names screens this trim removed", leftovers };
|
|
42125
42521
|
else {
|
|
@@ -42813,8 +43209,8 @@ __export(pack_exports, {
|
|
|
42813
43209
|
});
|
|
42814
43210
|
import { createHash as createHash21 } from "node:crypto";
|
|
42815
43211
|
import { deflateRawSync, inflateRawSync } from "node:zlib";
|
|
42816
|
-
import { existsSync as
|
|
42817
|
-
import { dirname as dirname24, join as
|
|
43212
|
+
import { existsSync as existsSync43, mkdirSync as mkdirSync20, readFileSync as readFileSync47, readdirSync as readdirSync22, rmSync as rmSync9, statSync as statSync11, writeFileSync as writeFileSync16 } from "node:fs";
|
|
43213
|
+
import { dirname as dirname24, join as join40, resolve as resolve37 } from "node:path";
|
|
42818
43214
|
function writeZip(entries) {
|
|
42819
43215
|
const sorted2 = entries.slice().sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
42820
43216
|
const total = sorted2.reduce((n, e) => n + e.bytes.length, 0);
|
|
@@ -42908,13 +43304,13 @@ function inflateEntry(buf, entry) {
|
|
|
42908
43304
|
return bytes2;
|
|
42909
43305
|
}
|
|
42910
43306
|
function readIf(path2) {
|
|
42911
|
-
return
|
|
43307
|
+
return existsSync43(path2) && statSync11(path2).isFile() ? readFileSync47(path2) : null;
|
|
42912
43308
|
}
|
|
42913
43309
|
function listDir(dir) {
|
|
42914
|
-
return
|
|
43310
|
+
return existsSync43(dir) ? readdirSync22(dir).filter((f) => statSync11(join40(dir, f)).isFile()) : [];
|
|
42915
43311
|
}
|
|
42916
43312
|
function gatherReleaseEntries(appDir2) {
|
|
42917
|
-
const manifestPath =
|
|
43313
|
+
const manifestPath = join40(appDir2, HIMI_PACKAGE_MANIFEST_PATH);
|
|
42918
43314
|
const manifestBytes = readIf(manifestPath);
|
|
42919
43315
|
if (!manifestBytes) throw new Error(`no ${HIMI_PACKAGE_MANIFEST_PATH} in ${appDir2} \u2014 build a release there first`);
|
|
42920
43316
|
const manifest = JSON.parse(manifestBytes.toString("utf8"));
|
|
@@ -42938,7 +43334,7 @@ function gatherReleaseEntries(appDir2) {
|
|
|
42938
43334
|
}
|
|
42939
43335
|
const missing = [];
|
|
42940
43336
|
for (const rel of wanted) {
|
|
42941
|
-
const bytes2 = readIf(
|
|
43337
|
+
const bytes2 = readIf(join40(appDir2, rel));
|
|
42942
43338
|
if (bytes2) entries.push({ path: rel, bytes: bytes2 });
|
|
42943
43339
|
else missing.push(rel);
|
|
42944
43340
|
}
|
|
@@ -42949,12 +43345,12 @@ function gatherReleaseEntries(appDir2) {
|
|
|
42949
43345
|
);
|
|
42950
43346
|
}
|
|
42951
43347
|
for (const name of SINGLETONS) {
|
|
42952
|
-
const bytes2 = readIf(
|
|
43348
|
+
const bytes2 = readIf(join40(appDir2, name));
|
|
42953
43349
|
if (bytes2) entries.push({ path: name, bytes: bytes2 });
|
|
42954
43350
|
}
|
|
42955
43351
|
const skipped = [];
|
|
42956
43352
|
for (const sub of ["screens", "bundles", "assets", "widgets"]) {
|
|
42957
|
-
for (const f of listDir(
|
|
43353
|
+
for (const f of listDir(join40(appDir2, sub))) {
|
|
42958
43354
|
if (!wanted.has(`${sub}/${f}`)) skipped.push(`${sub}/${f}`);
|
|
42959
43355
|
}
|
|
42960
43356
|
}
|
|
@@ -42987,18 +43383,18 @@ function buildEntries(appDir2, app, opts) {
|
|
|
42987
43383
|
return { all, header, manifest, skipped };
|
|
42988
43384
|
}
|
|
42989
43385
|
function packRelease(releaseRoot, app, out, opts = {}) {
|
|
42990
|
-
const appDir2 =
|
|
43386
|
+
const appDir2 = join40(resolve37(releaseRoot), app);
|
|
42991
43387
|
const { all, header, skipped } = buildEntries(appDir2, app, opts);
|
|
42992
43388
|
const buf = writeZip(all);
|
|
42993
|
-
const isDir2 =
|
|
42994
|
-
const outFile = isDir2 ?
|
|
43389
|
+
const isDir2 = existsSync43(out) && statSync11(out).isDirectory();
|
|
43390
|
+
const outFile = isDir2 ? join40(resolve37(out), packageFileName(app, header.releaseId)) : resolve37(out);
|
|
42995
43391
|
mkdirSync20(dirname24(outFile), { recursive: true });
|
|
42996
43392
|
writeFileSync16(outFile, buf);
|
|
42997
43393
|
return { app, releaseId: header.releaseId, header, out: outFile, bytes: buf.length, entryCount: all.length, skipped };
|
|
42998
43394
|
}
|
|
42999
43395
|
function resolvePackageDirDest(outDir, app, releaseId) {
|
|
43000
43396
|
const packagedApp = (dir) => {
|
|
43001
|
-
const bytes2 = readIf(
|
|
43397
|
+
const bytes2 = readIf(join40(dir, HIMI_PACKAGE_HEADER_PATH));
|
|
43002
43398
|
if (!bytes2) return void 0;
|
|
43003
43399
|
try {
|
|
43004
43400
|
return JSON.parse(bytes2.toString("utf8")).app;
|
|
@@ -43007,15 +43403,15 @@ function resolvePackageDirDest(outDir, app, releaseId) {
|
|
|
43007
43403
|
}
|
|
43008
43404
|
};
|
|
43009
43405
|
const replaceable = (dir) => {
|
|
43010
|
-
if (!
|
|
43406
|
+
if (!existsSync43(dir)) return true;
|
|
43011
43407
|
if (!statSync11(dir).isDirectory()) return false;
|
|
43012
43408
|
return readdirSync22(dir).length === 0 || packagedApp(dir) === app;
|
|
43013
43409
|
};
|
|
43014
|
-
if (
|
|
43410
|
+
if (existsSync43(outDir) && !statSync11(outDir).isDirectory()) {
|
|
43015
43411
|
throw new Error(`refusing to write a package tree over ${outDir} \u2014 it is a file, not a directory`);
|
|
43016
43412
|
}
|
|
43017
43413
|
if (replaceable(outDir)) return outDir;
|
|
43018
|
-
const child =
|
|
43414
|
+
const child = join40(outDir, packageDirName(app, releaseId));
|
|
43019
43415
|
if (!replaceable(child)) {
|
|
43020
43416
|
throw new Error(
|
|
43021
43417
|
`refusing to replace ${child}: it is not empty and is not a ${app} package (no ${HIMI_PACKAGE_HEADER_PATH}). Pass --out to a new or empty directory.`
|
|
@@ -43029,13 +43425,13 @@ function packReleaseToDir(releaseRoot, app, outDir, opts = {}) {
|
|
|
43029
43425
|
"a package carrying the app's source has no --format dir form: readers that predate the source entry drop it before hashing a directory and refuse the package as tampered. Pack it as a .himi archive."
|
|
43030
43426
|
);
|
|
43031
43427
|
}
|
|
43032
|
-
const appDir2 =
|
|
43428
|
+
const appDir2 = join40(resolve37(releaseRoot), app);
|
|
43033
43429
|
const { all, header, skipped } = buildEntries(appDir2, app, opts);
|
|
43034
43430
|
const dest = resolvePackageDirDest(resolve37(outDir), app, header.releaseId);
|
|
43035
43431
|
rmSync9(dest, { recursive: true, force: true });
|
|
43036
43432
|
let bytes2 = 0;
|
|
43037
43433
|
for (const entry of all) {
|
|
43038
|
-
const target =
|
|
43434
|
+
const target = join40(dest, entry.path);
|
|
43039
43435
|
mkdirSync20(dirname24(target), { recursive: true });
|
|
43040
43436
|
writeFileSync16(target, entry.bytes);
|
|
43041
43437
|
bytes2 += entry.bytes.length;
|
|
@@ -43058,21 +43454,21 @@ function openPackageBuffer(buf) {
|
|
|
43058
43454
|
return openFromEntries(readZip(buf), { requireHeader: true });
|
|
43059
43455
|
}
|
|
43060
43456
|
function openPackageFile(file) {
|
|
43061
|
-
return openPackageBuffer(
|
|
43457
|
+
return openPackageBuffer(readFileSync47(file));
|
|
43062
43458
|
}
|
|
43063
43459
|
function openPackageDir(dir) {
|
|
43064
43460
|
const root = resolve37(dir);
|
|
43065
43461
|
const entries = /* @__PURE__ */ new Map();
|
|
43066
43462
|
const walk2 = (rel) => {
|
|
43067
|
-
const abs = rel ?
|
|
43463
|
+
const abs = rel ? join40(root, rel) : root;
|
|
43068
43464
|
for (const name of readdirSync22(abs)) {
|
|
43069
43465
|
const childRel = rel ? `${rel}/${name}` : name;
|
|
43070
|
-
const childAbs =
|
|
43466
|
+
const childAbs = join40(abs, name);
|
|
43071
43467
|
if (statSync11(childAbs).isDirectory()) walk2(childRel);
|
|
43072
|
-
else if (isSafeEntryName(childRel)) entries.set(childRel,
|
|
43468
|
+
else if (isSafeEntryName(childRel)) entries.set(childRel, readFileSync47(childAbs));
|
|
43073
43469
|
}
|
|
43074
43470
|
};
|
|
43075
|
-
if (!
|
|
43471
|
+
if (!existsSync43(root)) throw new Error(`no such package directory: ${root}`);
|
|
43076
43472
|
walk2("");
|
|
43077
43473
|
const manifestBytes = entries.get(HIMI_PACKAGE_MANIFEST_PATH);
|
|
43078
43474
|
if (manifestBytes) {
|
|
@@ -43114,10 +43510,10 @@ function unpackTo(buf, dest, appFallback) {
|
|
|
43114
43510
|
if (!app) throw new Error("package declares no app id (no himi-package.json and no manifest.app)");
|
|
43115
43511
|
if (!isSafeAppId(app)) throw new Error(`package declares an unsafe app id ${JSON.stringify(app)} \u2014 refusing to unpack it`);
|
|
43116
43512
|
const root = resolve37(dest);
|
|
43117
|
-
const appDir2 =
|
|
43513
|
+
const appDir2 = join40(root, app);
|
|
43118
43514
|
rmSync9(appDir2, { recursive: true, force: true });
|
|
43119
43515
|
for (const [rel, bytes2] of entries) {
|
|
43120
|
-
const target =
|
|
43516
|
+
const target = join40(appDir2, rel);
|
|
43121
43517
|
mkdirSync20(dirname24(target), { recursive: true });
|
|
43122
43518
|
writeFileSync16(target, bytes2);
|
|
43123
43519
|
}
|
|
@@ -43153,20 +43549,20 @@ __export(app_source_exports, {
|
|
|
43153
43549
|
writeConflicts: () => writeConflicts,
|
|
43154
43550
|
zipAppSource: () => zipAppSource
|
|
43155
43551
|
});
|
|
43156
|
-
import { readdirSync as readdirSync23, lstatSync as lstatSync6, readFileSync as
|
|
43157
|
-
import { join as
|
|
43552
|
+
import { readdirSync as readdirSync23, lstatSync as lstatSync6, readFileSync as readFileSync48, mkdirSync as mkdirSync21, writeFileSync as writeFileSync17, existsSync as existsSync44, rmSync as rmSync10, rmdirSync, unlinkSync as unlinkSync3 } from "node:fs";
|
|
43553
|
+
import { join as join41, resolve as resolve38, sep as sep10 } from "node:path";
|
|
43158
43554
|
import { deflateRawSync as deflateRawSync2 } from "node:zlib";
|
|
43159
43555
|
function walkSourceTree(dir, file, skip) {
|
|
43160
43556
|
const walk2 = (relDir) => {
|
|
43161
|
-
for (const name of readdirSync23(
|
|
43162
|
-
const rel = relDir ?
|
|
43163
|
-
const st = lstatSync6(
|
|
43557
|
+
for (const name of readdirSync23(join41(dir, relDir))) {
|
|
43558
|
+
const rel = relDir ? join41(relDir, name) : name;
|
|
43559
|
+
const st = lstatSync6(join41(dir, rel));
|
|
43164
43560
|
if (st.isSymbolicLink()) {
|
|
43165
43561
|
skip(rel);
|
|
43166
43562
|
continue;
|
|
43167
43563
|
}
|
|
43168
43564
|
if (st.isDirectory()) {
|
|
43169
|
-
if (isDeniedSourceDir(name, relDir) ||
|
|
43565
|
+
if (isDeniedSourceDir(name, relDir) || existsSync44(join41(dir, rel, PACKAGE_DIR_MARKER))) skip(rel);
|
|
43170
43566
|
else walk2(rel);
|
|
43171
43567
|
continue;
|
|
43172
43568
|
}
|
|
@@ -43184,7 +43580,7 @@ function collectAppSource(dir) {
|
|
|
43184
43580
|
const skipped = [];
|
|
43185
43581
|
walkSourceTree(
|
|
43186
43582
|
dir,
|
|
43187
|
-
(archivePath, hostRel) => entries.push({ path: archivePath, bytes:
|
|
43583
|
+
(archivePath, hostRel) => entries.push({ path: archivePath, bytes: readFileSync48(join41(dir, hostRel)) }),
|
|
43188
43584
|
(hostRel) => skipped.push(hostRel)
|
|
43189
43585
|
);
|
|
43190
43586
|
entries.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
@@ -43238,13 +43634,13 @@ function writeAppSource(entries, destDir) {
|
|
|
43238
43634
|
const segments = entry.path.split("/");
|
|
43239
43635
|
let dir = root;
|
|
43240
43636
|
for (const segment of segments.slice(0, -1)) {
|
|
43241
|
-
dir =
|
|
43637
|
+
dir = join41(dir, segment);
|
|
43242
43638
|
const kind = pathKind(dir);
|
|
43243
43639
|
if (kind?.isSymbolicLink()) unlinkSync3(dir);
|
|
43244
43640
|
else if (kind) continue;
|
|
43245
43641
|
mkdirSync21(dir);
|
|
43246
43642
|
}
|
|
43247
|
-
const target =
|
|
43643
|
+
const target = join41(root, ...segments);
|
|
43248
43644
|
if (pathKind(target)?.isSymbolicLink()) unlinkSync3(target);
|
|
43249
43645
|
writeFileSync17(target, entry.bytes);
|
|
43250
43646
|
written.push(entry.path);
|
|
@@ -43252,7 +43648,7 @@ function writeAppSource(entries, destDir) {
|
|
|
43252
43648
|
return written;
|
|
43253
43649
|
}
|
|
43254
43650
|
function staleSourcePaths(entries, destDir) {
|
|
43255
|
-
if (!
|
|
43651
|
+
if (!existsSync44(destDir)) return [];
|
|
43256
43652
|
const archived = new Set(entries.map((e) => e.path));
|
|
43257
43653
|
const stale = [];
|
|
43258
43654
|
walkSourceTree(destDir, (archivePath) => {
|
|
@@ -43279,7 +43675,7 @@ function writeConflicts(entries, destDir) {
|
|
|
43279
43675
|
let dir = root;
|
|
43280
43676
|
let stop = false;
|
|
43281
43677
|
for (const [i, segment] of segments.slice(0, -1).entries()) {
|
|
43282
|
-
dir =
|
|
43678
|
+
dir = join41(dir, segment);
|
|
43283
43679
|
const kind2 = pathKind(dir);
|
|
43284
43680
|
if (!kind2 || kind2.isSymbolicLink()) {
|
|
43285
43681
|
stop = true;
|
|
@@ -43291,7 +43687,7 @@ function writeConflicts(entries, destDir) {
|
|
|
43291
43687
|
break;
|
|
43292
43688
|
}
|
|
43293
43689
|
if (stop) continue;
|
|
43294
|
-
const kind = pathKind(
|
|
43690
|
+
const kind = pathKind(join41(root, ...segments));
|
|
43295
43691
|
if (kind && !kind.isSymbolicLink() && kind.isDirectory()) {
|
|
43296
43692
|
say(entry.path, "is a directory here, but the release has a file at that path");
|
|
43297
43693
|
}
|
|
@@ -43301,22 +43697,22 @@ function writeConflicts(entries, destDir) {
|
|
|
43301
43697
|
function removeStaleSource(entries, destDir) {
|
|
43302
43698
|
const root = resolve38(destDir);
|
|
43303
43699
|
const removed = staleSourcePaths(entries, root);
|
|
43304
|
-
for (const rel of removed) rmSync10(
|
|
43700
|
+
for (const rel of removed) rmSync10(join41(root, ...rel.split("/")), { force: true });
|
|
43305
43701
|
const needed = /* @__PURE__ */ new Set();
|
|
43306
43702
|
for (const entry of entries) {
|
|
43307
43703
|
if (isDeniedSourcePath(entry.path)) continue;
|
|
43308
43704
|
const segments = entry.path.split("/");
|
|
43309
43705
|
for (let i = 1; i < segments.length; i++) needed.add(segments.slice(0, i).join("/"));
|
|
43310
43706
|
}
|
|
43311
|
-
if (
|
|
43707
|
+
if (existsSync44(root)) pruneEmptyDirs(root, "", needed, removed);
|
|
43312
43708
|
return removed.sort();
|
|
43313
43709
|
}
|
|
43314
43710
|
function pruneEmptyDirs(root, rel, needed, removed) {
|
|
43315
43711
|
let empty = true;
|
|
43316
|
-
for (const name of readdirSync23(rel ?
|
|
43317
|
-
const childRel = rel ?
|
|
43712
|
+
for (const name of readdirSync23(rel ? join41(root, rel) : root)) {
|
|
43713
|
+
const childRel = rel ? join41(rel, name) : name;
|
|
43318
43714
|
const posix3 = childRel.split(sep10).join("/");
|
|
43319
|
-
const kind = lstatSync6(
|
|
43715
|
+
const kind = lstatSync6(join41(root, childRel));
|
|
43320
43716
|
if (kind.isSymbolicLink() || !kind.isDirectory() || isDeniedSourceDir(name, rel)) {
|
|
43321
43717
|
empty = false;
|
|
43322
43718
|
continue;
|
|
@@ -43326,7 +43722,7 @@ function pruneEmptyDirs(root, rel, needed, removed) {
|
|
|
43326
43722
|
empty = false;
|
|
43327
43723
|
continue;
|
|
43328
43724
|
}
|
|
43329
|
-
rmdirSync(
|
|
43725
|
+
rmdirSync(join41(root, childRel));
|
|
43330
43726
|
removed.push(`${posix3}/`);
|
|
43331
43727
|
}
|
|
43332
43728
|
return empty;
|
|
@@ -43381,13 +43777,13 @@ __export(eject_exports, {
|
|
|
43381
43777
|
EJECTABLE: () => EJECTABLE,
|
|
43382
43778
|
ejectModule: () => ejectModule
|
|
43383
43779
|
});
|
|
43384
|
-
import { existsSync as
|
|
43385
|
-
import { dirname as dirname25, join as
|
|
43780
|
+
import { existsSync as existsSync45, mkdirSync as mkdirSync22, readFileSync as readFileSync49, writeFileSync as writeFileSync18 } from "node:fs";
|
|
43781
|
+
import { dirname as dirname25, join as join42, relative as relative7, resolve as resolve39, sep as sep11 } from "node:path";
|
|
43386
43782
|
function locate(repoRootOrCwd, mod) {
|
|
43387
43783
|
const inRepo = resolve39(repoRootOrCwd, `stdlib/flows/${mod}/src/index.ts`);
|
|
43388
|
-
if (
|
|
43784
|
+
if (existsSync45(inRepo)) return { path: inRepo, form: "source" };
|
|
43389
43785
|
const dist = resolve39(repoRootOrCwd, `node_modules/@wix/himalaya/dist/${mod}.mjs`);
|
|
43390
|
-
if (
|
|
43786
|
+
if (existsSync45(dist)) return { path: dist, form: "bundle" };
|
|
43391
43787
|
return null;
|
|
43392
43788
|
}
|
|
43393
43789
|
function specifiersFor(mod) {
|
|
@@ -43411,7 +43807,7 @@ function ejectModule(opts) {
|
|
|
43411
43807
|
};
|
|
43412
43808
|
}
|
|
43413
43809
|
const ext = found.form === "source" ? "ts" : "mjs";
|
|
43414
|
-
const target =
|
|
43810
|
+
const target = join42(contentDir2, "tier5-src", "_ejected", `${mod}.${ext}`);
|
|
43415
43811
|
mkdirSync22(dirname25(target), { recursive: true });
|
|
43416
43812
|
const banner = `// EJECTED from @wix/himalaya/${mod}. This app owns this file now.
|
|
43417
43813
|
//
|
|
@@ -43425,15 +43821,15 @@ function ejectModule(opts) {
|
|
|
43425
43821
|
// gate still applies. Ejecting buys layout and flow, never the floor.
|
|
43426
43822
|
|
|
43427
43823
|
`;
|
|
43428
|
-
const normalized =
|
|
43824
|
+
const normalized = readFileSync49(found.path, "utf8").replace(
|
|
43429
43825
|
/(["'])@himalaya\/([a-z0-9-]+(?:\/[a-z0-9-]+)?)\1/g,
|
|
43430
43826
|
(_m, q, sub) => `${q}@wix/himalaya/${sub}${q}`
|
|
43431
43827
|
);
|
|
43432
43828
|
writeFileSync18(target, banner + normalized);
|
|
43433
43829
|
const rewired = [];
|
|
43434
43830
|
for (const f of files) {
|
|
43435
|
-
if (!
|
|
43436
|
-
const before =
|
|
43831
|
+
if (!existsSync45(f)) continue;
|
|
43832
|
+
const before = readFileSync49(f, "utf8");
|
|
43437
43833
|
let after = before;
|
|
43438
43834
|
let rel = relative7(dirname25(f), target).split(sep11).join("/").replace(/\.tsx?$/, ".js");
|
|
43439
43835
|
if (!rel.startsWith(".")) rel = `./${rel}`;
|
|
@@ -43481,14 +43877,14 @@ __export(test_exports, {
|
|
|
43481
43877
|
scopeDescriptors: () => scopeDescriptors,
|
|
43482
43878
|
writeRecordedMocks: () => writeRecordedMocks
|
|
43483
43879
|
});
|
|
43484
|
-
import { existsSync as
|
|
43485
|
-
import { join as
|
|
43880
|
+
import { existsSync as existsSync46, mkdirSync as mkdirSync23, readFileSync as readFileSync50, writeFileSync as writeFileSync19 } from "node:fs";
|
|
43881
|
+
import { join as join43, resolve as resolve40 } from "node:path";
|
|
43486
43882
|
function readTestConfig(dir) {
|
|
43487
43883
|
const p = resolve40(dir, TEST_CONFIG_FILE);
|
|
43488
|
-
if (!
|
|
43884
|
+
if (!existsSync46(p)) return {};
|
|
43489
43885
|
let parsed;
|
|
43490
43886
|
try {
|
|
43491
|
-
parsed = JSON.parse(
|
|
43887
|
+
parsed = JSON.parse(readFileSync50(p, "utf8"));
|
|
43492
43888
|
} catch (e) {
|
|
43493
43889
|
throw new Error(`${TEST_CONFIG_FILE} is not valid JSON \u2014 ${e.message}`);
|
|
43494
43890
|
}
|
|
@@ -43531,7 +43927,7 @@ function readTestConfig(dir) {
|
|
|
43531
43927
|
function readNetRules(path2) {
|
|
43532
43928
|
let parsed;
|
|
43533
43929
|
try {
|
|
43534
|
-
parsed = JSON.parse(
|
|
43930
|
+
parsed = JSON.parse(readFileSync50(path2, "utf8"));
|
|
43535
43931
|
} catch (e) {
|
|
43536
43932
|
throw new Error(`--net ${path2} could not be read as JSON \u2014 ${e.message}`);
|
|
43537
43933
|
}
|
|
@@ -43552,7 +43948,7 @@ function readNetRules(path2) {
|
|
|
43552
43948
|
function defaultNetRules(dir) {
|
|
43553
43949
|
for (const rel of ["dev/net-mocks.json", "tests/net-mocks.json"]) {
|
|
43554
43950
|
const p = resolve40(dir, rel);
|
|
43555
|
-
if (
|
|
43951
|
+
if (existsSync46(p)) {
|
|
43556
43952
|
const rules = readNetRules(p);
|
|
43557
43953
|
if (rules.length) return { rules, from: rel };
|
|
43558
43954
|
}
|
|
@@ -43568,7 +43964,7 @@ function readCannedResponses() {
|
|
|
43568
43964
|
];
|
|
43569
43965
|
for (const url of candidates) {
|
|
43570
43966
|
try {
|
|
43571
|
-
const parsed = JSON.parse(
|
|
43967
|
+
const parsed = JSON.parse(readFileSync50(url, "utf8"));
|
|
43572
43968
|
const byKey = {};
|
|
43573
43969
|
for (const [k, v] of Object.entries(parsed)) {
|
|
43574
43970
|
if (!k.startsWith("//")) byKey[k] = v;
|
|
@@ -43660,8 +44056,8 @@ function writeRecordedMocks(opts) {
|
|
|
43660
44056
|
mkdir: (p) => mkdirSync23(p, { recursive: true }),
|
|
43661
44057
|
write: (p, s) => writeFileSync19(p, s)
|
|
43662
44058
|
};
|
|
43663
|
-
fs.mkdir(
|
|
43664
|
-
fs.write(
|
|
44059
|
+
fs.mkdir(join43(opts.dir, "dev"));
|
|
44060
|
+
fs.write(join43(opts.dir, "dev", "net-mocks.json"), JSON.stringify(opts.mocks, null, 2) + "\n");
|
|
43665
44061
|
return { ok: true, rules, to: "dev/net-mocks.json" };
|
|
43666
44062
|
}
|
|
43667
44063
|
function scopeDescriptors(descriptors, requestedIds, invalidScreens) {
|
|
@@ -43975,12 +44371,12 @@ async function runCrawl(opts) {
|
|
|
43975
44371
|
};
|
|
43976
44372
|
}
|
|
43977
44373
|
function describeTransport(net, opts, ran) {
|
|
43978
|
-
const
|
|
43979
|
-
if (net)
|
|
44374
|
+
const layers2 = [];
|
|
44375
|
+
if (net) layers2.push(`mocked (${net.from})`);
|
|
43980
44376
|
const cmsCount = Object.keys(opts.cmsSeed ?? {}).length;
|
|
43981
|
-
if (cmsCount)
|
|
43982
|
-
if (opts.canned?.count)
|
|
43983
|
-
const base =
|
|
44377
|
+
if (cmsCount) layers2.push(`cms (${cmsCount} seeded collection${cmsCount === 1 ? "" : "s"})`);
|
|
44378
|
+
if (opts.canned?.count) layers2.push(`canned (${opts.canned.count} frozen endpoints, ${opts.canned.from} \u2014 exercises code paths, not API-contract truth)`);
|
|
44379
|
+
const base = layers2.length ? layers2.join(" + ") : "offline (no net fixture \u2014 screens are crawled against a rejecting transport, which exercises their failure UI)";
|
|
43984
44380
|
const hostile = ran.hostile ? " + hostile boot passes (empty-lists, all-500)" : "";
|
|
43985
44381
|
const relations = ran.relations ? " + relations" : "";
|
|
43986
44382
|
const deep = ran.deep ? ` + deep chains (depth ${opts.deep})` : "";
|
|
@@ -44118,14 +44514,14 @@ var mobile_ux_lint_exports = {};
|
|
|
44118
44514
|
__export(mobile_ux_lint_exports, {
|
|
44119
44515
|
mobileUxIssues: () => mobileUxIssues
|
|
44120
44516
|
});
|
|
44121
|
-
import { existsSync as
|
|
44122
|
-
import { join as
|
|
44517
|
+
import { existsSync as existsSync47, readFileSync as readFileSync51 } from "node:fs";
|
|
44518
|
+
import { join as join44 } from "node:path";
|
|
44123
44519
|
function mobileUxIssues(dir, strict) {
|
|
44124
|
-
const file =
|
|
44125
|
-
if (!
|
|
44520
|
+
const file = join44(dir, "MOBILE-UX.md");
|
|
44521
|
+
if (!existsSync47(file)) return [];
|
|
44126
44522
|
let text5;
|
|
44127
44523
|
try {
|
|
44128
|
-
text5 =
|
|
44524
|
+
text5 = readFileSync51(file, "utf8");
|
|
44129
44525
|
} catch {
|
|
44130
44526
|
return [];
|
|
44131
44527
|
}
|
|
@@ -45800,8 +46196,8 @@ __export(functions_exports, {
|
|
|
45800
46196
|
resolveFunctionsTarget: () => resolveFunctionsTarget,
|
|
45801
46197
|
runRemoteFunctionOperation: () => runRemoteFunctionOperation
|
|
45802
46198
|
});
|
|
45803
|
-
import { readFileSync as
|
|
45804
|
-
import { join as
|
|
46199
|
+
import { readFileSync as readFileSync52, existsSync as existsSync48 } from "node:fs";
|
|
46200
|
+
import { join as join45, resolve as resolve41 } from "node:path";
|
|
45805
46201
|
function resolveFunctionsTarget(input) {
|
|
45806
46202
|
const explicitUrl = input.functionsUrl?.trim();
|
|
45807
46203
|
if (explicitUrl) return { mode: "remote", baseUrl: explicitUrl };
|
|
@@ -45820,9 +46216,9 @@ async function loadFunctionsApp(dir) {
|
|
|
45820
46216
|
}
|
|
45821
46217
|
const sources = {};
|
|
45822
46218
|
for (const definition of config.functions.functions) {
|
|
45823
|
-
const source = [".ts", ".js", ".mts", ".mjs"].map((extension) =>
|
|
46219
|
+
const source = [".ts", ".js", ".mts", ".mjs"].map((extension) => join45(loaded.dir, "functions", `${definition.name}${extension}`)).find(existsSync48);
|
|
45824
46220
|
if (!source) throw new Error(`missing source for function ${definition.name}; expected functions/${definition.name}.ts`);
|
|
45825
|
-
sources[definition.name] =
|
|
46221
|
+
sources[definition.name] = readFileSync52(source, "utf8");
|
|
45826
46222
|
}
|
|
45827
46223
|
const data = config.cms || config.data ? mergeDataResources(config) : void 0;
|
|
45828
46224
|
const dataErrors = validateDataResources(data, loaded.name).filter((issue2) => issue2.severity === "error");
|
|
@@ -45974,14 +46370,14 @@ __export(studio_reel_exports, {
|
|
|
45974
46370
|
utcDay: () => utcDay
|
|
45975
46371
|
});
|
|
45976
46372
|
import { createHash as createHash24 } from "node:crypto";
|
|
45977
|
-
import { lstatSync as lstatSync7, readFileSync as
|
|
45978
|
-
import { basename as basename11, join as
|
|
46373
|
+
import { lstatSync as lstatSync7, readFileSync as readFileSync53 } from "node:fs";
|
|
46374
|
+
import { basename as basename11, join as join46 } from "node:path";
|
|
45979
46375
|
function loadMemory2(dir) {
|
|
45980
|
-
const m = readJson4(
|
|
45981
|
-
if (!
|
|
46376
|
+
const m = readJson4(join46(dir, ".himi", "studio", "memory.json"));
|
|
46377
|
+
if (!isObj2(m) || m.version !== 1 || !isObj2(m.shots) || !Array.isArray(m.timeline)) return null;
|
|
45982
46378
|
const shots = [];
|
|
45983
46379
|
for (const [id, s] of Object.entries(m.shots)) {
|
|
45984
|
-
if (!
|
|
46380
|
+
if (!isObj2(s)) continue;
|
|
45985
46381
|
const file = historyName(s.sha, s.ext);
|
|
45986
46382
|
const firstSeen = str(s.firstSeen);
|
|
45987
46383
|
if (!file || !firstSeen) continue;
|
|
@@ -45990,7 +46386,7 @@ function loadMemory2(dir) {
|
|
|
45990
46386
|
}
|
|
45991
46387
|
const timeline = [];
|
|
45992
46388
|
for (const t of m.timeline) {
|
|
45993
|
-
if (!
|
|
46389
|
+
if (!isObj2(t)) continue;
|
|
45994
46390
|
const file = historyName(t.sha, t.ext);
|
|
45995
46391
|
const ts2 = str(t.ts);
|
|
45996
46392
|
const id = str(t.id);
|
|
@@ -46014,8 +46410,8 @@ function planReel(dir) {
|
|
|
46014
46410
|
const memory = loadMemory2(dir);
|
|
46015
46411
|
const { entries } = readProgress(dir);
|
|
46016
46412
|
const summary = summarizeProgress(entries);
|
|
46017
|
-
const manifest = readJson4(
|
|
46018
|
-
const tokens = readJson4(
|
|
46413
|
+
const manifest = readJson4(join46(dir, "himalaya.content.json"));
|
|
46414
|
+
const tokens = readJson4(join46(dir, "tokens.json"));
|
|
46019
46415
|
const accentToken = tokens?.colors?.accentPrimary;
|
|
46020
46416
|
const accentRaw = typeof accentToken === "string" ? accentToken : accentToken?.light;
|
|
46021
46417
|
const accent = typeof accentRaw === "string" && ACCENT.test(accentRaw) ? accentRaw : DEFAULT_ACCENT;
|
|
@@ -46030,7 +46426,7 @@ function planReel(dir) {
|
|
|
46030
46426
|
ts: e.ts,
|
|
46031
46427
|
message: e.message,
|
|
46032
46428
|
step: str(e.step),
|
|
46033
|
-
files: (Array.isArray(e.images) ? e.images : []).map((i) =>
|
|
46429
|
+
files: (Array.isArray(e.images) ? e.images : []).map((i) => isObj2(i) && typeof i.file === "string" ? basename11(i.file) : "").filter((f) => HISTORY_NAME.test(f))
|
|
46034
46430
|
}));
|
|
46035
46431
|
const times = [summary.startedAt, ...timeline.map((t) => t.ts), memory?.createdAt].filter((x) => !!x).sort();
|
|
46036
46432
|
const startedAt = times[0] ?? null;
|
|
@@ -46057,10 +46453,10 @@ function inlineImages(dir, plan, budget = REEL_BUDGET_BYTES) {
|
|
|
46057
46453
|
const verified = (f) => {
|
|
46058
46454
|
if (!HISTORY_NAME.test(f)) return null;
|
|
46059
46455
|
try {
|
|
46060
|
-
const path2 =
|
|
46456
|
+
const path2 = join46(dir, HISTORY_DIR, f);
|
|
46061
46457
|
const st = lstatSync7(path2);
|
|
46062
46458
|
if (!st.isFile() || st.nlink !== 1) return null;
|
|
46063
|
-
const bytes2 =
|
|
46459
|
+
const bytes2 = readFileSync53(path2);
|
|
46064
46460
|
return createHash24("sha256").update(bytes2).digest("hex") === f.slice(0, 64) && imageExtension(bytes2) === f.slice(65) ? bytes2 : null;
|
|
46065
46461
|
} catch {
|
|
46066
46462
|
return null;
|
|
@@ -46180,7 +46576,7 @@ function buildReel(dir, budget = REEL_BUDGET_BYTES) {
|
|
|
46180
46576
|
const { plan, images } = inlineImages(dir, planReel(dir), budget);
|
|
46181
46577
|
return { html: renderReel(plan, images), plan };
|
|
46182
46578
|
}
|
|
46183
|
-
var REEL_BUDGET_BYTES, MAX_FLIP_FRAMES, DEFAULT_ACCENT, ACCENT, HISTORY_NAME, MIME2, mimeOf, readJson4,
|
|
46579
|
+
var REEL_BUDGET_BYTES, MAX_FLIP_FRAMES, DEFAULT_ACCENT, ACCENT, HISTORY_NAME, MIME2, mimeOf, readJson4, isObj2, str, historyName, cited;
|
|
46184
46580
|
var init_studio_reel = __esm({
|
|
46185
46581
|
"src/studio-reel.ts"() {
|
|
46186
46582
|
init_progress();
|
|
@@ -46194,12 +46590,12 @@ var init_studio_reel = __esm({
|
|
|
46194
46590
|
mimeOf = (file) => MIME2[file.slice(65)] ?? "image/png";
|
|
46195
46591
|
readJson4 = (file) => {
|
|
46196
46592
|
try {
|
|
46197
|
-
return JSON.parse(
|
|
46593
|
+
return JSON.parse(readFileSync53(file, "utf8"));
|
|
46198
46594
|
} catch {
|
|
46199
46595
|
return null;
|
|
46200
46596
|
}
|
|
46201
46597
|
};
|
|
46202
|
-
|
|
46598
|
+
isObj2 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
46203
46599
|
str = (v) => typeof v === "string" && v ? v : null;
|
|
46204
46600
|
historyName = (sha, ext) => typeof sha === "string" && typeof ext === "string" && HISTORY_NAME.test(`${sha}.${ext}`) ? `${sha}.${ext}` : null;
|
|
46205
46601
|
cited = (p) => [
|
|
@@ -46225,9 +46621,9 @@ __export(native_decode_exports, {
|
|
|
46225
46621
|
runNativeDecode: () => runNativeDecode
|
|
46226
46622
|
});
|
|
46227
46623
|
import { execFileSync as execFileSync5, spawnSync as spawnSync2 } from "node:child_process";
|
|
46228
|
-
import { existsSync as
|
|
46624
|
+
import { existsSync as existsSync49, mkdtempSync as mkdtempSync2, readFileSync as readFileSync54, rmSync as rmSync11, writeFileSync as writeFileSync20 } from "node:fs";
|
|
46229
46625
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
46230
|
-
import { join as
|
|
46626
|
+
import { join as join47 } from "node:path";
|
|
46231
46627
|
import { fileURLToPath as fileURLToPath20 } from "node:url";
|
|
46232
46628
|
function nativeDecodePackageDir() {
|
|
46233
46629
|
return fileURLToPath20(new URL("../../../core/runtime/ios/HimalayaCore/", import.meta.url));
|
|
@@ -46237,8 +46633,8 @@ function nativeDecodeAndroidHarnessDir() {
|
|
|
46237
46633
|
}
|
|
46238
46634
|
function nativeOracleShipped() {
|
|
46239
46635
|
return {
|
|
46240
|
-
ios:
|
|
46241
|
-
android:
|
|
46636
|
+
ios: existsSync49(join47(nativeDecodePackageDir(), "Package.swift")),
|
|
46637
|
+
android: existsSync49(join47(nativeDecodeAndroidHarnessDir(), "gradlew"))
|
|
46242
46638
|
};
|
|
46243
46639
|
}
|
|
46244
46640
|
function detectNativeDecode(options = {}) {
|
|
@@ -46249,7 +46645,7 @@ function detectNativeDecode(options = {}) {
|
|
|
46249
46645
|
return { platform: "ios", available: false, reason: `the iOS decoder oracle requires macOS (darwin); this host is ${hostPlatform}` };
|
|
46250
46646
|
}
|
|
46251
46647
|
if (!swiftAvailable) return { platform: "ios", available: false, reason: "swift is not on PATH" };
|
|
46252
|
-
const packageAvailable = options.packageAvailable ??
|
|
46648
|
+
const packageAvailable = options.packageAvailable ?? existsSync49(join47(packageDir, "Package.swift"));
|
|
46253
46649
|
if (!packageAvailable) {
|
|
46254
46650
|
return {
|
|
46255
46651
|
platform: "ios",
|
|
@@ -46261,7 +46657,7 @@ function detectNativeDecode(options = {}) {
|
|
|
46261
46657
|
}
|
|
46262
46658
|
function localPropertiesSdk(harnessDir) {
|
|
46263
46659
|
try {
|
|
46264
|
-
const match =
|
|
46660
|
+
const match = readFileSync54(join47(harnessDir, "local.properties"), "utf8").match(/^sdk\.dir\s*=\s*(.+)$/m);
|
|
46265
46661
|
return match?.[1]?.trim().replace(/\\([ :\\])/g, "$1") ?? null;
|
|
46266
46662
|
} catch {
|
|
46267
46663
|
return null;
|
|
@@ -46269,8 +46665,8 @@ function localPropertiesSdk(harnessDir) {
|
|
|
46269
46665
|
}
|
|
46270
46666
|
function detectAndroidNativeDecode(options = {}) {
|
|
46271
46667
|
const harnessDir = options.harnessDir ?? nativeDecodeAndroidHarnessDir();
|
|
46272
|
-
const gradlew =
|
|
46273
|
-
const gradlewAvailable = options.gradlewAvailable ??
|
|
46668
|
+
const gradlew = join47(harnessDir, "gradlew");
|
|
46669
|
+
const gradlewAvailable = options.gradlewAvailable ?? existsSync49(gradlew);
|
|
46274
46670
|
if (!gradlewAvailable) {
|
|
46275
46671
|
return {
|
|
46276
46672
|
platform: "android",
|
|
@@ -46280,7 +46676,7 @@ function detectAndroidNativeDecode(options = {}) {
|
|
|
46280
46676
|
}
|
|
46281
46677
|
const androidHome = options.androidHome ?? process.env.ANDROID_HOME ?? "";
|
|
46282
46678
|
const sdk = androidHome.trim() || (options.localPropertiesSdk !== void 0 ? options.localPropertiesSdk : localPropertiesSdk(harnessDir));
|
|
46283
|
-
const sdkAvailable = options.sdkAvailable ?? (typeof sdk === "string" && sdk.length > 0 &&
|
|
46679
|
+
const sdkAvailable = options.sdkAvailable ?? (typeof sdk === "string" && sdk.length > 0 && existsSync49(sdk));
|
|
46284
46680
|
if (!sdkAvailable) {
|
|
46285
46681
|
return {
|
|
46286
46682
|
platform: "android",
|
|
@@ -46352,14 +46748,14 @@ function parseNativeDecodeOutput(stdout, expectedScreenIds, platform = "ios") {
|
|
|
46352
46748
|
return verdicts;
|
|
46353
46749
|
}
|
|
46354
46750
|
function runNativeDecode(options) {
|
|
46355
|
-
const descriptorDir = mkdtempSync2(
|
|
46751
|
+
const descriptorDir = mkdtempSync2(join47(tmpdir3(), "himi-native-decode-"));
|
|
46356
46752
|
const startedAt = Date.now();
|
|
46357
46753
|
try {
|
|
46358
46754
|
for (const descriptor of options.descriptors) {
|
|
46359
46755
|
if (typeof descriptor.descriptorJson !== "string") {
|
|
46360
46756
|
throw new Error(`native decode cannot judge ${descriptor.screenId}: the release builder did not return its exact baked JSON bytes`);
|
|
46361
46757
|
}
|
|
46362
|
-
writeFileSync20(
|
|
46758
|
+
writeFileSync20(join47(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
|
|
46363
46759
|
}
|
|
46364
46760
|
options.progress?.("building cached Swift oracle");
|
|
46365
46761
|
execFileSync5("swift", ["build", "--package-path", options.packageDir, "--product", "himi-decode-oracle"], {
|
|
@@ -46371,7 +46767,7 @@ function runNativeDecode(options) {
|
|
|
46371
46767
|
encoding: "utf8"
|
|
46372
46768
|
}).trim();
|
|
46373
46769
|
options.progress?.(`running real Swift decoder over ${options.descriptors.length} screen${options.descriptors.length === 1 ? "" : "s"}`);
|
|
46374
|
-
const stdout = execFileSync5(
|
|
46770
|
+
const stdout = execFileSync5(join47(binPath, "himi-decode-oracle"), ["--dir", descriptorDir], {
|
|
46375
46771
|
stdio: ["ignore", "pipe", "pipe"],
|
|
46376
46772
|
encoding: "utf8"
|
|
46377
46773
|
});
|
|
@@ -46389,15 +46785,15 @@ function runNativeDecode(options) {
|
|
|
46389
46785
|
}
|
|
46390
46786
|
}
|
|
46391
46787
|
function runAndroidNativeDecode(options) {
|
|
46392
|
-
const descriptorDir = mkdtempSync2(
|
|
46393
|
-
const outputPath =
|
|
46788
|
+
const descriptorDir = mkdtempSync2(join47(tmpdir3(), "himi-native-decode-android-"));
|
|
46789
|
+
const outputPath = join47(descriptorDir, "verdicts.ndjson");
|
|
46394
46790
|
const startedAt = Date.now();
|
|
46395
46791
|
try {
|
|
46396
46792
|
for (const descriptor of options.descriptors) {
|
|
46397
46793
|
if (typeof descriptor.descriptorJson !== "string") {
|
|
46398
46794
|
throw new Error(`native decode cannot judge ${descriptor.screenId}: the release builder did not return its exact baked JSON bytes`);
|
|
46399
46795
|
}
|
|
46400
|
-
writeFileSync20(
|
|
46796
|
+
writeFileSync20(join47(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
|
|
46401
46797
|
}
|
|
46402
46798
|
options.progress?.(`running real Kotlin decoder over ${options.descriptors.length} screen${options.descriptors.length === 1 ? "" : "s"}`);
|
|
46403
46799
|
execFileSync5(options.gradlew, [
|
|
@@ -46412,7 +46808,7 @@ function runAndroidNativeDecode(options) {
|
|
|
46412
46808
|
stdio: ["ignore", "ignore", "pipe"],
|
|
46413
46809
|
encoding: "utf8"
|
|
46414
46810
|
});
|
|
46415
|
-
const stdout =
|
|
46811
|
+
const stdout = readFileSync54(outputPath, "utf8");
|
|
46416
46812
|
return {
|
|
46417
46813
|
platform: "android",
|
|
46418
46814
|
verdicts: parseNativeDecodeOutput(stdout, options.descriptors.map((descriptor) => descriptor.screenId), "android"),
|
|
@@ -46482,13 +46878,13 @@ __export(browser_authoring_exports, {
|
|
|
46482
46878
|
});
|
|
46483
46879
|
import { createServer as createServer3 } from "node:http";
|
|
46484
46880
|
import { createHash as createHash25, randomBytes as randomBytes4 } from "node:crypto";
|
|
46485
|
-
import { existsSync as
|
|
46486
|
-
import { join as
|
|
46881
|
+
import { existsSync as existsSync50, readdirSync as readdirSync24, readFileSync as readFileSync55, realpathSync as realpathSync5, statSync as statSync12 } from "node:fs";
|
|
46882
|
+
import { join as join48, posix, relative as relative8, sep as sep12 } from "node:path";
|
|
46487
46883
|
function humanMs(ms) {
|
|
46488
46884
|
return ms < 1e3 ? `${ms}ms` : `${Math.round(ms / 1e3)}s`;
|
|
46489
46885
|
}
|
|
46490
46886
|
function collectWorkerSources(tier5SrcDir, bundleName) {
|
|
46491
|
-
const root =
|
|
46887
|
+
const root = join48(tier5SrcDir, bundleName);
|
|
46492
46888
|
const files = {};
|
|
46493
46889
|
const visitedDirs = /* @__PURE__ */ new Set();
|
|
46494
46890
|
const walk2 = (abs, rel) => {
|
|
@@ -46496,16 +46892,16 @@ function collectWorkerSources(tier5SrcDir, bundleName) {
|
|
|
46496
46892
|
if (visitedDirs.has(real)) return;
|
|
46497
46893
|
visitedDirs.add(real);
|
|
46498
46894
|
for (const name of readdirSync24(abs).sort()) {
|
|
46499
|
-
const childAbs =
|
|
46895
|
+
const childAbs = join48(abs, name);
|
|
46500
46896
|
const childRel = posix.join(rel, name);
|
|
46501
46897
|
if (statSync12(childAbs).isDirectory()) {
|
|
46502
46898
|
walk2(childAbs, childRel);
|
|
46503
46899
|
} else if (/\.(ts|tsx|js|mjs|json)$/.test(name)) {
|
|
46504
|
-
files[childRel] =
|
|
46900
|
+
files[childRel] = readFileSync55(childAbs, "utf8");
|
|
46505
46901
|
}
|
|
46506
46902
|
}
|
|
46507
46903
|
};
|
|
46508
|
-
if (!
|
|
46904
|
+
if (!existsSync50(root)) return null;
|
|
46509
46905
|
walk2(root, `/tier5-src/${bundleName}`);
|
|
46510
46906
|
const entry = [`/tier5-src/${bundleName}/index.ts`, `/tier5-src/${bundleName}/index.js`].find((p) => p in files);
|
|
46511
46907
|
if (!entry) return null;
|
|
@@ -46522,20 +46918,20 @@ function collectRelativeSiblings(files, tier5SrcDir) {
|
|
|
46522
46918
|
const spec = m[1];
|
|
46523
46919
|
const virtual = posix.normalize(posix.join(dir, spec));
|
|
46524
46920
|
if (!virtual.startsWith("/tier5-src/")) continue;
|
|
46525
|
-
const onDisk =
|
|
46921
|
+
const onDisk = join48(tier5SrcDir, virtual.slice("/tier5-src/".length));
|
|
46526
46922
|
const candidates = [
|
|
46527
46923
|
onDisk,
|
|
46528
46924
|
`${onDisk}.ts`,
|
|
46529
46925
|
`${onDisk}.js`,
|
|
46530
46926
|
onDisk.replace(/\.js$/, ".ts"),
|
|
46531
|
-
|
|
46532
|
-
|
|
46927
|
+
join48(onDisk, "index.ts"),
|
|
46928
|
+
join48(onDisk, "index.js")
|
|
46533
46929
|
];
|
|
46534
46930
|
for (const abs of candidates) {
|
|
46535
|
-
if (!
|
|
46931
|
+
if (!existsSync50(abs) || statSync12(abs).isDirectory()) continue;
|
|
46536
46932
|
const key2 = `/tier5-src/${relative8(tier5SrcDir, abs).split(sep12).join(posix.sep)}`;
|
|
46537
46933
|
if (key2 in files) break;
|
|
46538
|
-
files[key2] =
|
|
46934
|
+
files[key2] = readFileSync55(abs, "utf8");
|
|
46539
46935
|
queue.push(key2);
|
|
46540
46936
|
break;
|
|
46541
46937
|
}
|
|
@@ -46570,7 +46966,7 @@ function collectSdkModules(files, resolveSubpath) {
|
|
|
46570
46966
|
function sdkSubpathReader(resolve48) {
|
|
46571
46967
|
return (sub) => {
|
|
46572
46968
|
try {
|
|
46573
|
-
return
|
|
46969
|
+
return readFileSync55(resolve48(`@wix/himalaya/${sub}`), "utf8");
|
|
46574
46970
|
} catch {
|
|
46575
46971
|
return null;
|
|
46576
46972
|
}
|
|
@@ -46742,8 +47138,8 @@ __export(coverage_exports, {
|
|
|
46742
47138
|
suppressedNativeKeys: () => suppressedNativeKeys,
|
|
46743
47139
|
trendAndStore: () => trendAndStore
|
|
46744
47140
|
});
|
|
46745
|
-
import { existsSync as
|
|
46746
|
-
import { dirname as dirname26, join as
|
|
47141
|
+
import { existsSync as existsSync51, mkdirSync as mkdirSync24, readFileSync as readFileSync56, writeFileSync as writeFileSync21 } from "node:fs";
|
|
47142
|
+
import { dirname as dirname26, join as join49 } from "node:path";
|
|
46747
47143
|
function suppressedNativeKeys(oracle) {
|
|
46748
47144
|
return [...oracle.ios ? [] : ["native-decode|ios"], ...oracle.android ? [] : ["native-decode|android"]];
|
|
46749
47145
|
}
|
|
@@ -46923,11 +47319,11 @@ function assembleLedger(r, options = {}) {
|
|
|
46923
47319
|
return out;
|
|
46924
47320
|
}
|
|
46925
47321
|
function trendAndStore(dir, entries, suppressed) {
|
|
46926
|
-
const p =
|
|
47322
|
+
const p = join49(dir, LEDGER_FILE);
|
|
46927
47323
|
let previous = null;
|
|
46928
47324
|
try {
|
|
46929
|
-
if (
|
|
46930
|
-
const parsed = JSON.parse(
|
|
47325
|
+
if (existsSync51(p)) {
|
|
47326
|
+
const parsed = JSON.parse(readFileSync56(p, "utf8"));
|
|
46931
47327
|
if (Array.isArray(parsed.keys)) previous = parsed.keys.filter((k) => typeof k === "string");
|
|
46932
47328
|
}
|
|
46933
47329
|
} catch {
|
|
@@ -46966,11 +47362,11 @@ function formatLedger(entries, trend) {
|
|
|
46966
47362
|
return out.join("\n");
|
|
46967
47363
|
}
|
|
46968
47364
|
function diffAndStoreObservations(dir, current) {
|
|
46969
|
-
const p =
|
|
47365
|
+
const p = join49(dir, OBS_FILE);
|
|
46970
47366
|
let previous = null;
|
|
46971
47367
|
try {
|
|
46972
|
-
if (
|
|
46973
|
-
const parsed = JSON.parse(
|
|
47368
|
+
if (existsSync51(p)) {
|
|
47369
|
+
const parsed = JSON.parse(readFileSync56(p, "utf8"));
|
|
46974
47370
|
if (parsed.screens && typeof parsed.screens === "object" && !Array.isArray(parsed.screens) && Object.values(parsed.screens).every(
|
|
46975
47371
|
(v) => Array.isArray(v) && v.every((l) => typeof l === "string")
|
|
46976
47372
|
)) {
|
|
@@ -47019,8 +47415,8 @@ var LEDGER_FILE, OBS_FILE;
|
|
|
47019
47415
|
var init_coverage = __esm({
|
|
47020
47416
|
"src/coverage.ts"() {
|
|
47021
47417
|
init_native_decode();
|
|
47022
|
-
LEDGER_FILE =
|
|
47023
|
-
OBS_FILE =
|
|
47418
|
+
LEDGER_FILE = join49(".himi", "test-ledger.json");
|
|
47419
|
+
OBS_FILE = join49(".himi", "test-observations.json");
|
|
47024
47420
|
}
|
|
47025
47421
|
});
|
|
47026
47422
|
|
|
@@ -47031,11 +47427,11 @@ __export(design_kits_exports, {
|
|
|
47031
47427
|
kitsDir: () => kitsDir,
|
|
47032
47428
|
listKits: () => listKits2
|
|
47033
47429
|
});
|
|
47034
|
-
import { existsSync as
|
|
47035
|
-
import { join as
|
|
47430
|
+
import { existsSync as existsSync52, readFileSync as readFileSync57, readdirSync as readdirSync25 } from "node:fs";
|
|
47431
|
+
import { join as join50, basename as basename12 } from "node:path";
|
|
47036
47432
|
import { fileURLToPath as fileURLToPath21 } from "node:url";
|
|
47037
47433
|
function kitsDir() {
|
|
47038
|
-
return KIT_DIR_CANDIDATES.find((p) =>
|
|
47434
|
+
return KIT_DIR_CANDIDATES.find((p) => existsSync52(p));
|
|
47039
47435
|
}
|
|
47040
47436
|
function listKits2() {
|
|
47041
47437
|
const dir = kitsDir();
|
|
@@ -47059,7 +47455,7 @@ In a published @wix/himalaya-cli this is a packaging bug \u2014 the kits should
|
|
|
47059
47455
|
if (!kits.includes(name)) {
|
|
47060
47456
|
return { ok: false, kit: name, kits, problems: [`no design kit named "${name}". Available: ${kits.join(", ")}`] };
|
|
47061
47457
|
}
|
|
47062
|
-
const raw =
|
|
47458
|
+
const raw = readFileSync57(join50(dir, `${name}.json`), "utf8");
|
|
47063
47459
|
let parsed;
|
|
47064
47460
|
try {
|
|
47065
47461
|
parsed = JSON.parse(raw);
|
|
@@ -47083,9 +47479,9 @@ var init_design_kits = __esm({
|
|
|
47083
47479
|
"src/design-kits.ts"() {
|
|
47084
47480
|
KIT_DIR_CANDIDATES = [
|
|
47085
47481
|
// in-repo: tools/himi-cli/src/design-kits.ts → <repo>/stdlib/design-kits/
|
|
47086
|
-
|
|
47482
|
+
join50(fileURLToPath21(new URL("../../..", import.meta.url)), "stdlib", "design-kits"),
|
|
47087
47483
|
// published CLI: <pkg>/dist/cli.mjs → <pkg>/stdlib/design-kits/
|
|
47088
|
-
|
|
47484
|
+
join50(fileURLToPath21(new URL("..", import.meta.url)), "stdlib", "design-kits")
|
|
47089
47485
|
];
|
|
47090
47486
|
}
|
|
47091
47487
|
});
|
|
@@ -47099,11 +47495,11 @@ __export(assets_exports, {
|
|
|
47099
47495
|
removeAssetPayload: () => removeAssetPayload,
|
|
47100
47496
|
verifyReport: () => verifyReport
|
|
47101
47497
|
});
|
|
47102
|
-
import { readFileSync as
|
|
47498
|
+
import { readFileSync as readFileSync58 } from "node:fs";
|
|
47103
47499
|
import { basename as basename13 } from "node:path";
|
|
47104
47500
|
function declaredAssets(dir) {
|
|
47105
47501
|
return collectAssets(dir).map((a) => {
|
|
47106
|
-
const bytes2 =
|
|
47502
|
+
const bytes2 = readFileSync58(a.path);
|
|
47107
47503
|
return {
|
|
47108
47504
|
name: a.name,
|
|
47109
47505
|
sha256: assetSha256(bytes2),
|
|
@@ -47180,7 +47576,7 @@ function verifyReport(dir, app, manifest) {
|
|
|
47180
47576
|
};
|
|
47181
47577
|
}
|
|
47182
47578
|
function addAssetPayload(manifest, filePath, opts) {
|
|
47183
|
-
const bytes2 =
|
|
47579
|
+
const bytes2 = readFileSync58(filePath);
|
|
47184
47580
|
const name = opts.name ?? basename13(filePath);
|
|
47185
47581
|
const sha2565 = assetSha256(bytes2);
|
|
47186
47582
|
const record2 = {
|
|
@@ -48782,21 +49178,21 @@ var init_preview_assets_generated = __esm({
|
|
|
48782
49178
|
"../../packages/serve/src/preview-assets.generated.ts"() {
|
|
48783
49179
|
init_preview_assets_format();
|
|
48784
49180
|
PREVIEW_ASSET_MANIFEST = [
|
|
48785
|
-
{ key: "assets/index-
|
|
48786
|
-
{ key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset:
|
|
48787
|
-
{ key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset:
|
|
48788
|
-
{ key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset:
|
|
48789
|
-
{ key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset:
|
|
48790
|
-
{ key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset:
|
|
48791
|
-
{ key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset:
|
|
48792
|
-
{ key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset:
|
|
48793
|
-
{ key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset:
|
|
48794
|
-
{ key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset:
|
|
48795
|
-
{ key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset:
|
|
48796
|
-
{ key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset:
|
|
48797
|
-
{ key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset:
|
|
48798
|
-
{ key: "index.html", contentType: "text/html; charset=utf-8", offset:
|
|
48799
|
-
{ key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset:
|
|
49181
|
+
{ key: "assets/index-BvsDhZYW.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1043409, sha256: "98882914dcb360867c5f265e3d6542774f18c0b0c8f18813b66b304a122c1b01" },
|
|
49182
|
+
{ key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset: 1043417, length: 4610, sha256: "994062dd7af4186a739de55dd9e151c63b6301f8e2cbafc608d35c2e87da0cd2" },
|
|
49183
|
+
{ key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset: 1048027, length: 488584, sha256: "d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134" },
|
|
49184
|
+
{ key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 1536611, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
|
|
49185
|
+
{ key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1627535, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
|
|
49186
|
+
{ key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1718519, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
|
|
49187
|
+
{ key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1809499, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
|
|
49188
|
+
{ key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1900371, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
|
|
49189
|
+
{ key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 1991351, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
|
|
49190
|
+
{ key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 2099987, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
|
|
49191
|
+
{ key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 2209071, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
|
|
49192
|
+
{ key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 2318119, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
|
|
49193
|
+
{ key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 2425819, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
|
|
49194
|
+
{ key: "index.html", contentType: "text/html; charset=utf-8", offset: 2513927, length: 4947, sha256: "3dd02534fef5e0c2bb40b6c6a6c994641728fde306921e66ffab3e9a7dfa6bbe" },
|
|
49195
|
+
{ key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 2518874, length: 17209, sha256: "dffc9718e2faa63ae2cc919e0a842f585ed565aaaa7c53778e90379442c731b6" }
|
|
48800
49196
|
];
|
|
48801
49197
|
}
|
|
48802
49198
|
});
|
|
@@ -48812,9 +49208,9 @@ __export(run_exports, {
|
|
|
48812
49208
|
runPackage: () => runPackage,
|
|
48813
49209
|
withoutProdServe: () => withoutProdServe
|
|
48814
49210
|
});
|
|
48815
|
-
import { cpSync as cpSync2, existsSync as
|
|
49211
|
+
import { cpSync as cpSync2, existsSync as existsSync53, mkdirSync as mkdirSync25, mkdtempSync as mkdtempSync3, readFileSync as readFileSync59, rmSync as rmSync12, statSync as statSync13 } from "node:fs";
|
|
48816
49212
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
48817
|
-
import { dirname as dirname27, join as
|
|
49213
|
+
import { dirname as dirname27, join as join51 } from "node:path";
|
|
48818
49214
|
import { fileURLToPath as fileURLToPath22 } from "node:url";
|
|
48819
49215
|
function makePackageRunHandler(opts) {
|
|
48820
49216
|
return makeRunHandler({
|
|
@@ -48833,9 +49229,9 @@ async function fetchBytes(url) {
|
|
|
48833
49229
|
}
|
|
48834
49230
|
async function resolvePackage(source, workDir) {
|
|
48835
49231
|
const isUrl2 = /^https?:\/\//i.test(source);
|
|
48836
|
-
if (!isUrl2 &&
|
|
48837
|
-
const appDirManifest =
|
|
48838
|
-
if (
|
|
49232
|
+
if (!isUrl2 && existsSync53(source) && statSync13(source).isDirectory()) {
|
|
49233
|
+
const appDirManifest = join51(source, "release-manifest.json");
|
|
49234
|
+
if (existsSync53(appDirManifest)) {
|
|
48839
49235
|
const opened2 = openPackageDir(source);
|
|
48840
49236
|
if (!opened2.validation.ok) {
|
|
48841
49237
|
throw new Error(`package is not valid:
|
|
@@ -48844,9 +49240,9 @@ async function resolvePackage(source, workDir) {
|
|
|
48844
49240
|
const app2 = opened2.header?.app ?? opened2.manifest?.app;
|
|
48845
49241
|
if (!app2) throw new Error(`${source} has no app id (no himi-package.json and no manifest.app)`);
|
|
48846
49242
|
if (!isSafeAppId(app2)) throw new Error(`${source} declares an unsafe app id ${JSON.stringify(app2)} \u2014 refusing to open it`);
|
|
48847
|
-
const root2 = workDir ?? mkdtempSync3(
|
|
48848
|
-
const target =
|
|
48849
|
-
if (
|
|
49243
|
+
const root2 = workDir ?? mkdtempSync3(join51(tmpdir4(), "himi-run-"));
|
|
49244
|
+
const target = join51(root2, app2);
|
|
49245
|
+
if (join51(source) !== target) {
|
|
48850
49246
|
mkdirSync25(root2, { recursive: true });
|
|
48851
49247
|
rmSync12(target, { recursive: true, force: true });
|
|
48852
49248
|
cpSync2(source, target, { recursive: true });
|
|
@@ -48863,8 +49259,8 @@ async function resolvePackage(source, workDir) {
|
|
|
48863
49259
|
}
|
|
48864
49260
|
throw new Error(`${source} is a directory but has no release-manifest.json \u2014 is it a package?`);
|
|
48865
49261
|
}
|
|
48866
|
-
const bytes2 = isUrl2 ? await fetchBytes(source) :
|
|
48867
|
-
const root = workDir ?? mkdtempSync3(
|
|
49262
|
+
const bytes2 = isUrl2 ? await fetchBytes(source) : readFileSync59(source);
|
|
49263
|
+
const root = workDir ?? mkdtempSync3(join51(tmpdir4(), "himi-run-"));
|
|
48868
49264
|
const { app, appDir: appDir2 } = unpackTo(bytes2, root);
|
|
48869
49265
|
const opened = openPackageDir(appDir2);
|
|
48870
49266
|
if (!opened.validation.ok) {
|
|
@@ -48887,14 +49283,14 @@ async function loadPreviewAssets() {
|
|
|
48887
49283
|
const mod = await Promise.resolve().then(() => (init_preview_assets_generated(), preview_assets_generated_exports));
|
|
48888
49284
|
const here = dirname27(fileURLToPath22(import.meta.url));
|
|
48889
49285
|
const candidates = [
|
|
48890
|
-
|
|
49286
|
+
join51(here, "preview-assets.generated.bin"),
|
|
48891
49287
|
// published: copied next to the bundled CLI
|
|
48892
|
-
|
|
49288
|
+
join51(here, "../../../packages/serve/src/preview-assets.generated.bin")
|
|
48893
49289
|
// in-repo checkout
|
|
48894
49290
|
];
|
|
48895
49291
|
for (const path2 of candidates) {
|
|
48896
|
-
if (!
|
|
48897
|
-
const blob =
|
|
49292
|
+
if (!existsSync53(path2)) continue;
|
|
49293
|
+
const blob = readFileSync59(path2);
|
|
48898
49294
|
return mod.assemblePreviewAssetsFromBlob(new Uint8Array(blob.buffer, blob.byteOffset, blob.byteLength));
|
|
48899
49295
|
}
|
|
48900
49296
|
return /* @__PURE__ */ new Map();
|
|
@@ -48989,9 +49385,9 @@ __export(run_watch_exports, {
|
|
|
48989
49385
|
watchedContentDir: () => watchedContentDir,
|
|
48990
49386
|
writeRunRecord: () => writeRunRecord
|
|
48991
49387
|
});
|
|
48992
|
-
import { closeSync as closeSync2, constants, existsSync as
|
|
49388
|
+
import { closeSync as closeSync2, constants, existsSync as existsSync54, fstatSync, lstatSync as lstatSync8, statSync as statSync14, mkdirSync as mkdirSync26, openSync as openSync2, readFileSync as readFileSync60, realpathSync as realpathSync6, renameSync as renameSync5, rmSync as rmSync13, writeFileSync as writeFileSync22, watch as fsWatch } from "node:fs";
|
|
48993
49389
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
48994
|
-
import { extname as extname4, join as
|
|
49390
|
+
import { extname as extname4, join as join52, resolve as resolve42, sep as sep13 } from "node:path";
|
|
48995
49391
|
function diffReleases(prev, next) {
|
|
48996
49392
|
const bundles = Object.keys(next.bundles).filter((b) => prev.bundles[b]?.sha256 !== next.bundles[b].sha256).sort();
|
|
48997
49393
|
const changedBundles = new Set(bundles);
|
|
@@ -49030,8 +49426,8 @@ function watchContent(dir, onChange, opts = {}) {
|
|
|
49030
49426
|
const watch2 = opts.watch ?? ((p, o, l) => fsWatch(p, o, (event, file) => l(event, file === null ? null : String(file))));
|
|
49031
49427
|
let timer = null;
|
|
49032
49428
|
const pending = /* @__PURE__ */ new Set();
|
|
49033
|
-
const
|
|
49034
|
-
if (!file || ignoredChange(file, (rel) => isDir(
|
|
49429
|
+
const watcher2 = watch2(dir, { recursive: true }, (_event, file) => {
|
|
49430
|
+
if (!file || ignoredChange(file, (rel) => isDir(join52(dir, rel)))) return;
|
|
49035
49431
|
pending.add(file);
|
|
49036
49432
|
if (timer) clearTimeout(timer);
|
|
49037
49433
|
timer = setTimeout(() => {
|
|
@@ -49044,7 +49440,7 @@ function watchContent(dir, onChange, opts = {}) {
|
|
|
49044
49440
|
return {
|
|
49045
49441
|
close() {
|
|
49046
49442
|
if (timer) clearTimeout(timer);
|
|
49047
|
-
|
|
49443
|
+
watcher2.close();
|
|
49048
49444
|
}
|
|
49049
49445
|
};
|
|
49050
49446
|
}
|
|
@@ -49052,7 +49448,7 @@ function watchedContentDir(source) {
|
|
|
49052
49448
|
if (!source || /^https?:\/\//i.test(source)) return null;
|
|
49053
49449
|
const dir = resolve42(source);
|
|
49054
49450
|
try {
|
|
49055
|
-
return statSync14(dir).isDirectory() &&
|
|
49451
|
+
return statSync14(dir).isDirectory() && existsSync54(join52(dir, "himalaya.content.json")) ? dir : null;
|
|
49056
49452
|
} catch {
|
|
49057
49453
|
return null;
|
|
49058
49454
|
}
|
|
@@ -49109,7 +49505,7 @@ function serialize(task) {
|
|
|
49109
49505
|
});
|
|
49110
49506
|
}
|
|
49111
49507
|
function himiDir(dir) {
|
|
49112
|
-
const root =
|
|
49508
|
+
const root = join52(dir, ".himi");
|
|
49113
49509
|
try {
|
|
49114
49510
|
return lstatSync8(root).isDirectory() ? root : null;
|
|
49115
49511
|
} catch (e) {
|
|
@@ -49121,11 +49517,11 @@ function himiDir(dir) {
|
|
|
49121
49517
|
function writeRunRecord(dir, record2) {
|
|
49122
49518
|
const root = himiDir(dir);
|
|
49123
49519
|
if (!root) return false;
|
|
49124
|
-
const tmp =
|
|
49520
|
+
const tmp = join52(root, `.run.json.${process.pid}.${randomUUID3()}.tmp`);
|
|
49125
49521
|
try {
|
|
49126
49522
|
writeFileSync22(tmp, `${JSON.stringify(record2, null, 2)}
|
|
49127
49523
|
`, { flag: "wx" });
|
|
49128
|
-
renameSync5(tmp,
|
|
49524
|
+
renameSync5(tmp, join52(root, "run.json"));
|
|
49129
49525
|
} catch (e) {
|
|
49130
49526
|
rmSync13(tmp, { force: true });
|
|
49131
49527
|
throw e;
|
|
@@ -49133,7 +49529,7 @@ function writeRunRecord(dir, record2) {
|
|
|
49133
49529
|
return true;
|
|
49134
49530
|
}
|
|
49135
49531
|
function removeRunRecord(dir, owner) {
|
|
49136
|
-
const root =
|
|
49532
|
+
const root = join52(dir, ".himi");
|
|
49137
49533
|
try {
|
|
49138
49534
|
if (!lstatSync8(root).isDirectory()) return;
|
|
49139
49535
|
} catch {
|
|
@@ -49148,15 +49544,16 @@ function removeRunRecord(dir, owner) {
|
|
|
49148
49544
|
}
|
|
49149
49545
|
if (typeof pid === "number" && pid !== owner) return;
|
|
49150
49546
|
}
|
|
49151
|
-
rmSync13(
|
|
49547
|
+
rmSync13(join52(root, "run.json"), { force: true });
|
|
49152
49548
|
}
|
|
49153
49549
|
function boardFile(dir, pathname) {
|
|
49154
49550
|
let rel = null;
|
|
49155
|
-
if (pathname === "/__himi/studio/" || pathname === "/__himi/studio/index.html") rel =
|
|
49156
|
-
else if (pathname === "/__himi/studio/state.js") rel =
|
|
49551
|
+
if (pathname === "/__himi/studio/" || pathname === "/__himi/studio/index.html") rel = join52("studio", "index.html");
|
|
49552
|
+
else if (pathname === "/__himi/studio/state.js") rel = join52("studio", "state.js");
|
|
49553
|
+
else if (pathname === "/__himi/studio/timeline.js") rel = join52("studio", "timeline.js");
|
|
49157
49554
|
else {
|
|
49158
49555
|
const m = /^\/__himi\/history\/([0-9a-f]{64}\.(png|jpg|gif|webp))$/.exec(pathname);
|
|
49159
|
-
if (m) rel =
|
|
49556
|
+
if (m) rel = join52("history", m[1]);
|
|
49160
49557
|
}
|
|
49161
49558
|
if (!rel) return null;
|
|
49162
49559
|
const bytes2 = readConfined(resolve42(dir, ".himi"), rel);
|
|
@@ -49172,7 +49569,7 @@ function readConfined(root, rel) {
|
|
|
49172
49569
|
const parts = rel.split(sep13);
|
|
49173
49570
|
let at = root;
|
|
49174
49571
|
for (let i = 0; i < parts.length; i++) {
|
|
49175
|
-
at =
|
|
49572
|
+
at = join52(at, parts[i]);
|
|
49176
49573
|
const st = lstatSync8(at);
|
|
49177
49574
|
if (st.isSymbolicLink() || !(i === parts.length - 1 ? st.isFile() : st.isDirectory())) return null;
|
|
49178
49575
|
}
|
|
@@ -49181,7 +49578,7 @@ function readConfined(root, rel) {
|
|
|
49181
49578
|
const fd = openSync2(at, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
|
|
49182
49579
|
try {
|
|
49183
49580
|
if (!fstatSync(fd).isFile()) return null;
|
|
49184
|
-
return
|
|
49581
|
+
return readFileSync60(fd);
|
|
49185
49582
|
} finally {
|
|
49186
49583
|
closeSync2(fd);
|
|
49187
49584
|
}
|
|
@@ -49232,7 +49629,7 @@ __export(run_browser_exports, {
|
|
|
49232
49629
|
runInBrowser: () => runInBrowser
|
|
49233
49630
|
});
|
|
49234
49631
|
import { createServer as createServer5 } from "node:http";
|
|
49235
|
-
import { existsSync as
|
|
49632
|
+
import { existsSync as existsSync55, readFileSync as readFileSync61 } from "node:fs";
|
|
49236
49633
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
49237
49634
|
import { dirname as dirname28, resolve as resolve43 } from "node:path";
|
|
49238
49635
|
import { fileURLToPath as fileURLToPath23 } from "node:url";
|
|
@@ -49240,7 +49637,7 @@ function stagedDir() {
|
|
|
49240
49637
|
return process.env.HIMI_BROWSER_PLANE_OUT ? resolve43(process.env.HIMI_BROWSER_PLANE_OUT) : resolve43(REPO, "packages", "serve", "dist", "browser-plane");
|
|
49241
49638
|
}
|
|
49242
49639
|
function missingStaged() {
|
|
49243
|
-
return [...SERVED].filter((f) => !
|
|
49640
|
+
return [...SERVED].filter((f) => !existsSync55(resolve43(stagedDir(), f))).sort();
|
|
49244
49641
|
}
|
|
49245
49642
|
function ensureBrowserPlaneStaged() {
|
|
49246
49643
|
if (missingStaged().length === 0) return { ok: true, detail: "already staged" };
|
|
@@ -49330,7 +49727,7 @@ async function runInBrowser(releaseRoot, app, header, opts = {}) {
|
|
|
49330
49727
|
}
|
|
49331
49728
|
const name = path2 === "/" || path2 === "/index.html" ? "host.html" : path2.slice(1);
|
|
49332
49729
|
if (SERVED.has(name)) {
|
|
49333
|
-
if (!
|
|
49730
|
+
if (!existsSync55(resolve43(stagedDir(), name))) {
|
|
49334
49731
|
const restaged = ensureBrowserPlaneStaged();
|
|
49335
49732
|
if (!restaged.ok) {
|
|
49336
49733
|
res.writeHead(503, { "content-type": "application/json" });
|
|
@@ -49340,7 +49737,7 @@ async function runInBrowser(releaseRoot, app, header, opts = {}) {
|
|
|
49340
49737
|
}
|
|
49341
49738
|
let bytes2;
|
|
49342
49739
|
try {
|
|
49343
|
-
bytes2 =
|
|
49740
|
+
bytes2 = readFileSync61(resolve43(stagedDir(), name));
|
|
49344
49741
|
} catch (e) {
|
|
49345
49742
|
res.writeHead(503, { "content-type": "application/json" });
|
|
49346
49743
|
res.end(JSON.stringify({ error: "browser_plane_unstaged", file: name, detail: String(e) }));
|
|
@@ -49800,7 +50197,7 @@ __export(preflight_exports, {
|
|
|
49800
50197
|
parseStoreConfig: () => parseStoreConfig,
|
|
49801
50198
|
requireEnv: () => requireEnv
|
|
49802
50199
|
});
|
|
49803
|
-
import { existsSync as
|
|
50200
|
+
import { existsSync as existsSync56, readFileSync as readFileSync62 } from "node:fs";
|
|
49804
50201
|
import { isAbsolute as isAbsolute3, relative as relative9, resolve as resolve44 } from "node:path";
|
|
49805
50202
|
function isInsideRepo(p) {
|
|
49806
50203
|
const rel = relative9(REPO_ROOT3, resolve44(p));
|
|
@@ -49857,10 +50254,10 @@ function parseStoreConfig(text5) {
|
|
|
49857
50254
|
}
|
|
49858
50255
|
function loadStoreConfig(app) {
|
|
49859
50256
|
const p = storeConfigPath(app);
|
|
49860
|
-
if (!
|
|
50257
|
+
if (!existsSync56(p)) {
|
|
49861
50258
|
throw new Error(`No store config at ${p}. Create apps/${app}/store/store.config.yaml first (see /setup-store-signing).`);
|
|
49862
50259
|
}
|
|
49863
|
-
return parseStoreConfig(
|
|
50260
|
+
return parseStoreConfig(readFileSync62(p, "utf8"));
|
|
49864
50261
|
}
|
|
49865
50262
|
var init_preflight = __esm({
|
|
49866
50263
|
"../store-release/preflight.ts"() {
|
|
@@ -49879,19 +50276,19 @@ __export(credential_profile_exports, {
|
|
|
49879
50276
|
profilePath: () => profilePath,
|
|
49880
50277
|
resolveStoreCredentials: () => resolveStoreCredentials
|
|
49881
50278
|
});
|
|
49882
|
-
import { existsSync as
|
|
50279
|
+
import { existsSync as existsSync57, readFileSync as readFileSync63 } from "node:fs";
|
|
49883
50280
|
import { homedir as homedir5 } from "node:os";
|
|
49884
|
-
import { join as
|
|
50281
|
+
import { join as join53 } from "node:path";
|
|
49885
50282
|
function credentialsDir(home = homedir5()) {
|
|
49886
|
-
return
|
|
50283
|
+
return join53(home, ".himalaya", "store-credentials");
|
|
49887
50284
|
}
|
|
49888
50285
|
function profilePath(name, home = homedir5()) {
|
|
49889
50286
|
if (!PROFILE_NAME.test(name)) {
|
|
49890
50287
|
throw new Error(
|
|
49891
|
-
`credential profile ${JSON.stringify(name)} is not a profile name \u2014 use letters, digits, ".", "_" or "-" starting with a letter or digit. It names ${
|
|
50288
|
+
`credential profile ${JSON.stringify(name)} is not a profile name \u2014 use letters, digits, ".", "_" or "-" starting with a letter or digit. It names ${join53(credentialsDir(home), "<name>.json")}; it is never a path.`
|
|
49892
50289
|
);
|
|
49893
50290
|
}
|
|
49894
|
-
return
|
|
50291
|
+
return join53(credentialsDir(home), `${name}.json`);
|
|
49895
50292
|
}
|
|
49896
50293
|
function parseProfile(text5, label2) {
|
|
49897
50294
|
let doc;
|
|
@@ -49922,8 +50319,8 @@ function resolveStoreCredentials(opts) {
|
|
|
49922
50319
|
const { app, cfg } = opts;
|
|
49923
50320
|
const env = opts.env ?? process.env;
|
|
49924
50321
|
const home = opts.home ?? homedir5();
|
|
49925
|
-
const read = opts.readProfile ?? ((p) =>
|
|
49926
|
-
const exists = opts.profileExists ??
|
|
50322
|
+
const read = opts.readProfile ?? ((p) => readFileSync63(p, "utf8"));
|
|
50323
|
+
const exists = opts.profileExists ?? existsSync57;
|
|
49927
50324
|
const ios = cfg.ios ?? {};
|
|
49928
50325
|
const flagName = opts.profileFlag?.trim();
|
|
49929
50326
|
const named = namedProfile(cfg, opts.profileFlag);
|
|
@@ -50003,9 +50400,9 @@ __export(preflight_app_exports, {
|
|
|
50003
50400
|
preflightApp: () => preflightApp,
|
|
50004
50401
|
profileAccount: () => profileAccount
|
|
50005
50402
|
});
|
|
50006
|
-
import { readFileSync as
|
|
50403
|
+
import { readFileSync as readFileSync64, existsSync as existsSync58, readdirSync as readdirSync26, statSync as statSync15 } from "node:fs";
|
|
50007
50404
|
import { createHash as createHash26 } from "node:crypto";
|
|
50008
|
-
import { join as
|
|
50405
|
+
import { join as join54 } from "node:path";
|
|
50009
50406
|
function analyze(projectYml, storeConfig, icon, account) {
|
|
50010
50407
|
const f = [];
|
|
50011
50408
|
const has = (re, s) => re.test(s);
|
|
@@ -50069,13 +50466,13 @@ function profileAccount(app, storeConfig, opts = {}) {
|
|
|
50069
50466
|
}
|
|
50070
50467
|
}
|
|
50071
50468
|
async function preflightApp(app, opts = {}) {
|
|
50072
|
-
const projectYml =
|
|
50073
|
-
const storeConfig =
|
|
50469
|
+
const projectYml = existsSync58(iosProjectYml(app)) ? readFileSync64(iosProjectYml(app), "utf8") : "";
|
|
50470
|
+
const storeConfig = existsSync58(storeConfigPath(app)) ? readFileSync64(storeConfigPath(app), "utf8") : "";
|
|
50074
50471
|
if (!storeConfig) return [{ level: "error", message: `no apps/${app}/store/store.config.yaml \u2014 run /setup-store-signing first.` }];
|
|
50075
50472
|
const findings = analyze(
|
|
50076
50473
|
projectYml,
|
|
50077
50474
|
storeConfig,
|
|
50078
|
-
await appIconState(
|
|
50475
|
+
await appIconState(join54(appDir(app), "ios")),
|
|
50079
50476
|
profileAccount(app, storeConfig, opts)
|
|
50080
50477
|
);
|
|
50081
50478
|
findings.push(...analyzeListing(metadataFilesPresent(app), listScreenshots(app)));
|
|
@@ -50104,17 +50501,17 @@ function analyzeSubmissionRecord(appLevel, review, opts) {
|
|
|
50104
50501
|
return f;
|
|
50105
50502
|
}
|
|
50106
50503
|
function appLevelMetadataFiles(app, locale = "en-US") {
|
|
50107
|
-
const root =
|
|
50504
|
+
const root = join54(storeDir(app), "metadata");
|
|
50108
50505
|
const out = /* @__PURE__ */ new Set();
|
|
50109
|
-
if (
|
|
50506
|
+
if (existsSync58(root)) {
|
|
50110
50507
|
for (const n of readdirSync26(root)) if (n.endsWith(".txt")) out.add(n);
|
|
50111
50508
|
}
|
|
50112
|
-
if (
|
|
50509
|
+
if (existsSync58(join54(root, locale, "privacy_url.txt"))) out.add("privacy_url.txt");
|
|
50113
50510
|
return out;
|
|
50114
50511
|
}
|
|
50115
50512
|
function reviewInfoFiles(app) {
|
|
50116
|
-
const dir =
|
|
50117
|
-
if (!
|
|
50513
|
+
const dir = join54(storeDir(app), "review_information");
|
|
50514
|
+
if (!existsSync58(dir)) return /* @__PURE__ */ new Set();
|
|
50118
50515
|
return new Set(readdirSync26(dir).filter((n) => n.endsWith(".txt")));
|
|
50119
50516
|
}
|
|
50120
50517
|
function isValidAppStoreSize(w, h) {
|
|
@@ -50224,12 +50621,12 @@ function analyzePlayListing(assets) {
|
|
|
50224
50621
|
return f;
|
|
50225
50622
|
}
|
|
50226
50623
|
function playListingAssets(app, locale = "en-US") {
|
|
50227
|
-
const dir =
|
|
50624
|
+
const dir = join54(storeDir(app), "play", locale, "images");
|
|
50228
50625
|
const read = (names) => {
|
|
50229
50626
|
for (const name of names) {
|
|
50230
|
-
const p =
|
|
50627
|
+
const p = join54(dir, name);
|
|
50231
50628
|
try {
|
|
50232
|
-
if (statSync15(p).isFile()) return { name, bytes:
|
|
50629
|
+
if (statSync15(p).isFile()) return { name, bytes: readFileSync64(p) };
|
|
50233
50630
|
} catch {
|
|
50234
50631
|
}
|
|
50235
50632
|
}
|
|
@@ -50260,26 +50657,26 @@ function analyzeListing(metaFiles, shots) {
|
|
|
50260
50657
|
return f;
|
|
50261
50658
|
}
|
|
50262
50659
|
function metadataFilesPresent(app, locale = "en-US") {
|
|
50263
|
-
const dir =
|
|
50264
|
-
if (!
|
|
50660
|
+
const dir = join54(storeDir(app), "metadata", locale);
|
|
50661
|
+
if (!existsSync58(dir)) return /* @__PURE__ */ new Set();
|
|
50265
50662
|
return new Set(readdirSync26(dir).filter((n) => n.endsWith(".txt")));
|
|
50266
50663
|
}
|
|
50267
50664
|
function listScreenshots(app, locale = "en-US") {
|
|
50268
50665
|
const out = [];
|
|
50269
|
-
const flat =
|
|
50270
|
-
if (
|
|
50666
|
+
const flat = join54(storeDir(app), "screenshots", locale);
|
|
50667
|
+
if (existsSync58(flat)) {
|
|
50271
50668
|
for (const png of readdirSync26(flat).filter((n) => n.endsWith(".png"))) {
|
|
50272
|
-
const sz = pngSize(
|
|
50669
|
+
const sz = pngSize(readFileSync64(join54(flat, png)));
|
|
50273
50670
|
if (sz) out.push({ name: png, w: sz.w, h: sz.h });
|
|
50274
50671
|
}
|
|
50275
50672
|
}
|
|
50276
|
-
const legacy =
|
|
50277
|
-
if (
|
|
50673
|
+
const legacy = join54(storeDir(app), "metadata", locale, "screenshots");
|
|
50674
|
+
if (existsSync58(legacy)) {
|
|
50278
50675
|
for (const deviceDir of readdirSync26(legacy)) {
|
|
50279
|
-
const d =
|
|
50676
|
+
const d = join54(legacy, deviceDir);
|
|
50280
50677
|
if (!statSync15(d).isDirectory()) continue;
|
|
50281
50678
|
for (const png of readdirSync26(d).filter((n) => n.endsWith(".png"))) {
|
|
50282
|
-
const sz = pngSize(
|
|
50679
|
+
const sz = pngSize(readFileSync64(join54(d, png)));
|
|
50283
50680
|
if (sz) out.push({ name: `${deviceDir}/${png}`, w: sz.w, h: sz.h });
|
|
50284
50681
|
}
|
|
50285
50682
|
}
|
|
@@ -50287,13 +50684,13 @@ function listScreenshots(app, locale = "en-US") {
|
|
|
50287
50684
|
return out;
|
|
50288
50685
|
}
|
|
50289
50686
|
function placeholderHashes2() {
|
|
50290
|
-
const templateIos =
|
|
50291
|
-
if (!
|
|
50687
|
+
const templateIos = join54(appDir("_template"), "ios");
|
|
50688
|
+
if (!existsSync58(templateIos)) return [LEGACY_PLACEHOLDER_SHA2562];
|
|
50292
50689
|
for (const target of readdirSync26(templateIos)) {
|
|
50293
|
-
const p =
|
|
50690
|
+
const p = join54(templateIos, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
|
|
50294
50691
|
try {
|
|
50295
50692
|
if (!statSync15(p).isFile()) continue;
|
|
50296
|
-
return [LEGACY_PLACEHOLDER_SHA2562, createHash26("sha256").update(
|
|
50693
|
+
return [LEGACY_PLACEHOLDER_SHA2562, createHash26("sha256").update(readFileSync64(p)).digest("hex")];
|
|
50297
50694
|
} catch {
|
|
50298
50695
|
}
|
|
50299
50696
|
}
|
|
@@ -50324,12 +50721,12 @@ async function pixelIssues(bytes2) {
|
|
|
50324
50721
|
}
|
|
50325
50722
|
}
|
|
50326
50723
|
async function appIconState(iosDir) {
|
|
50327
|
-
if (!
|
|
50724
|
+
if (!existsSync58(iosDir)) return { exists: false, isPlaceholder: false, storeIssues: [] };
|
|
50328
50725
|
for (const target of readdirSync26(iosDir)) {
|
|
50329
|
-
const p =
|
|
50726
|
+
const p = join54(iosDir, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
|
|
50330
50727
|
try {
|
|
50331
50728
|
if (!statSync15(p).isFile()) continue;
|
|
50332
|
-
const bytes2 =
|
|
50729
|
+
const bytes2 = readFileSync64(p);
|
|
50333
50730
|
const hash = createHash26("sha256").update(bytes2).digest("hex");
|
|
50334
50731
|
const pixels = await pixelIssues(bytes2);
|
|
50335
50732
|
return {
|
|
@@ -50401,7 +50798,7 @@ __export(version_exports, {
|
|
|
50401
50798
|
setAndroidVersion: () => setAndroidVersion,
|
|
50402
50799
|
setIosVersion: () => setIosVersion
|
|
50403
50800
|
});
|
|
50404
|
-
import { readFileSync as
|
|
50801
|
+
import { readFileSync as readFileSync65, writeFileSync as writeFileSync23 } from "node:fs";
|
|
50405
50802
|
function readIosVersion(projectYml) {
|
|
50406
50803
|
const marketing = matchScalar(projectYml, "CFBundleShortVersionString");
|
|
50407
50804
|
const build2 = matchScalar(projectYml, "CFBundleVersion");
|
|
@@ -50459,8 +50856,8 @@ function setAndroidVersion(gradle, v) {
|
|
|
50459
50856
|
function bumpVersion(app, opts) {
|
|
50460
50857
|
const iosPath = iosProjectYml(app);
|
|
50461
50858
|
const gradlePath = androidGradle(app);
|
|
50462
|
-
const iosYml =
|
|
50463
|
-
const gradle =
|
|
50859
|
+
const iosYml = readFileSync65(iosPath, "utf8");
|
|
50860
|
+
const gradle = readFileSync65(gradlePath, "utf8");
|
|
50464
50861
|
const current = readIosVersion(iosYml);
|
|
50465
50862
|
const next = {
|
|
50466
50863
|
marketing: opts.marketing ?? current.marketing,
|
|
@@ -50477,7 +50874,7 @@ var init_version = __esm({
|
|
|
50477
50874
|
});
|
|
50478
50875
|
|
|
50479
50876
|
// ../store-release/register-bundle.ts
|
|
50480
|
-
import { readFileSync as
|
|
50877
|
+
import { readFileSync as readFileSync66 } from "node:fs";
|
|
50481
50878
|
import { createPrivateKey as createPrivateKey2, sign } from "node:crypto";
|
|
50482
50879
|
function b64url2(b) {
|
|
50483
50880
|
return Buffer.from(b).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
@@ -50495,7 +50892,7 @@ function bundleIdBody(identifier, name, platform = "IOS") {
|
|
|
50495
50892
|
async function registerBundleId(opts) {
|
|
50496
50893
|
const env = requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
|
|
50497
50894
|
assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
|
|
50498
|
-
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID,
|
|
50895
|
+
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync66(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
|
|
50499
50896
|
const res = await fetch(`${ASC_API}/v1/bundleIds`, {
|
|
50500
50897
|
method: "POST",
|
|
50501
50898
|
headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" },
|
|
@@ -50549,7 +50946,7 @@ __export(asc_status_exports, {
|
|
|
50549
50946
|
ascStatus: () => ascStatus,
|
|
50550
50947
|
buildVerdict: () => buildVerdict
|
|
50551
50948
|
});
|
|
50552
|
-
import { readFileSync as
|
|
50949
|
+
import { readFileSync as readFileSync67 } from "node:fs";
|
|
50553
50950
|
function buildVerdict(builds) {
|
|
50554
50951
|
if (!builds.length) {
|
|
50555
50952
|
return "NO builds registered \u2014 if you uploaded recently and it's been >15 min, the binary was REJECTED IN PROCESSING (reason is email-only; run validate-binary.ts / scan-purpose-strings.ts to reproduce it).";
|
|
@@ -50563,7 +50960,7 @@ function buildVerdict(builds) {
|
|
|
50563
50960
|
function client(creds) {
|
|
50564
50961
|
const env = creds ?? requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
|
|
50565
50962
|
assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
|
|
50566
|
-
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID,
|
|
50963
|
+
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync67(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
|
|
50567
50964
|
return async (path2) => {
|
|
50568
50965
|
const r = await fetch(`${ASC}${path2}`, { headers: { Authorization: `Bearer ${jwt}` } });
|
|
50569
50966
|
return { status: r.status, json: await r.json().catch(() => ({})) };
|
|
@@ -50723,7 +51120,7 @@ __export(secrets_exports, {
|
|
|
50723
51120
|
runRemoteSecretsCommand: () => runRemoteSecretsCommand,
|
|
50724
51121
|
runSecretsCommand: () => runSecretsCommand
|
|
50725
51122
|
});
|
|
50726
|
-
import { readFileSync as
|
|
51123
|
+
import { readFileSync as readFileSync68 } from "node:fs";
|
|
50727
51124
|
function environment(value) {
|
|
50728
51125
|
if (value === "preview" || value === "production") return value;
|
|
50729
51126
|
throw new Error("--environment must be preview or production");
|
|
@@ -50754,7 +51151,7 @@ async function runSecretsCommand(operation, flags, io, options = {}) {
|
|
|
50754
51151
|
io.log(JSON.stringify(await vault.list({ app, environment: env })));
|
|
50755
51152
|
return 0;
|
|
50756
51153
|
}
|
|
50757
|
-
const value = options.readValue ? options.readValue() :
|
|
51154
|
+
const value = options.readValue ? options.readValue() : readFileSync68(0, "utf8").replace(/\r?\n$/, "");
|
|
50758
51155
|
if (operation === "set") await vault.set({ app, environment: env, name, value });
|
|
50759
51156
|
else if (operation === "rotate") await vault.rotate({ app, environment: env, name, value });
|
|
50760
51157
|
else throw new Error(`unknown secrets operation ${operation}`);
|
|
@@ -50783,7 +51180,7 @@ async function runRemoteSecretsCommand(operation, flags, io, options) {
|
|
|
50783
51180
|
}
|
|
50784
51181
|
let body;
|
|
50785
51182
|
if (operation !== "list") {
|
|
50786
|
-
const value = options.readValue ? options.readValue() :
|
|
51183
|
+
const value = options.readValue ? options.readValue() : readFileSync68(0, "utf8").replace(/\r?\n$/, "");
|
|
50787
51184
|
body = JSON.stringify({ value });
|
|
50788
51185
|
}
|
|
50789
51186
|
const response = await (options.fetchImpl ?? fetch)(url, { method: operation === "list" ? "GET" : operation === "set" ? "PUT" : "POST", headers: headers2, body });
|
|
@@ -50819,15 +51216,15 @@ __export(notify_exports, {
|
|
|
50819
51216
|
runNotify: () => runNotify,
|
|
50820
51217
|
saveAdminSession: () => saveAdminSession
|
|
50821
51218
|
});
|
|
50822
|
-
import { chmodSync as chmodSync3, mkdirSync as mkdirSync27, readFileSync as
|
|
51219
|
+
import { chmodSync as chmodSync3, mkdirSync as mkdirSync27, readFileSync as readFileSync69, writeFileSync as writeFileSync24 } from "node:fs";
|
|
50823
51220
|
import { homedir as homedir6 } from "node:os";
|
|
50824
|
-
import { dirname as dirname30, join as
|
|
51221
|
+
import { dirname as dirname30, join as join55 } from "node:path";
|
|
50825
51222
|
function defaultSessionsPath() {
|
|
50826
|
-
return process.env.HIMI_ADMIN_SESSIONS_FILE ??
|
|
51223
|
+
return process.env.HIMI_ADMIN_SESSIONS_FILE ?? join55(homedir6(), ".himalaya", "admin-sessions.json");
|
|
50827
51224
|
}
|
|
50828
51225
|
function loadSessionsFile(path2 = defaultSessionsPath()) {
|
|
50829
51226
|
try {
|
|
50830
|
-
return JSON.parse(
|
|
51227
|
+
return JSON.parse(readFileSync69(path2, "utf8"));
|
|
50831
51228
|
} catch {
|
|
50832
51229
|
return {};
|
|
50833
51230
|
}
|
|
@@ -54385,7 +54782,7 @@ var init_brand_font = __esm({
|
|
|
54385
54782
|
|
|
54386
54783
|
// src/site-analyze/write-artifacts.ts
|
|
54387
54784
|
import { mkdirSync as mkdirSync28, writeFileSync as writeFileSync25 } from "node:fs";
|
|
54388
|
-
import { join as
|
|
54785
|
+
import { join as join56 } from "node:path";
|
|
54389
54786
|
function attachVeloSources(book, sources, put) {
|
|
54390
54787
|
const byPath = new Map((sources ?? []).map((s) => [s.path, s.text]));
|
|
54391
54788
|
for (const f of book.velo.files) {
|
|
@@ -54540,12 +54937,12 @@ async function downloadMedia(book, fetchImpl, put) {
|
|
|
54540
54937
|
}
|
|
54541
54938
|
async function writeBusinessBook(result, opts) {
|
|
54542
54939
|
const out = opts.outDir;
|
|
54543
|
-
mkdirSync28(
|
|
54544
|
-
mkdirSync28(
|
|
54940
|
+
mkdirSync28(join56(out, "evidence/pages"), { recursive: true });
|
|
54941
|
+
mkdirSync28(join56(out, "media/catalog"), { recursive: true });
|
|
54545
54942
|
const files = [];
|
|
54546
54943
|
const put = (rel, body) => {
|
|
54547
|
-
const p =
|
|
54548
|
-
mkdirSync28(
|
|
54944
|
+
const p = join56(out, rel);
|
|
54945
|
+
mkdirSync28(join56(p, ".."), { recursive: true });
|
|
54549
54946
|
writeFileSync25(p, body);
|
|
54550
54947
|
files.push(rel);
|
|
54551
54948
|
};
|
|
@@ -54639,8 +55036,8 @@ var init_customer_build = __esm({
|
|
|
54639
55036
|
});
|
|
54640
55037
|
|
|
54641
55038
|
// src/site-analyze/apply.ts
|
|
54642
|
-
import { existsSync as
|
|
54643
|
-
import { dirname as dirname31, isAbsolute as isAbsolute4, join as
|
|
55039
|
+
import { existsSync as existsSync59, readFileSync as readFileSync70, writeFileSync as writeFileSync26, copyFileSync as copyFileSync3, mkdirSync as mkdirSync29, realpathSync as realpathSync7, statSync as statSync16 } from "node:fs";
|
|
55040
|
+
import { dirname as dirname31, isAbsolute as isAbsolute4, join as join57, resolve as resolve45, sep as sep14 } from "node:path";
|
|
54644
55041
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
54645
55042
|
function unpairedRedirectNote(overlay) {
|
|
54646
55043
|
if (!overlay.wix?.clientId || overlay.wix.redirectUri) return void 0;
|
|
@@ -54655,7 +55052,7 @@ function committedShellProvisioning(path2) {
|
|
|
54655
55052
|
function findRepoRoot(cwd) {
|
|
54656
55053
|
let dir = cwd;
|
|
54657
55054
|
for (let i = 0; i < 8; i++) {
|
|
54658
|
-
if (SHELL_NAMES2.some((name) =>
|
|
55055
|
+
if (SHELL_NAMES2.some((name) => existsSync59(join57(dir, shellAppDir(name), "package.json")))) return dir;
|
|
54659
55056
|
const next = dirname31(dir);
|
|
54660
55057
|
if (next === dir) break;
|
|
54661
55058
|
dir = next;
|
|
@@ -54723,11 +55120,11 @@ function mergeCustomerOwned(committed, overlay) {
|
|
|
54723
55120
|
}
|
|
54724
55121
|
function buildMergedContract(options) {
|
|
54725
55122
|
const { appDir: appDir2, packageDir, overlay } = options;
|
|
54726
|
-
const committedPath =
|
|
54727
|
-
if (!
|
|
55123
|
+
const committedPath = join57(appDir2, "provisioning.json");
|
|
55124
|
+
if (!existsSync59(committedPath)) {
|
|
54728
55125
|
throw new Error(`shell has no committed provisioning.json at ${committedPath} to build a contract from`);
|
|
54729
55126
|
}
|
|
54730
|
-
const committed = JSON.parse(
|
|
55127
|
+
const committed = JSON.parse(readFileSync70(committedPath, "utf8"));
|
|
54731
55128
|
const merged = mergeCustomerOwned(committed, overlay);
|
|
54732
55129
|
const overlayFontFamily = (overlay.branding ?? {}).fontFamily;
|
|
54733
55130
|
const branding = merged.branding ?? {};
|
|
@@ -54739,8 +55136,8 @@ function buildMergedContract(options) {
|
|
|
54739
55136
|
};
|
|
54740
55137
|
const stage = (fromRel, toRel) => {
|
|
54741
55138
|
const from = contained(packageDir, fromRel);
|
|
54742
|
-
const to = contained(
|
|
54743
|
-
if (!from || !to || !
|
|
55139
|
+
const to = contained(join57(appDir2, STAGED), toRel.slice(STAGED.length + 1));
|
|
55140
|
+
if (!from || !to || !existsSync59(from)) return void 0;
|
|
54744
55141
|
let real;
|
|
54745
55142
|
let realRoot;
|
|
54746
55143
|
try {
|
|
@@ -54762,11 +55159,11 @@ function buildMergedContract(options) {
|
|
|
54762
55159
|
};
|
|
54763
55160
|
const icon = stage("media/icon.png", `${STAGED}/icon.png`);
|
|
54764
55161
|
if (icon) branding.appIconPath = icon;
|
|
54765
|
-
const facesPath =
|
|
54766
|
-
if (
|
|
55162
|
+
const facesPath = join57(packageDir, "media/fonts/faces.json");
|
|
55163
|
+
if (existsSync59(facesPath)) {
|
|
54767
55164
|
let faces = [];
|
|
54768
55165
|
try {
|
|
54769
|
-
const parsed = JSON.parse(
|
|
55166
|
+
const parsed = JSON.parse(readFileSync70(facesPath, "utf8"));
|
|
54770
55167
|
faces = Array.isArray(parsed) ? parsed : [];
|
|
54771
55168
|
} catch {
|
|
54772
55169
|
faces = [];
|
|
@@ -54787,9 +55184,9 @@ function buildMergedContract(options) {
|
|
|
54787
55184
|
merged.branding = branding;
|
|
54788
55185
|
const body = `${JSON.stringify(merged, null, 2)}
|
|
54789
55186
|
`;
|
|
54790
|
-
const path2 =
|
|
55187
|
+
const path2 = join57(packageDir, "provisioning.contract.json");
|
|
54791
55188
|
writeFileSync26(path2, body);
|
|
54792
|
-
const localPath =
|
|
55189
|
+
const localPath = join57(appDir2, LOCAL_CONTRACT_REL);
|
|
54793
55190
|
mkdirSync29(dirname31(localPath), { recursive: true });
|
|
54794
55191
|
writeFileSync26(localPath, body);
|
|
54795
55192
|
staged.push(localPath);
|
|
@@ -54799,8 +55196,8 @@ async function applyOverlays(input) {
|
|
|
54799
55196
|
const cwd = resolve45(input.cwd);
|
|
54800
55197
|
const shell = input.shell ?? DEFAULT_BRANDABLE_SHELL;
|
|
54801
55198
|
assertKnownShell(shell);
|
|
54802
|
-
const overlay = JSON.parse(
|
|
54803
|
-
const tokens = JSON.parse(
|
|
55199
|
+
const overlay = JSON.parse(readFileSync70(input.overlayPath, "utf8"));
|
|
55200
|
+
const tokens = JSON.parse(readFileSync70(input.tokensPath, "utf8"));
|
|
54804
55201
|
const wrote = [];
|
|
54805
55202
|
const notes = [];
|
|
54806
55203
|
const repoRoot2 = findRepoRoot(cwd);
|
|
@@ -54810,7 +55207,7 @@ async function applyOverlays(input) {
|
|
|
54810
55207
|
`shell "${shell}" cannot bake a customer brand \u2014 it ships no prepare:customer script`
|
|
54811
55208
|
);
|
|
54812
55209
|
}
|
|
54813
|
-
const appDir2 =
|
|
55210
|
+
const appDir2 = join57(repoRoot2, shellAppDir(shell));
|
|
54814
55211
|
const packageDir = dirname31(resolve45(input.overlayPath));
|
|
54815
55212
|
const { path: contract, staged } = buildMergedContract({ appDir: appDir2, packageDir, overlay });
|
|
54816
55213
|
wrote.push(...staged);
|
|
@@ -54832,10 +55229,10 @@ async function applyOverlays(input) {
|
|
|
54832
55229
|
note: `prepare:customer --contract with a merged contract (committed provisioning.json untouched)${unpairedInRepo ? ` \xB7 ${unpairedInRepo}` : ""}`
|
|
54833
55230
|
};
|
|
54834
55231
|
}
|
|
54835
|
-
const pkgProv =
|
|
55232
|
+
const pkgProv = join57(cwd, "provisioning.json");
|
|
54836
55233
|
assertNotCommitted(pkgProv, input.forbiddenProvisioning);
|
|
54837
|
-
if (
|
|
54838
|
-
const cur = JSON.parse(
|
|
55234
|
+
if (existsSync59(pkgProv)) {
|
|
55235
|
+
const cur = JSON.parse(readFileSync70(pkgProv, "utf8"));
|
|
54839
55236
|
const merged = deepMerge4(cur, overlay);
|
|
54840
55237
|
writeFileSync26(pkgProv, JSON.stringify(merged, null, 2) + "\n");
|
|
54841
55238
|
wrote.push(pkgProv);
|
|
@@ -54843,9 +55240,9 @@ async function applyOverlays(input) {
|
|
|
54843
55240
|
writeFileSync26(pkgProv, JSON.stringify(overlay, null, 2) + "\n");
|
|
54844
55241
|
wrote.push(pkgProv);
|
|
54845
55242
|
}
|
|
54846
|
-
const pkgTokens =
|
|
54847
|
-
if (
|
|
54848
|
-
const cur = JSON.parse(
|
|
55243
|
+
const pkgTokens = join57(cwd, "tokens.json");
|
|
55244
|
+
if (existsSync59(pkgTokens) && (tokens.colors || tokens.typography)) {
|
|
55245
|
+
const cur = JSON.parse(readFileSync70(pkgTokens, "utf8"));
|
|
54849
55246
|
const merged = deepMerge4(cur, tokens);
|
|
54850
55247
|
const mergedColors = merged.colors;
|
|
54851
55248
|
if (mergedColors && typeof mergedColors === "object" && !Array.isArray(mergedColors)) {
|
|
@@ -54864,9 +55261,9 @@ async function applyOverlays(input) {
|
|
|
54864
55261
|
wrote.push(pkgTokens);
|
|
54865
55262
|
}
|
|
54866
55263
|
const homeAction = homeRefreshActionId(shell);
|
|
54867
|
-
const homeSrc =
|
|
54868
|
-
if (homeAction &&
|
|
54869
|
-
const prev =
|
|
55264
|
+
const homeSrc = join57(cwd, "dev/index.ts");
|
|
55265
|
+
if (homeAction && existsSync59(homeSrc)) {
|
|
55266
|
+
const prev = readFileSync70(homeSrc, "utf8");
|
|
54870
55267
|
const patched = patchBrandParams(prev, overlay, homeAction);
|
|
54871
55268
|
let next = patched.src;
|
|
54872
55269
|
if (!patched.foreign && overlay.installedVerticals?.length) {
|
|
@@ -54889,13 +55286,13 @@ async function applyOverlays(input) {
|
|
|
54889
55286
|
notes.push(`${patched.unparsed} onAppear params block(s) in ${homeSrc} could not be read \u2014 any brand values inside them were not applied`);
|
|
54890
55287
|
}
|
|
54891
55288
|
}
|
|
54892
|
-
if (!input.iconPath || !
|
|
55289
|
+
if (!input.iconPath || !existsSync59(input.iconPath)) {
|
|
54893
55290
|
const book = input.iconPath ? dirname31(dirname31(resolve45(input.iconPath))) : void 0;
|
|
54894
55291
|
notes.push(
|
|
54895
55292
|
book ? `no icon installed \u2014 ${siteLogoAbsence(book).hint}` : "no icon installed and no business book to say why \u2014 `himi icon generate` draws one from the accent, or `himi icon set <file.png>` installs the customer's own mark"
|
|
54896
55293
|
);
|
|
54897
55294
|
}
|
|
54898
|
-
if (input.iconPath &&
|
|
55295
|
+
if (input.iconPath && existsSync59(input.iconPath)) {
|
|
54899
55296
|
try {
|
|
54900
55297
|
const installed = await installIcon(cwd, input.iconPath, { derivePlay: true });
|
|
54901
55298
|
wrote.push(...installed.wrote);
|
|
@@ -59050,7 +59447,7 @@ __export(cli_exports, {
|
|
|
59050
59447
|
runSiteAnalyze: () => runSiteAnalyze,
|
|
59051
59448
|
runSiteFunctionCli: () => runSiteFunctionCli
|
|
59052
59449
|
});
|
|
59053
|
-
import { readFileSync as
|
|
59450
|
+
import { readFileSync as readFileSync71 } from "node:fs";
|
|
59054
59451
|
import { resolve as resolve46 } from "node:path";
|
|
59055
59452
|
function assetFetchFor(_opts) {
|
|
59056
59453
|
return pinnedFetch2;
|
|
@@ -59137,7 +59534,7 @@ async function runSiteFunctionCli(opts) {
|
|
|
59137
59534
|
let source;
|
|
59138
59535
|
if (opts.sourcePath) {
|
|
59139
59536
|
const p = resolve46(opts.cwd ?? process.cwd(), opts.sourcePath);
|
|
59140
|
-
source =
|
|
59537
|
+
source = readFileSync71(p, "utf8");
|
|
59141
59538
|
}
|
|
59142
59539
|
let body;
|
|
59143
59540
|
if (opts.bodyRaw != null) {
|
|
@@ -59394,7 +59791,7 @@ __export(site_create_exports, {
|
|
|
59394
59791
|
runSiteList: () => runSiteList,
|
|
59395
59792
|
writeProvisioningBinding: () => writeProvisioningBinding
|
|
59396
59793
|
});
|
|
59397
|
-
import { existsSync as
|
|
59794
|
+
import { existsSync as existsSync60, readFileSync as readFileSync72, writeFileSync as writeFileSync27 } from "node:fs";
|
|
59398
59795
|
import { resolve as resolvePath2 } from "node:path";
|
|
59399
59796
|
function oauthClientName(projectName) {
|
|
59400
59797
|
return `${projectName} client`;
|
|
@@ -59543,7 +59940,7 @@ async function runSiteCreate(opts) {
|
|
|
59543
59940
|
if (!wantOauthApp) return { ...base, nextSteps: nextSteps(metaSiteId) };
|
|
59544
59941
|
return { ...base, clientId, redirectUri, nextSteps: nextSteps(metaSiteId, clientId) };
|
|
59545
59942
|
}
|
|
59546
|
-
function writeProvisioningBinding(target, binding2, fs = { existsSync:
|
|
59943
|
+
function writeProvisioningBinding(target, binding2, fs = { existsSync: existsSync60, readFileSync: readFileSync72, writeFileSync: writeFileSync27 }) {
|
|
59547
59944
|
const msid = binding2.siteId;
|
|
59548
59945
|
const path2 = resolvePath2(target);
|
|
59549
59946
|
const committed = committedShellProvisioning(path2);
|
|
@@ -60216,11 +60613,11 @@ var init_context = __esm({
|
|
|
60216
60613
|
});
|
|
60217
60614
|
|
|
60218
60615
|
// src/cli.ts
|
|
60219
|
-
import { mkdtempSync as mkdtempSync4, readFileSync as
|
|
60616
|
+
import { mkdtempSync as mkdtempSync4, readFileSync as readFileSync73, mkdirSync as mkdirSync30, writeFileSync as writeFileSync28, existsSync as existsSync61, rmSync as rmSync14, readdirSync as readdirSync27, statSync as statSync17, lstatSync as lstatSync9, accessSync, constants as constants2, renameSync as renameSync6, cpSync as cpSync3 } from "node:fs";
|
|
60220
60617
|
import { execFile, execFileSync as execFileSync7, spawnSync as spawnSync5, spawn as spawn6 } from "node:child_process";
|
|
60221
60618
|
import { createHash as createHash27, randomUUID as randomUUID5 } from "node:crypto";
|
|
60222
60619
|
import { tmpdir as tmpdir5, homedir as homedir7, hostname } from "node:os";
|
|
60223
|
-
import { join as
|
|
60620
|
+
import { join as join58, resolve as resolve47, relative as relative10, basename as basename14, dirname as dirname32 } from "node:path";
|
|
60224
60621
|
import { fileURLToPath as fileURLToPath24 } from "node:url";
|
|
60225
60622
|
|
|
60226
60623
|
// ../serve-cli/src/client.ts
|
|
@@ -63496,8 +63893,8 @@ var str6 = (v) => typeof v === "string" ? v : void 0;
|
|
|
63496
63893
|
var num2 = (v) => typeof v === "string" && v !== "" && Number.isFinite(Number(v)) ? Number(v) : void 0;
|
|
63497
63894
|
function embeddedTemplateCatalog() {
|
|
63498
63895
|
return availableTemplates().map((name) => {
|
|
63499
|
-
const path2 =
|
|
63500
|
-
const meta = JSON.parse(
|
|
63896
|
+
const path2 = join58(templateSourceDir(name), TEMPLATE_META_FILE);
|
|
63897
|
+
const meta = JSON.parse(readFileSync73(path2, "utf8"));
|
|
63501
63898
|
if (!meta || typeof meta.title !== "string" || typeof meta.description !== "string" || !Array.isArray(meta.tags)) {
|
|
63502
63899
|
throw new Error(`${path2} must be { title: string, description: string, tags: string[], category?: string }`);
|
|
63503
63900
|
}
|
|
@@ -64166,7 +64563,7 @@ var COMMANDS = [
|
|
|
64166
64563
|
];
|
|
64167
64564
|
function cliVersion() {
|
|
64168
64565
|
try {
|
|
64169
|
-
return JSON.parse(
|
|
64566
|
+
return JSON.parse(readFileSync73(new URL("../package.json", import.meta.url), "utf8")).version ?? "unknown";
|
|
64170
64567
|
} catch {
|
|
64171
64568
|
return "unknown";
|
|
64172
64569
|
}
|
|
@@ -64284,7 +64681,7 @@ function ageInDays(publishedAt, now = Date.now()) {
|
|
|
64284
64681
|
}
|
|
64285
64682
|
function packageVersion(path2) {
|
|
64286
64683
|
try {
|
|
64287
|
-
const version2 = JSON.parse(
|
|
64684
|
+
const version2 = JSON.parse(readFileSync73(path2, "utf8")).version;
|
|
64288
64685
|
return typeof version2 === "string" && version2 ? version2 : void 0;
|
|
64289
64686
|
} catch {
|
|
64290
64687
|
return void 0;
|
|
@@ -64293,7 +64690,7 @@ function packageVersion(path2) {
|
|
|
64293
64690
|
function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("./authoring-runtime/node_modules/@wix/himalaya/package.json", import.meta.url)) {
|
|
64294
64691
|
let dir = resolve47(fromDir);
|
|
64295
64692
|
for (; ; ) {
|
|
64296
|
-
const version2 = packageVersion(
|
|
64693
|
+
const version2 = packageVersion(join58(dir, "node_modules", "@wix", "himalaya", "package.json"));
|
|
64297
64694
|
if (version2) return { version: version2, source: "local" };
|
|
64298
64695
|
const parent = dirname32(dir);
|
|
64299
64696
|
if (parent === dir) break;
|
|
@@ -64303,7 +64700,7 @@ function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("
|
|
|
64303
64700
|
if (bundled) return { version: bundled, source: "bundled" };
|
|
64304
64701
|
try {
|
|
64305
64702
|
const root = execFileSync7("npm", ["root", "-g"], { stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
64306
|
-
const version2 = root ? packageVersion(
|
|
64703
|
+
const version2 = root ? packageVersion(join58(root, "@wix", "himalaya", "package.json")) : void 0;
|
|
64307
64704
|
return version2 ? { version: version2, source: "global" } : {};
|
|
64308
64705
|
} catch {
|
|
64309
64706
|
return {};
|
|
@@ -64350,11 +64747,11 @@ var UPDATE_RETRY_AFTER_FAILURE_MS = 60 * 60 * 1e3;
|
|
|
64350
64747
|
var UPDATE_SNOOZE_MS = 24 * 60 * 60 * 1e3;
|
|
64351
64748
|
var UPDATE_REEXEC_ENV = "HIMI_UPDATED_ONCE";
|
|
64352
64749
|
function updateCachePath(env = process.env) {
|
|
64353
|
-
return env.HIMI_UPDATE_CACHE_FILE ??
|
|
64750
|
+
return env.HIMI_UPDATE_CACHE_FILE ?? join58(homedir7(), ".himalaya", "update-check.json");
|
|
64354
64751
|
}
|
|
64355
64752
|
function readUpdateCache(path2) {
|
|
64356
64753
|
try {
|
|
64357
|
-
const parsed = JSON.parse(
|
|
64754
|
+
const parsed = JSON.parse(readFileSync73(path2, "utf8"));
|
|
64358
64755
|
return parsed && typeof parsed === "object" ? parsed : {};
|
|
64359
64756
|
} catch {
|
|
64360
64757
|
return {};
|
|
@@ -64422,12 +64819,12 @@ function createUpdateRunner(spawn7 = spawnSync5) {
|
|
|
64422
64819
|
},
|
|
64423
64820
|
installedVersion: () => {
|
|
64424
64821
|
const root = globalNodeModulesRoot();
|
|
64425
|
-
return root ? packageVersion(
|
|
64822
|
+
return root ? packageVersion(join58(root, "@wix", "himalaya-cli", "package.json")) : void 0;
|
|
64426
64823
|
},
|
|
64427
64824
|
reexec: (argv) => {
|
|
64428
64825
|
const root = globalNodeModulesRoot();
|
|
64429
|
-
const entry = root ?
|
|
64430
|
-
if (!entry || !
|
|
64826
|
+
const entry = root ? join58(root, "@wix", "himalaya-cli", "dist", "cli.mjs") : void 0;
|
|
64827
|
+
if (!entry || !existsSync61(entry)) return void 0;
|
|
64431
64828
|
const result = spawnSync5(process.execPath, [entry, ...argv], {
|
|
64432
64829
|
// inherit keeps PIPED STDIN working — commands that read stdin must survive a re-exec.
|
|
64433
64830
|
stdio: "inherit",
|
|
@@ -64474,7 +64871,7 @@ function staleUpdateLockFile(cachePath, now) {
|
|
|
64474
64871
|
for (const path2 of [`${cachePath}.lock.break`, `${cachePath}.lock`]) {
|
|
64475
64872
|
let content;
|
|
64476
64873
|
try {
|
|
64477
|
-
content =
|
|
64874
|
+
content = readFileSync73(path2, "utf8");
|
|
64478
64875
|
} catch {
|
|
64479
64876
|
continue;
|
|
64480
64877
|
}
|
|
@@ -64497,7 +64894,7 @@ function acquireUpdateLock(cachePath, now, hooks = {}) {
|
|
|
64497
64894
|
const mine = lockStamp(now);
|
|
64498
64895
|
const readLock = (path2) => {
|
|
64499
64896
|
try {
|
|
64500
|
-
return
|
|
64897
|
+
return readFileSync73(path2, "utf8");
|
|
64501
64898
|
} catch {
|
|
64502
64899
|
return void 0;
|
|
64503
64900
|
}
|
|
@@ -64794,9 +65191,9 @@ function diagnoseBody(body) {
|
|
|
64794
65191
|
const out = {};
|
|
64795
65192
|
const emptied = [];
|
|
64796
65193
|
for (const [key2, value] of Object.entries(body)) {
|
|
64797
|
-
const
|
|
64798
|
-
if (
|
|
64799
|
-
out[key2] =
|
|
65194
|
+
const fold2 = (key2 === "issues" || key2 === "failures" || key2 === "warnings") && folded(value);
|
|
65195
|
+
if (fold2) emptied.push(key2);
|
|
65196
|
+
out[key2] = fold2 ? [] : value;
|
|
64800
65197
|
}
|
|
64801
65198
|
if (emptied.length) out.foldedIntoFindings = emptied;
|
|
64802
65199
|
return out;
|
|
@@ -65035,7 +65432,7 @@ function executableOnPath(name, env = process.env) {
|
|
|
65035
65432
|
const suffixes = process.platform === "win32" ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
|
|
65036
65433
|
for (const dir of entries) {
|
|
65037
65434
|
for (const suffix of suffixes) {
|
|
65038
|
-
const candidate =
|
|
65435
|
+
const candidate = join58(dir, `${name}${suffix}`);
|
|
65039
65436
|
try {
|
|
65040
65437
|
if (!statSync17(candidate).isFile()) continue;
|
|
65041
65438
|
if (process.platform !== "win32") accessSync(candidate, constants2.X_OK);
|
|
@@ -65144,7 +65541,7 @@ async function nativeConfigAdvisories(app, configSource) {
|
|
|
65144
65541
|
const { iosProjectYml: iosProjectYml2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
65145
65542
|
const { androidOptedIn: androidOptedIn3, LABEL_IOS_SPLASH: LABEL_IOS_SPLASH2 } = await Promise.resolve().then(() => (init_splash(), splash_exports));
|
|
65146
65543
|
const iosYmlPath = iosProjectYml2(app);
|
|
65147
|
-
const iosYml =
|
|
65544
|
+
const iosYml = existsSync61(iosYmlPath) ? readFileSync73(iosYmlPath, "utf8") : "";
|
|
65148
65545
|
let optedIn = iosYml.includes(LABEL_IOS_SPLASH2);
|
|
65149
65546
|
if (!optedIn) {
|
|
65150
65547
|
const { androidManifestPath: androidManifestPath3 } = await Promise.resolve().then(() => (init_gen_native_config(), gen_native_config_exports));
|
|
@@ -65158,7 +65555,7 @@ async function nativeConfigAdvisories(app, configSource) {
|
|
|
65158
65555
|
}
|
|
65159
65556
|
function readConfigSource(dir) {
|
|
65160
65557
|
try {
|
|
65161
|
-
return
|
|
65558
|
+
return readFileSync73(join58(dir, "config.ts"), "utf8");
|
|
65162
65559
|
} catch {
|
|
65163
65560
|
return null;
|
|
65164
65561
|
}
|
|
@@ -65170,7 +65567,7 @@ function writePngFile(path2, base64) {
|
|
|
65170
65567
|
}
|
|
65171
65568
|
async function initFromRemoteTemplate(name, parentDir, template, c) {
|
|
65172
65569
|
const dir = resolve47(parentDir, name);
|
|
65173
|
-
if (
|
|
65570
|
+
if (existsSync61(join58(dir, "himalaya.content.json"))) {
|
|
65174
65571
|
throw new Error(`content package already exists at ${dir}`);
|
|
65175
65572
|
}
|
|
65176
65573
|
const r = await c.fetchTemplateSource(TEMPLATE_APP_PREFIX + template);
|
|
@@ -65213,7 +65610,7 @@ function symlinkDestinationIssue(dest) {
|
|
|
65213
65610
|
function restoreDestinationIssue(dest, force) {
|
|
65214
65611
|
const link = symlinkDestinationIssue(dest);
|
|
65215
65612
|
if (link) return link;
|
|
65216
|
-
if (!
|
|
65613
|
+
if (!existsSync61(dest)) return null;
|
|
65217
65614
|
if (!statSync17(dest).isDirectory()) {
|
|
65218
65615
|
return { error: `${dest} exists and is not a directory`, hint: "pass --out/--name to land somewhere else, or remove the file" };
|
|
65219
65616
|
}
|
|
@@ -65228,7 +65625,7 @@ function restoreDestinationIssue(dest, force) {
|
|
|
65228
65625
|
function isHimalayaMonorepoCheckout(start) {
|
|
65229
65626
|
let dir = resolve47(start);
|
|
65230
65627
|
for (; ; ) {
|
|
65231
|
-
if (
|
|
65628
|
+
if (existsSync61(join58(dir, "tools", "himi-cli", "src", "cli.ts")) && existsSync61(join58(dir, "core", "serve", "src", "server.ts"))) return true;
|
|
65232
65629
|
const parent = dirname32(dir);
|
|
65233
65630
|
if (parent === dir) return false;
|
|
65234
65631
|
dir = parent;
|
|
@@ -65271,7 +65668,7 @@ function materializeForPreview(appDir2, slug, displayName) {
|
|
|
65271
65668
|
Object.entries(files).map(([rel, body]) => [rel, rel === "himalaya.content.json" ? substituteIdentity(body, slug) : body])
|
|
65272
65669
|
);
|
|
65273
65670
|
const repoRoot2 = resolve47(fileURLToPath24(new URL("../../..", import.meta.url)));
|
|
65274
|
-
const root =
|
|
65671
|
+
const root = join58(repoRoot2, "node_modules", ".cache", "himi-template-preview");
|
|
65275
65672
|
const stillRunning = (pid) => {
|
|
65276
65673
|
try {
|
|
65277
65674
|
process.kill(pid, 0);
|
|
@@ -65285,12 +65682,12 @@ function materializeForPreview(appDir2, slug, displayName) {
|
|
|
65285
65682
|
if (!entry.isDirectory()) continue;
|
|
65286
65683
|
const pid = Number(entry.name.startsWith(`${slug}-`) ? entry.name.slice(slug.length + 1) : NaN);
|
|
65287
65684
|
if (Number.isInteger(pid) && pid > 0 && pid !== process.pid && !stillRunning(pid)) {
|
|
65288
|
-
rmSync14(
|
|
65685
|
+
rmSync14(join58(root, entry.name), { recursive: true, force: true });
|
|
65289
65686
|
}
|
|
65290
65687
|
}
|
|
65291
65688
|
} catch {
|
|
65292
65689
|
}
|
|
65293
|
-
const dest =
|
|
65690
|
+
const dest = join58(root, `${slug}-${process.pid}`);
|
|
65294
65691
|
rmSync14(dest, { recursive: true, force: true });
|
|
65295
65692
|
mkdirSync30(dest, { recursive: true });
|
|
65296
65693
|
materializeSource(forBuild, displayName, dest, slug);
|
|
@@ -65298,8 +65695,8 @@ function materializeForPreview(appDir2, slug, displayName) {
|
|
|
65298
65695
|
}
|
|
65299
65696
|
async function appId(dir) {
|
|
65300
65697
|
try {
|
|
65301
|
-
const { readFileSync:
|
|
65302
|
-
const m = JSON.parse(
|
|
65698
|
+
const { readFileSync: readFileSync74 } = await import("node:fs");
|
|
65699
|
+
const m = JSON.parse(readFileSync74(join58(dir, "himalaya.content.json"), "utf8"));
|
|
65303
65700
|
if (m.name) return m.name;
|
|
65304
65701
|
} catch {
|
|
65305
65702
|
}
|
|
@@ -65307,8 +65704,8 @@ async function appId(dir) {
|
|
|
65307
65704
|
}
|
|
65308
65705
|
async function contentVisibility(dir) {
|
|
65309
65706
|
try {
|
|
65310
|
-
const { readFileSync:
|
|
65311
|
-
const m = JSON.parse(
|
|
65707
|
+
const { readFileSync: readFileSync74 } = await import("node:fs");
|
|
65708
|
+
const m = JSON.parse(readFileSync74(join58(dir, "himalaya.content.json"), "utf8"));
|
|
65312
65709
|
if (m.visibility === "public" || m.visibility === "unlisted") return m.visibility;
|
|
65313
65710
|
} catch {
|
|
65314
65711
|
}
|
|
@@ -65532,7 +65929,7 @@ async function recordedReleaseForContentQuietly(dir, resolution, onDrift) {
|
|
|
65532
65929
|
try {
|
|
65533
65930
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
65534
65931
|
const bres = await buildContentForValidation2(dir, { resolution });
|
|
65535
|
-
out = mkdtempSync4(
|
|
65932
|
+
out = mkdtempSync4(join58(tmpdir5(), "himi-ux-record-"));
|
|
65536
65933
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
65537
65934
|
const outcome = await buildReleaseFromContent2(dir, out, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {}, collect: { lint: true } });
|
|
65538
65935
|
const releaseId = outcome.manifest.releaseId;
|
|
@@ -65710,7 +66107,7 @@ async function producedWidgetFamilies(dir) {
|
|
|
65710
66107
|
let js;
|
|
65711
66108
|
for (const candidate of [`${name}.bundle.js`, `${name}.js`, name]) {
|
|
65712
66109
|
try {
|
|
65713
|
-
js =
|
|
66110
|
+
js = readFileSync73(join58(outDir, candidate), "utf8");
|
|
65714
66111
|
break;
|
|
65715
66112
|
} catch {
|
|
65716
66113
|
}
|
|
@@ -65741,7 +66138,7 @@ async function producedWidgetFamilies(dir) {
|
|
|
65741
66138
|
}
|
|
65742
66139
|
return { families, source: "dist/bundles" };
|
|
65743
66140
|
}
|
|
65744
|
-
var boardOpen = (dir) =>
|
|
66141
|
+
var boardOpen = (dir) => existsSync61(join58(dir, ".himi", "studio", "index.html"));
|
|
65745
66142
|
var BOARD_REFRESHERS = /* @__PURE__ */ new Set(["render", "test", "validate", "build", "push", "icon", "site", "ux", "progress"]);
|
|
65746
66143
|
async function leaveForBoard(dir, record2, value) {
|
|
65747
66144
|
if (!boardOpen(dir)) return;
|
|
@@ -66129,7 +66526,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66129
66526
|
const sourceDir = resolve47(str6(flags["source-dir"]) ?? appDir2);
|
|
66130
66527
|
let meta;
|
|
66131
66528
|
try {
|
|
66132
|
-
meta = JSON.parse(
|
|
66529
|
+
meta = JSON.parse(readFileSync73(join58(sourceDir, TEMPLATE_META_FILE), "utf8"));
|
|
66133
66530
|
} catch {
|
|
66134
66531
|
io.error(JSON.stringify({ error: `no ${TEMPLATE_META_FILE} in ${sourceDir} \u2014 a template must declare { title, description, tags } to be published`, hint: `add ${TEMPLATE_META_FILE} next to himalaya.content.json (or pass --source-dir <dir>)` }));
|
|
66135
66532
|
return 2;
|
|
@@ -66139,7 +66536,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66139
66536
|
return 2;
|
|
66140
66537
|
}
|
|
66141
66538
|
try {
|
|
66142
|
-
const appearance = extractTemplateAppearance(JSON.parse(
|
|
66539
|
+
const appearance = extractTemplateAppearance(JSON.parse(readFileSync73(join58(sourceDir, "tokens.json"), "utf8")));
|
|
66143
66540
|
meta = { ...appearance, ...meta };
|
|
66144
66541
|
} catch {
|
|
66145
66542
|
}
|
|
@@ -66151,7 +66548,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66151
66548
|
const force = flags.force === true;
|
|
66152
66549
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
66153
66550
|
const bres = await buildContentForValidation2(buildDir, { resolution: resolutionFlag(flags) });
|
|
66154
|
-
const out = mkdtempSync4(
|
|
66551
|
+
const out = mkdtempSync4(join58(tmpdir5(), "himi-template-"));
|
|
66155
66552
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
66156
66553
|
const outcome = await buildReleaseFromContent2(buildDir, out, {
|
|
66157
66554
|
...hasWorkers ? { tier5Dir: bundleOutDir2(buildDir) } : {},
|
|
@@ -66204,7 +66601,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66204
66601
|
let iconHash;
|
|
66205
66602
|
if (iconPath) {
|
|
66206
66603
|
try {
|
|
66207
|
-
const bytes2 =
|
|
66604
|
+
const bytes2 = readFileSync73(iconPath);
|
|
66208
66605
|
payload.icon = bytes2.toString("base64");
|
|
66209
66606
|
iconHash = createHash27("sha256").update(bytes2).digest("hex");
|
|
66210
66607
|
} catch {
|
|
@@ -66437,7 +66834,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66437
66834
|
const { navIssues: navIssues2 } = await Promise.resolve().then(() => (init_nav_lint(), nav_lint_exports));
|
|
66438
66835
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
66439
66836
|
const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
|
|
66440
|
-
const out = mkdtempSync4(
|
|
66837
|
+
const out = mkdtempSync4(join58(tmpdir5(), "himi-validate-"));
|
|
66441
66838
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
66442
66839
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
66443
66840
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -66480,7 +66877,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66480
66877
|
const path2 = dpxSessionTokenPath();
|
|
66481
66878
|
let raw;
|
|
66482
66879
|
try {
|
|
66483
|
-
raw =
|
|
66880
|
+
raw = readFileSync73(path2, "utf8");
|
|
66484
66881
|
} catch {
|
|
66485
66882
|
throw new Error(`no DPX BO session at ${path2}; run dpx auth login, write dpx auth token to that path, then himi login --dpx --target bo`);
|
|
66486
66883
|
}
|
|
@@ -66600,13 +66997,13 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66600
66997
|
case "studio": {
|
|
66601
66998
|
const { openStudio: openStudio2 } = await Promise.resolve().then(() => (init_studio(), studio_exports));
|
|
66602
66999
|
const dir = contentDir(flags);
|
|
66603
|
-
if (!
|
|
67000
|
+
if (!existsSync61(join58(dir, "himalaya.content.json"))) {
|
|
66604
67001
|
io.error(JSON.stringify({ ok: false, error: "not_a_content_package", dir, hint: "run from the app directory (or pass --content <dir>) \u2014 the board reads that package's .himi/" }));
|
|
66605
67002
|
return 2;
|
|
66606
67003
|
}
|
|
66607
67004
|
if (pos[1] === "reel") {
|
|
66608
67005
|
const { buildReel: buildReel2 } = await Promise.resolve().then(() => (init_studio_reel(), studio_reel_exports));
|
|
66609
|
-
const out = resolve47(str6(flags.out) ??
|
|
67006
|
+
const out = resolve47(str6(flags.out) ?? join58(dir, ".himi", "making-of.html"));
|
|
66610
67007
|
const { html, plan } = buildReel2(dir);
|
|
66611
67008
|
mkdirSync30(dirname32(out), { recursive: true });
|
|
66612
67009
|
writeFileSync28(out, html);
|
|
@@ -66656,7 +67053,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66656
67053
|
const { appendProgress: appendProgress2, readProgress: readProgress2, summarizeProgress: summarizeProgress2, parseStep: parseStep2, notifyDesktop: notifyDesktop2, appLabel: appLabel2, journalPath: journalPath2, ProgressError: ProgressError2, JOURNEY_STEPS: JOURNEY_STEPS2 } = await Promise.resolve().then(() => (init_progress(), progress_exports));
|
|
66657
67054
|
const dir = contentDir(flags);
|
|
66658
67055
|
const journal = journalPath2(dir);
|
|
66659
|
-
const hint =
|
|
67056
|
+
const hint = existsSync61(join58(dir, "himalaya.content.json")) ? {} : { hint: "no himalaya.content.json here \u2014 run from the app directory (or pass --content <dir>) so the build board finds this journal" };
|
|
66660
67057
|
const message = pos.slice(1).join(" ").trim();
|
|
66661
67058
|
if (!message) {
|
|
66662
67059
|
if (flags.step !== void 0 || flags.image !== void 0 || flags.notify === true) {
|
|
@@ -66748,7 +67145,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66748
67145
|
case "test": {
|
|
66749
67146
|
const dir = contentDir(flags);
|
|
66750
67147
|
const structuredOutput = flags.json === true || io.isTTY !== true;
|
|
66751
|
-
if (
|
|
67148
|
+
if (existsSync61(join58(dir, "functions"))) {
|
|
66752
67149
|
const { invokeLocalFunction: invokeLocalFunction2, loadFunctionsApp: loadFunctionsApp2 } = await Promise.resolve().then(() => (init_functions(), functions_exports));
|
|
66753
67150
|
const loaded = await loadFunctionsApp2(dir);
|
|
66754
67151
|
const results = [];
|
|
@@ -66835,7 +67232,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66835
67232
|
}
|
|
66836
67233
|
}
|
|
66837
67234
|
const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
|
|
66838
|
-
const out = mkdtempSync4(
|
|
67235
|
+
const out = mkdtempSync4(join58(tmpdir5(), "himi-test-"));
|
|
66839
67236
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
66840
67237
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
66841
67238
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -66880,7 +67277,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
66880
67277
|
io.error(JSON.stringify({ error: `screen "${screen.screenId}" has no Tier-5 worker, so there is nothing for the browser loop to build` }));
|
|
66881
67278
|
return 2;
|
|
66882
67279
|
}
|
|
66883
|
-
const sources = collectWorkerSources2(
|
|
67280
|
+
const sources = collectWorkerSources2(join58(dir, "tier5-src"), screen.bundleName);
|
|
66884
67281
|
if (!sources) {
|
|
66885
67282
|
io.error(JSON.stringify({ error: `no worker source found at tier5-src/${screen.bundleName} \u2014 the browser loop compiles SOURCE, not the built bundle` }));
|
|
66886
67283
|
return 2;
|
|
@@ -67041,7 +67438,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67041
67438
|
const sp = await runShotsPass2({
|
|
67042
67439
|
descriptors: scopeDescriptors2(outcome.descriptors ?? [], pos.slice(1), invalidScreens),
|
|
67043
67440
|
tokens: outcome.tokens,
|
|
67044
|
-
outDir:
|
|
67441
|
+
outDir: join58(dir, ".himi", "shots"),
|
|
67045
67442
|
width: 390,
|
|
67046
67443
|
layers: { rules: shotRules, ...cmsSeed ? { cmsSeed } : {}, ...canned ? { canned: canned.byKey } : {} },
|
|
67047
67444
|
...budgetMs ? { budgetMs } : {},
|
|
@@ -67079,7 +67476,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67079
67476
|
releaseId: result.releaseId,
|
|
67080
67477
|
releasePayload: release,
|
|
67081
67478
|
descriptors: attestedDescriptors,
|
|
67082
|
-
screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""),
|
|
67479
|
+
screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""), join58(dir, ".himi", "shots", name)])),
|
|
67083
67480
|
coverage: {
|
|
67084
67481
|
screens: crawledScreens.size,
|
|
67085
67482
|
actionsDispatched: result.actions.exercised,
|
|
@@ -67169,7 +67566,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67169
67566
|
return 2;
|
|
67170
67567
|
}
|
|
67171
67568
|
try {
|
|
67172
|
-
const raw = stateArg.trim().startsWith("{") ? stateArg :
|
|
67569
|
+
const raw = stateArg.trim().startsWith("{") ? stateArg : readFileSync73(stateArg.replace(/^@/, ""), "utf8");
|
|
67173
67570
|
injectedState = JSON.parse(raw);
|
|
67174
67571
|
} catch (e) {
|
|
67175
67572
|
io.error(JSON.stringify({ error: `--state must be inline JSON or a path to a .json file \u2014 ${e.message}` }));
|
|
@@ -67184,7 +67581,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67184
67581
|
return 2;
|
|
67185
67582
|
}
|
|
67186
67583
|
try {
|
|
67187
|
-
const raw = inputArg.trim().startsWith("{") ? inputArg :
|
|
67584
|
+
const raw = inputArg.trim().startsWith("{") ? inputArg : readFileSync73(inputArg.replace(/^@/, ""), "utf8");
|
|
67188
67585
|
const parsed = JSON.parse(raw);
|
|
67189
67586
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("must be a JSON object");
|
|
67190
67587
|
injectedInput = parsed;
|
|
@@ -67233,7 +67630,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67233
67630
|
}
|
|
67234
67631
|
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
67235
67632
|
const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
|
|
67236
|
-
const out = mkdtempSync4(
|
|
67633
|
+
const out = mkdtempSync4(join58(tmpdir5(), "himi-render-"));
|
|
67237
67634
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
67238
67635
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
67239
67636
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -67247,7 +67644,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
67247
67644
|
const diagnostics = (outcome.lint ?? []).find((s) => s.screenId === screenId)?.issues ?? [];
|
|
67248
67645
|
let pngFile;
|
|
67249
67646
|
let attestationPngFile;
|
|
67250
|
-
const shotPath =
|
|
67647
|
+
const shotPath = join58(dir, ".himi", "shots", `${screenId}.png`);
|
|
67251
67648
|
const pngTarget = typeof flags.png === "string" ? str6(flags.png) : flags.png === true ? shotPath : void 0;
|
|
67252
67649
|
if (pngTarget && r.pngBase64) {
|
|
67253
67650
|
pngFile = writePngFile(pngTarget, r.pngBase64);
|
|
@@ -67583,7 +67980,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
67583
67980
|
io.error(JSON.stringify(linked));
|
|
67584
67981
|
return 1;
|
|
67585
67982
|
}
|
|
67586
|
-
if (
|
|
67983
|
+
if (existsSync61(dest)) {
|
|
67587
67984
|
if (!statSync17(dest).isDirectory()) {
|
|
67588
67985
|
io.error(JSON.stringify({
|
|
67589
67986
|
error: `${dest} exists and is not a directory`,
|
|
@@ -67596,7 +67993,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
67596
67993
|
io.error(JSON.stringify({ error: `${dest} already exists and is not empty`, hint: "pass --force to write into it anyway (merging, and naming what it keeps), --replace to restore exactly what was archived, or --out/--name to land somewhere else" }));
|
|
67597
67994
|
return 1;
|
|
67598
67995
|
}
|
|
67599
|
-
if (replace && occupied && !
|
|
67996
|
+
if (replace && occupied && !existsSync61(join58(dest, "himalaya.content.json"))) {
|
|
67600
67997
|
io.error(JSON.stringify({
|
|
67601
67998
|
error: `${dest} is not a content package \u2014 refusing to --replace it`,
|
|
67602
67999
|
hint: "--replace only clears a directory that holds himalaya.content.json. Check --out/--name, or pass --force to merge into it instead."
|
|
@@ -67735,7 +68132,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
67735
68132
|
const force = flags.force === true;
|
|
67736
68133
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
67737
68134
|
const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
|
|
67738
|
-
const out = mkdtempSync4(
|
|
68135
|
+
const out = mkdtempSync4(join58(tmpdir5(), "himi-push-"));
|
|
67739
68136
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
67740
68137
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
67741
68138
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -68256,7 +68653,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68256
68653
|
}
|
|
68257
68654
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
68258
68655
|
const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
|
|
68259
|
-
const built = mkdtempSync4(
|
|
68656
|
+
const built = mkdtempSync4(join58(tmpdir5(), "himi-pack-"));
|
|
68260
68657
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
68261
68658
|
const outcome = await buildReleaseFromContent2(dir, built, {
|
|
68262
68659
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -68459,7 +68856,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68459
68856
|
}));
|
|
68460
68857
|
return 1;
|
|
68461
68858
|
}
|
|
68462
|
-
const archive =
|
|
68859
|
+
const archive = readFileSync73(resolve47(file));
|
|
68463
68860
|
const result = await client2().createPackageShare({
|
|
68464
68861
|
app: opened.header.app,
|
|
68465
68862
|
releaseId: opened.header.releaseId,
|
|
@@ -68513,11 +68910,11 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68513
68910
|
const app = await appId(dir2);
|
|
68514
68911
|
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
68515
68912
|
const bres = await buildContentBundles2(dir2, { resolution: resolutionFlag(flags) });
|
|
68516
|
-
temp = mkdtempSync4(
|
|
68913
|
+
temp = mkdtempSync4(join58(tmpdir5(), "himi-run-build-"));
|
|
68517
68914
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
68518
68915
|
const initial = await buildReleaseFromContent2(dir2, temp, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir2) } : {} });
|
|
68519
68916
|
servedMissing = initial.missingBundles;
|
|
68520
|
-
source =
|
|
68917
|
+
source = join58(temp, app);
|
|
68521
68918
|
}
|
|
68522
68919
|
const chromeArg = str6(flags.chrome) ?? "preview";
|
|
68523
68920
|
if (chromeArg !== "preview" && chromeArg !== "app") {
|
|
@@ -68553,7 +68950,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68553
68950
|
if (!recordKit) return;
|
|
68554
68951
|
startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
68555
68952
|
const failure = record2(served2, { ok: true, at: startedAt });
|
|
68556
|
-
if (!recorded) io.error(JSON.stringify({ run: "run_record_skipped", message: `${failure ?? `${
|
|
68953
|
+
if (!recorded) io.error(JSON.stringify({ run: "run_record_skipped", message: `${failure ?? `${join58(dir, ".himi")} is not a real directory`}, so the build board will not frame this preview.` }));
|
|
68557
68954
|
await refreshBoard();
|
|
68558
68955
|
};
|
|
68559
68956
|
const retract = async () => {
|
|
@@ -68584,7 +68981,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68584
68981
|
}
|
|
68585
68982
|
const watchKit = watch2 ? await Promise.resolve().then(() => (init_run_watch(), run_watch_exports)) : null;
|
|
68586
68983
|
const bus = watchKit ? new watchKit.ReloadBus() : void 0;
|
|
68587
|
-
if (watch2) served = mkdtempSync4(
|
|
68984
|
+
if (watch2) served = mkdtempSync4(join58(tmpdir5(), "himi-run-served-"));
|
|
68588
68985
|
const running = await runPackage2(source, {
|
|
68589
68986
|
port,
|
|
68590
68987
|
chrome: chromeArg,
|
|
@@ -68596,15 +68993,15 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68596
68993
|
...recordKit ? { extraRoutes: (request) => recordKit.boardFile(dir, new URL(request.url).pathname) } : {},
|
|
68597
68994
|
...watchKit && served && bus ? { workDir: served, screenEvents: bus } : {}
|
|
68598
68995
|
});
|
|
68599
|
-
let
|
|
68996
|
+
let watcher2;
|
|
68600
68997
|
let rebuild;
|
|
68601
68998
|
let stopping = false;
|
|
68602
68999
|
try {
|
|
68603
69000
|
await announce(running);
|
|
68604
69001
|
if (watchKit && bus) {
|
|
68605
69002
|
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
68606
|
-
const live2 =
|
|
68607
|
-
const manifestOf = (tree) => JSON.parse(
|
|
69003
|
+
const live2 = join58(running.releaseRoot, running.app);
|
|
69004
|
+
const manifestOf = (tree) => JSON.parse(readFileSync73(join58(tree, "release-manifest.json"), "utf8"));
|
|
68608
69005
|
let current = manifestOf(live2);
|
|
68609
69006
|
const failed2 = async (message) => {
|
|
68610
69007
|
if (stopping) return;
|
|
@@ -68615,7 +69012,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68615
69012
|
};
|
|
68616
69013
|
rebuild = watchKit.serialize(async () => {
|
|
68617
69014
|
const t0 = Date.now();
|
|
68618
|
-
const next = mkdtempSync4(
|
|
69015
|
+
const next = mkdtempSync4(join58(tmpdir5(), "himi-run-build-"));
|
|
68619
69016
|
try {
|
|
68620
69017
|
const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
|
|
68621
69018
|
if (bres.compileErrors.length) {
|
|
@@ -68632,14 +69029,14 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68632
69029
|
return;
|
|
68633
69030
|
}
|
|
68634
69031
|
if (stopping) return;
|
|
68635
|
-
const fresh = manifestOf(
|
|
69032
|
+
const fresh = manifestOf(join58(next, running.app));
|
|
68636
69033
|
const diff = watchKit.diffReleases(current, fresh);
|
|
68637
69034
|
const retired = `${live2}.retired-${Date.now()}`;
|
|
68638
69035
|
renameSync6(live2, retired);
|
|
68639
69036
|
try {
|
|
68640
|
-
renameSync6(
|
|
69037
|
+
renameSync6(join58(next, running.app), live2);
|
|
68641
69038
|
} catch {
|
|
68642
|
-
cpSync3(
|
|
69039
|
+
cpSync3(join58(next, running.app), live2, { recursive: true });
|
|
68643
69040
|
}
|
|
68644
69041
|
rmSync14(retired, { recursive: true, force: true });
|
|
68645
69042
|
current = fresh;
|
|
@@ -68654,7 +69051,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68654
69051
|
rmSync14(next, { recursive: true, force: true });
|
|
68655
69052
|
}
|
|
68656
69053
|
});
|
|
68657
|
-
|
|
69054
|
+
watcher2 = watchKit.watchContent(dir, () => rebuild?.());
|
|
68658
69055
|
}
|
|
68659
69056
|
} catch (e) {
|
|
68660
69057
|
await retract().catch(() => {
|
|
@@ -68676,7 +69073,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
68676
69073
|
await new Promise((done) => {
|
|
68677
69074
|
const stop = async () => {
|
|
68678
69075
|
stopping = true;
|
|
68679
|
-
|
|
69076
|
+
watcher2?.close();
|
|
68680
69077
|
try {
|
|
68681
69078
|
await rebuild?.stop();
|
|
68682
69079
|
await retract();
|
|
@@ -69237,7 +69634,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
69237
69634
|
io.error(JSON.stringify({ error: `patch ${kind} needs --file`, usage: PATCH_USAGE }));
|
|
69238
69635
|
return 2;
|
|
69239
69636
|
}
|
|
69240
|
-
if (!
|
|
69637
|
+
if (!existsSync61(file)) {
|
|
69241
69638
|
io.error(JSON.stringify({ error: `no such file: ${file}` }));
|
|
69242
69639
|
return 2;
|
|
69243
69640
|
}
|
|
@@ -69293,7 +69690,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
69293
69690
|
lintNote: "`himi patch` sends a raw file. Nothing here built or linted your app \u2014 `himi push --only <selector>` is the same edit with the full lint gate in front of it."
|
|
69294
69691
|
};
|
|
69295
69692
|
if (kind === "tokens" || kind === "app-config") {
|
|
69296
|
-
const body =
|
|
69693
|
+
const body = readFileSync73(file, "utf8");
|
|
69297
69694
|
const patch2 = kind === "tokens" ? { tokens: body } : { appConfig: body };
|
|
69298
69695
|
return runReleasePatch({
|
|
69299
69696
|
...common,
|
|
@@ -69308,7 +69705,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
69308
69705
|
io.error(JSON.stringify({ error: "patch screen needs a <screenId>", usage: PATCH_USAGE }));
|
|
69309
69706
|
return 2;
|
|
69310
69707
|
}
|
|
69311
|
-
const descriptor =
|
|
69708
|
+
const descriptor = readFileSync73(file, "utf8");
|
|
69312
69709
|
try {
|
|
69313
69710
|
JSON.parse(descriptor);
|
|
69314
69711
|
} catch (e) {
|
|
@@ -69348,7 +69745,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
69348
69745
|
extra: { kind, screen: id, file: { path: file, bytes: Buffer.byteLength(descriptor, "utf8") } }
|
|
69349
69746
|
});
|
|
69350
69747
|
}
|
|
69351
|
-
const bytes2 =
|
|
69748
|
+
const bytes2 = readFileSync73(file);
|
|
69352
69749
|
const sha = createHash27("sha256").update(bytes2).digest("hex");
|
|
69353
69750
|
const forScreens = (str6(flags["for-screen"]) ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
69354
69751
|
if (flags["no-rebind"] !== void 0 && flags["no-rebind"] !== true) {
|
|
@@ -69492,7 +69889,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
69492
69889
|
}
|
|
69493
69890
|
let def;
|
|
69494
69891
|
try {
|
|
69495
|
-
const parsed = JSON.parse(arg.startsWith("@") ?
|
|
69892
|
+
const parsed = JSON.parse(arg.startsWith("@") ? readFileSync73(arg.slice(1), "utf8") : arg);
|
|
69496
69893
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
69497
69894
|
io.error(JSON.stringify({ error: "invalid_definition", problems: [`--definition must be a JSON object, got ${Array.isArray(parsed) ? "an array" : parsed === null ? "null" : typeof parsed}`] }));
|
|
69498
69895
|
return 2;
|
|
@@ -69956,7 +70353,7 @@ ${label2}`);
|
|
|
69956
70353
|
const platform = str6(flags.platform)?.split(",").map((p) => p.trim()).filter(Boolean);
|
|
69957
70354
|
{
|
|
69958
70355
|
const distDir = contentDir(flags);
|
|
69959
|
-
if (
|
|
70356
|
+
if (existsSync61(join58(distDir, "himalaya.content.json"))) {
|
|
69960
70357
|
const issues = await iconIssues(distDir, flags.strict === true, { requireDeclared: true, requireVerified: true });
|
|
69961
70358
|
const errors = issues.filter((i) => i.severity === "error");
|
|
69962
70359
|
for (const i of issues.filter((i2) => i2.severity === "warning")) {
|
|
@@ -70225,7 +70622,7 @@ ${label2}`);
|
|
|
70225
70622
|
const dpxPath = dpxSessionTokenPath();
|
|
70226
70623
|
let dpx;
|
|
70227
70624
|
try {
|
|
70228
|
-
dpx =
|
|
70625
|
+
dpx = readFileSync73(dpxPath, "utf8").trim();
|
|
70229
70626
|
} catch {
|
|
70230
70627
|
io.error(JSON.stringify({ error: `no dpx session at ${dpxPath} \u2014 run \`dpx auth login\` then \`dpx auth token > ${dpxPath}\` (dpx 2.x keeps its own state in ~/.dpx/auth.json and does NOT write the legacy session file), or omit --dpx` }));
|
|
70231
70628
|
return 1;
|
|
@@ -70627,7 +71024,7 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
|
|
|
70627
71024
|
const path2 = dpxSessionTokenPath();
|
|
70628
71025
|
let raw;
|
|
70629
71026
|
try {
|
|
70630
|
-
raw =
|
|
71027
|
+
raw = readFileSync73(path2, "utf8");
|
|
70631
71028
|
} catch {
|
|
70632
71029
|
io.error(JSON.stringify({ error: `no DPX BO session at ${path2}` }));
|
|
70633
71030
|
return 1;
|