@wix/himalaya-cli 0.1102.0 → 0.1104.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.mjs +301 -21
- package/guides/wix-business-context.md +22 -0
- package/package.json +2 -2
package/dist/cli.mjs
CHANGED
|
@@ -3979,7 +3979,11 @@ function isBrandable(repoRoot2, name) {
|
|
|
3979
3979
|
return false;
|
|
3980
3980
|
}
|
|
3981
3981
|
}
|
|
3982
|
-
|
|
3982
|
+
function isSiteShell(name) {
|
|
3983
|
+
assertKnownShell(name);
|
|
3984
|
+
return SITE_SHELLS.has(name);
|
|
3985
|
+
}
|
|
3986
|
+
var SHELL_NAMES2, DEFAULT_BRANDABLE_SHELL, HOME_REFRESH_ACTIONS, SITE_SHELLS;
|
|
3983
3987
|
var init_brandable_shells = __esm({
|
|
3984
3988
|
"src/brandable-shells.ts"() {
|
|
3985
3989
|
init_dist_jobs();
|
|
@@ -3988,6 +3992,7 @@ var init_brandable_shells = __esm({
|
|
|
3988
3992
|
HOME_REFRESH_ACTIONS = {
|
|
3989
3993
|
"branded-lite": "tier5.himiBrandedHome.refresh"
|
|
3990
3994
|
};
|
|
3995
|
+
SITE_SHELLS = /* @__PURE__ */ new Set(["brandy"]);
|
|
3991
3996
|
}
|
|
3992
3997
|
});
|
|
3993
3998
|
|
|
@@ -24713,6 +24718,7 @@ function shouldRevealError(args) {
|
|
|
24713
24718
|
var EMAIL_RE, URL_HOST_RE, INTEGER_RE, NUMBER_RE;
|
|
24714
24719
|
var init_validation = __esm({
|
|
24715
24720
|
"../../core/ts/src/validation.ts"() {
|
|
24721
|
+
"use strict";
|
|
24716
24722
|
EMAIL_RE = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}$/;
|
|
24717
24723
|
URL_HOST_RE = /^[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*(:[0-9]+)?$/;
|
|
24718
24724
|
INTEGER_RE = /^[+-]?[0-9]+$/;
|
|
@@ -29113,6 +29119,7 @@ function validateWorkerSubtree(raw, slotId, policy, actionCatalog) {
|
|
|
29113
29119
|
var WORKER_SUBTREE_CEILINGS, ID_PART, ACTION_ID;
|
|
29114
29120
|
var init_worker_subtree = __esm({
|
|
29115
29121
|
"../../core/ts/src/worker-subtree.ts"() {
|
|
29122
|
+
"use strict";
|
|
29116
29123
|
init_worker_subtree_safe_types_generated();
|
|
29117
29124
|
WORKER_SUBTREE_CEILINGS = Object.freeze({
|
|
29118
29125
|
maxEncodedBytes: 65536,
|
|
@@ -36813,8 +36820,86 @@ var init_app_registry_client = __esm({
|
|
|
36813
36820
|
});
|
|
36814
36821
|
|
|
36815
36822
|
// ../../core/ts/src/site-shell.ts
|
|
36823
|
+
function normalizeSiteOrigin(origin) {
|
|
36824
|
+
const raw = (typeof origin === "string" ? origin : "").trim();
|
|
36825
|
+
let url;
|
|
36826
|
+
try {
|
|
36827
|
+
url = new URL(raw);
|
|
36828
|
+
} catch {
|
|
36829
|
+
throw new Error(`site origin ${JSON.stringify(origin)} is not a URL`);
|
|
36830
|
+
}
|
|
36831
|
+
if (url.protocol !== "https:") {
|
|
36832
|
+
throw new Error(`site origin ${JSON.stringify(origin)} must be https`);
|
|
36833
|
+
}
|
|
36834
|
+
if (url.username || url.password) {
|
|
36835
|
+
throw new Error(`site origin ${JSON.stringify(origin)} must not carry credentials`);
|
|
36836
|
+
}
|
|
36837
|
+
if (url.search || url.hash) {
|
|
36838
|
+
throw new Error(`site origin ${JSON.stringify(origin)} must not carry a query or fragment`);
|
|
36839
|
+
}
|
|
36840
|
+
const path2 = url.pathname.replace(/\/+$/, "");
|
|
36841
|
+
return `https://${url.host.toLowerCase()}${path2}`;
|
|
36842
|
+
}
|
|
36843
|
+
function sitePageUrl(origin, path2) {
|
|
36844
|
+
const base = normalizeSiteOrigin(origin);
|
|
36845
|
+
const raw = (typeof path2 === "string" ? path2 : "").trim();
|
|
36846
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(raw) || raw.startsWith("//")) {
|
|
36847
|
+
throw new Error(`site page path ${JSON.stringify(path2)} must be relative to the site`);
|
|
36848
|
+
}
|
|
36849
|
+
if (raw.includes("\\")) {
|
|
36850
|
+
throw new Error(`site page path ${JSON.stringify(path2)} must not contain a backslash`);
|
|
36851
|
+
}
|
|
36852
|
+
const trimmed = raw.replace(/^\/+/, "");
|
|
36853
|
+
const joined = trimmed ? `${base}/${trimmed}` : base;
|
|
36854
|
+
const resolved2 = new URL(joined);
|
|
36855
|
+
const baseUrl = new URL(base);
|
|
36856
|
+
const basePath = baseUrl.pathname.replace(/\/+$/, "");
|
|
36857
|
+
const inside2 = resolved2.pathname === basePath || resolved2.pathname === `${basePath}/` || resolved2.pathname.startsWith(`${basePath}/`);
|
|
36858
|
+
if (resolved2.host !== baseUrl.host || !inside2) {
|
|
36859
|
+
throw new Error(`site page path ${JSON.stringify(path2)} resolves outside the site`);
|
|
36860
|
+
}
|
|
36861
|
+
return joined;
|
|
36862
|
+
}
|
|
36863
|
+
function siteScreenId(page) {
|
|
36864
|
+
return `${SITE_SCREEN_PREFIX}${page.id}`;
|
|
36865
|
+
}
|
|
36866
|
+
function assertSitePage(page) {
|
|
36867
|
+
if (!page || typeof page.id !== "string" || !PAGE_ID.test(page.id)) {
|
|
36868
|
+
throw new Error(`site page id ${JSON.stringify(page?.id)} must match ${PAGE_ID}`);
|
|
36869
|
+
}
|
|
36870
|
+
if (siteScreenId(page) === SITE_PAGE_SCREEN_ID) {
|
|
36871
|
+
throw new Error(`site page id "page" is reserved for the ${SITE_PAGE_SCREEN_ID} fallback screen`);
|
|
36872
|
+
}
|
|
36873
|
+
if (typeof page.title !== "string" || !page.title.trim()) {
|
|
36874
|
+
throw new Error(`site page ${page.id} needs a title`);
|
|
36875
|
+
}
|
|
36876
|
+
}
|
|
36877
|
+
function assertSiteShellConfig(site) {
|
|
36878
|
+
normalizeSiteOrigin(site.origin);
|
|
36879
|
+
if (site.kind !== "wix" && site.kind !== "base44") {
|
|
36880
|
+
throw new Error(`site kind ${JSON.stringify(site.kind)} must be "wix" or "base44"`);
|
|
36881
|
+
}
|
|
36882
|
+
if (!Array.isArray(site.pages) || site.pages.length === 0) {
|
|
36883
|
+
throw new Error("a site shell needs at least one page");
|
|
36884
|
+
}
|
|
36885
|
+
const seen = /* @__PURE__ */ new Set();
|
|
36886
|
+
for (const page of site.pages) {
|
|
36887
|
+
assertSitePage(page);
|
|
36888
|
+
if (seen.has(page.id)) throw new Error(`site page id ${page.id} is declared twice`);
|
|
36889
|
+
seen.add(page.id);
|
|
36890
|
+
sitePageUrl(site.origin, page.path);
|
|
36891
|
+
}
|
|
36892
|
+
if (!site.pages.some((page) => (page.placement ?? "tab") === "tab")) {
|
|
36893
|
+
throw new Error('a site shell needs at least one page with placement "tab"');
|
|
36894
|
+
}
|
|
36895
|
+
}
|
|
36896
|
+
var SITE_SHELL_MAX_TABS, SITE_SCREEN_PREFIX, SITE_PAGE_SCREEN_ID, PAGE_ID;
|
|
36816
36897
|
var init_site_shell = __esm({
|
|
36817
36898
|
"../../core/ts/src/site-shell.ts"() {
|
|
36899
|
+
SITE_SHELL_MAX_TABS = 4;
|
|
36900
|
+
SITE_SCREEN_PREFIX = "site_";
|
|
36901
|
+
SITE_PAGE_SCREEN_ID = "site_page";
|
|
36902
|
+
PAGE_ID = /^[a-z0-9_]+$/;
|
|
36818
36903
|
}
|
|
36819
36904
|
});
|
|
36820
36905
|
|
|
@@ -60017,7 +60102,7 @@ function classifyPageRole(url, title, _nav = "") {
|
|
|
60017
60102
|
if (/\b(blog|journal|news|posts?|ebooks?|insight)\b/.test(hay)) return "blog";
|
|
60018
60103
|
if (/\b(about|story|our-story)\b/.test(hay)) return "about";
|
|
60019
60104
|
if (/\b(contact|find-us)\b/.test(hay)) return "contact";
|
|
60020
|
-
if (/\b(
|
|
60105
|
+
if (/\b(events?|meetups?|workshops?)\b/.test(hay)) return "events";
|
|
60021
60106
|
if (/\b(gallery|portfolio|work)\b/.test(hay)) return "gallery";
|
|
60022
60107
|
return "other";
|
|
60023
60108
|
}
|
|
@@ -60380,11 +60465,11 @@ function parsePublishedHtml(html) {
|
|
|
60380
60465
|
PAGE_ENTRY_RE.lastIndex = 0;
|
|
60381
60466
|
let m;
|
|
60382
60467
|
while (m = PAGE_ENTRY_RE.exec(html)) {
|
|
60383
|
-
const
|
|
60384
|
-
if (seen.has(
|
|
60385
|
-
seen.add(
|
|
60468
|
+
const pageId2 = m[1];
|
|
60469
|
+
if (seen.has(pageId2) || pages.length >= 80) continue;
|
|
60470
|
+
seen.add(pageId2);
|
|
60386
60471
|
pages.push({
|
|
60387
|
-
pageId,
|
|
60472
|
+
pageId: pageId2,
|
|
60388
60473
|
title: unescapeJsonString(m[2] ?? ""),
|
|
60389
60474
|
slug: unescapeJsonString(m[3] ?? "")
|
|
60390
60475
|
});
|
|
@@ -60679,7 +60764,7 @@ function veloHintFromEval(evaled, page) {
|
|
|
60679
60764
|
if (!v) return void 0;
|
|
60680
60765
|
const wixRendered = !!v.wixRendered;
|
|
60681
60766
|
const pageModuleUrls = (v.pageModuleUrls ?? []).filter(Boolean).slice(0, 16);
|
|
60682
|
-
const
|
|
60767
|
+
const pageId2 = (v.pageId || page.pageId || "").trim() || void 0;
|
|
60683
60768
|
const hasCode = pageModuleUrls.length > 0 || !!v.gridAppId || (v.wixCodeFeatures ?? []).length > 0;
|
|
60684
60769
|
return {
|
|
60685
60770
|
wixRendered,
|
|
@@ -60688,7 +60773,7 @@ function veloHintFromEval(evaled, page) {
|
|
|
60688
60773
|
wixCodeFeatures: (v.wixCodeFeatures ?? []).slice(0, 24),
|
|
60689
60774
|
pageModuleUrls,
|
|
60690
60775
|
httpFunctionHints: (v.httpFunctionHints ?? []).filter(Boolean).slice(0, 16),
|
|
60691
|
-
pages: [{ url: page.url, title: page.title, hasCode: wixRendered && hasCode, ...
|
|
60776
|
+
pages: [{ url: page.url, title: page.title, hasCode: wixRendered && hasCode, ...pageId2 ? { pageId: pageId2 } : {} }]
|
|
60692
60777
|
};
|
|
60693
60778
|
}
|
|
60694
60779
|
function pageIdFromVeloPath(path2) {
|
|
@@ -62811,13 +62896,15 @@ function mergeCustomerOwned(committed, overlay) {
|
|
|
62811
62896
|
"locale",
|
|
62812
62897
|
"wix",
|
|
62813
62898
|
"copy",
|
|
62814
|
-
"faq"
|
|
62899
|
+
"faq",
|
|
62900
|
+
"site"
|
|
62815
62901
|
];
|
|
62816
62902
|
const customer = {};
|
|
62817
62903
|
for (const key2 of CUSTOMER_OWNED) {
|
|
62818
62904
|
const value = overlay[key2];
|
|
62819
62905
|
if (value !== void 0) customer[key2] = value;
|
|
62820
62906
|
}
|
|
62907
|
+
if (committed.site === void 0) delete customer.site;
|
|
62821
62908
|
const overlayBranding = { ...customer.branding ?? {} };
|
|
62822
62909
|
delete overlayBranding.appIconPath;
|
|
62823
62910
|
delete overlayBranding.fonts;
|
|
@@ -62969,7 +63056,7 @@ async function applyOverlays(input) {
|
|
|
62969
63056
|
const committedSite = existsSync64(committedPath) ? JSON.parse(readFileSync76(committedPath, "utf8")).site : void 0;
|
|
62970
63057
|
if (committedSite !== void 0 && overlay.site === void 0) {
|
|
62971
63058
|
throw new Error(
|
|
62972
|
-
`shell "${shell}" is a site shell: its contract names the customer's website (a \`site\` block),
|
|
63059
|
+
`shell "${shell}" is a site shell: its contract names the customer's website (a \`site\` block), and this overlay has none. Re-run \`himi site analyze --url <site> --shell ${shell}\` to derive the site's page map (edit \`site.pages\` in provisioning.overlay.json if needed), then --apply.`
|
|
62973
63060
|
);
|
|
62974
63061
|
}
|
|
62975
63062
|
const packageDir = dirname35(resolve49(input.overlayPath));
|
|
@@ -63175,6 +63262,170 @@ var init_apply2 = __esm({
|
|
|
63175
63262
|
}
|
|
63176
63263
|
});
|
|
63177
63264
|
|
|
63265
|
+
// src/site-analyze/site-shell-derive.ts
|
|
63266
|
+
function isSystemPage(path2, title) {
|
|
63267
|
+
const last = path2.split("/").filter(Boolean).pop() ?? "";
|
|
63268
|
+
return SYSTEM_SEGMENT.test(last) || SYSTEM_TITLE.test(title);
|
|
63269
|
+
}
|
|
63270
|
+
function boundedTitle(s) {
|
|
63271
|
+
const t = oneLine2(s).replace(/\s*\(new\)\s*$/i, "");
|
|
63272
|
+
return t.length <= SITE_PAGE_TITLE_MAX ? t : t.slice(0, SITE_PAGE_TITLE_MAX).trimEnd();
|
|
63273
|
+
}
|
|
63274
|
+
function pathOnSite(origin, url) {
|
|
63275
|
+
let u;
|
|
63276
|
+
let base;
|
|
63277
|
+
try {
|
|
63278
|
+
u = new URL(url);
|
|
63279
|
+
base = new URL(origin);
|
|
63280
|
+
} catch {
|
|
63281
|
+
return null;
|
|
63282
|
+
}
|
|
63283
|
+
const host = (h) => h.toLowerCase().replace(/^www\./, "");
|
|
63284
|
+
if (host(u.host) !== host(base.host)) return null;
|
|
63285
|
+
const basePath = base.pathname.replace(/\/+$/, "");
|
|
63286
|
+
const p = u.pathname.replace(/\/+$/, "");
|
|
63287
|
+
if (p !== basePath && !p.startsWith(`${basePath}/`)) return null;
|
|
63288
|
+
return p.slice(basePath.length) || "/";
|
|
63289
|
+
}
|
|
63290
|
+
function isHomePage(page, mainPageId) {
|
|
63291
|
+
return mainPageId !== void 0 && page.pageId === mainPageId || !page.slug || page.slug === "home";
|
|
63292
|
+
}
|
|
63293
|
+
function pageId(c, used) {
|
|
63294
|
+
const fromPath = (c.path.split("/").filter(Boolean).pop() ?? "").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
63295
|
+
const base = c.role !== "other" && c.role !== "home" && !used.has(c.role) ? c.role : fromPath || "page_1";
|
|
63296
|
+
let id = base === "page" ? "page_1" : base;
|
|
63297
|
+
for (let n = 2; used.has(id); n++) id = `${base}_${n}`;
|
|
63298
|
+
used.add(id);
|
|
63299
|
+
return id;
|
|
63300
|
+
}
|
|
63301
|
+
function deriveSiteShell(input) {
|
|
63302
|
+
const origin = normalizeSiteOrigin(input.siteUrl);
|
|
63303
|
+
const notes = [];
|
|
63304
|
+
const published = input.look.sitePages ?? [];
|
|
63305
|
+
const mainPageId = input.look.mainPageId;
|
|
63306
|
+
const candidates = [];
|
|
63307
|
+
const seenPaths = /* @__PURE__ */ new Set(["/"]);
|
|
63308
|
+
let systemDropped = 0;
|
|
63309
|
+
const add = (title, path2, url) => {
|
|
63310
|
+
if (seenPaths.has(path2) || !title) return;
|
|
63311
|
+
if (isSystemPage(path2, title)) {
|
|
63312
|
+
seenPaths.add(path2);
|
|
63313
|
+
systemDropped++;
|
|
63314
|
+
return;
|
|
63315
|
+
}
|
|
63316
|
+
seenPaths.add(path2);
|
|
63317
|
+
candidates.push({ title: boundedTitle(title), path: path2, role: classifyPageRole(url, title) });
|
|
63318
|
+
};
|
|
63319
|
+
const navLinks = input.look.navLinks ?? [];
|
|
63320
|
+
let homeTitle = "Home";
|
|
63321
|
+
if (navLinks.length) {
|
|
63322
|
+
for (const link of navLinks) {
|
|
63323
|
+
const path2 = pathOnSite(origin, link.href);
|
|
63324
|
+
if (path2 === null) continue;
|
|
63325
|
+
if (path2 === "/" && homeTitle === "Home" && HOME_WORD.test(oneLine2(link.label))) homeTitle = boundedTitle(link.label);
|
|
63326
|
+
add(link.label, path2, link.href);
|
|
63327
|
+
}
|
|
63328
|
+
} else if (input.look.navLabels.length && published.length) {
|
|
63329
|
+
const byTitle = new Map(published.map((p) => [oneLine2(p.title).toLowerCase(), p]));
|
|
63330
|
+
for (const label2 of input.look.navLabels) {
|
|
63331
|
+
if (homeTitle === "Home" && HOME_WORD.test(oneLine2(label2))) homeTitle = boundedTitle(label2);
|
|
63332
|
+
const page = byTitle.get(oneLine2(label2).toLowerCase());
|
|
63333
|
+
const path2 = page?.url ? pathOnSite(origin, page.url) : null;
|
|
63334
|
+
if (page && path2 !== null) add(label2, path2, page.url);
|
|
63335
|
+
}
|
|
63336
|
+
}
|
|
63337
|
+
if (!candidates.length && navLinks.length) {
|
|
63338
|
+
notes.push("site pages: the site's header menu links only to its home page, so the map has only Home \u2014 add the site's pages to `site.pages` before --apply.");
|
|
63339
|
+
} else if (!candidates.length) {
|
|
63340
|
+
for (const page of published) {
|
|
63341
|
+
if (isHomePage(page, mainPageId) || !page.url) continue;
|
|
63342
|
+
const path2 = pathOnSite(origin, page.url);
|
|
63343
|
+
if (path2 !== null) add(page.title, path2, page.url);
|
|
63344
|
+
}
|
|
63345
|
+
if (published.length) {
|
|
63346
|
+
notes.push("site pages: no header menu was crawled, so pages follow the published page list \u2014 reorder them in `site.pages` if the site's menu differs.");
|
|
63347
|
+
}
|
|
63348
|
+
}
|
|
63349
|
+
if (systemDropped) notes.push(`site pages: left out ${systemDropped} flow/utility page(s) (thank-you, popups, item templates, members-area pages).`);
|
|
63350
|
+
const dropped = Math.max(0, candidates.length - (DERIVED_SITE_MAX_PAGES - 1));
|
|
63351
|
+
const kept = candidates.slice(0, DERIVED_SITE_MAX_PAGES - 1);
|
|
63352
|
+
if (dropped) notes.push(`site pages: kept the first ${DERIVED_SITE_MAX_PAGES} pages; ${dropped} more are reachable from the site's own links but have no native row.`);
|
|
63353
|
+
const used = /* @__PURE__ */ new Set(["home"]);
|
|
63354
|
+
const placed = kept.map((c) => ({ c, id: pageId(c, used), placement: "drawer" }));
|
|
63355
|
+
let tabs = 1;
|
|
63356
|
+
for (const p of placed) {
|
|
63357
|
+
if (p.c.role === "members") p.placement = "overflow";
|
|
63358
|
+
else if (TAB_ROLES.has(p.c.role) && tabs < SITE_SHELL_MAX_TABS) {
|
|
63359
|
+
p.placement = "tab";
|
|
63360
|
+
tabs++;
|
|
63361
|
+
}
|
|
63362
|
+
}
|
|
63363
|
+
if (tabs < 2) {
|
|
63364
|
+
for (const p of placed) {
|
|
63365
|
+
if (tabs >= SITE_SHELL_MAX_TABS) break;
|
|
63366
|
+
if (p.placement === "drawer") {
|
|
63367
|
+
p.placement = "tab";
|
|
63368
|
+
tabs++;
|
|
63369
|
+
}
|
|
63370
|
+
}
|
|
63371
|
+
}
|
|
63372
|
+
const pages = [
|
|
63373
|
+
{ id: "home", title: homeTitle, path: "/", icon: "home" },
|
|
63374
|
+
...placed.map(({ c, id, placement }) => ({
|
|
63375
|
+
id,
|
|
63376
|
+
title: c.title,
|
|
63377
|
+
path: c.path,
|
|
63378
|
+
icon: ROLE_ICON[c.role],
|
|
63379
|
+
...placement === "tab" ? {} : { placement }
|
|
63380
|
+
}))
|
|
63381
|
+
];
|
|
63382
|
+
if (!published.length && !navLinks.length) {
|
|
63383
|
+
notes.push("site pages: the analysis read no page list, so the map has only Home \u2014 add the site's pages to `site.pages` before --apply.");
|
|
63384
|
+
}
|
|
63385
|
+
const site = {
|
|
63386
|
+
origin,
|
|
63387
|
+
kind: "wix",
|
|
63388
|
+
pages,
|
|
63389
|
+
// Hidden by default — the product decision for the site shell (RFC 0062 §6); the owner can
|
|
63390
|
+
// turn any of them back on here, and the flags ride the OTA descriptor.
|
|
63391
|
+
chrome: { hideSiteHeader: true, hideSiteFooter: true, hideWixAds: true }
|
|
63392
|
+
};
|
|
63393
|
+
assertSiteShellConfig(site);
|
|
63394
|
+
const tabTitles = pages.filter((p) => (p.placement ?? "tab") === "tab").map((p) => p.title);
|
|
63395
|
+
notes.unshift(`site pages: ${pages.length} derived \u2014 tabs ${tabTitles.join(", ")}; edit \`site.pages\` in provisioning.overlay.json to change them.`);
|
|
63396
|
+
return { site, notes };
|
|
63397
|
+
}
|
|
63398
|
+
var DERIVED_SITE_MAX_PAGES, SITE_PAGE_TITLE_MAX, ROLE_ICON, TAB_ROLES, SYSTEM_SEGMENT, SYSTEM_TITLE, HOME_WORD, oneLine2;
|
|
63399
|
+
var init_site_shell_derive = __esm({
|
|
63400
|
+
"src/site-analyze/site-shell-derive.ts"() {
|
|
63401
|
+
init_site_shell();
|
|
63402
|
+
init_traits();
|
|
63403
|
+
DERIVED_SITE_MAX_PAGES = 10;
|
|
63404
|
+
SITE_PAGE_TITLE_MAX = 40;
|
|
63405
|
+
ROLE_ICON = {
|
|
63406
|
+
home: "home",
|
|
63407
|
+
shop: "bag",
|
|
63408
|
+
book: "calendar",
|
|
63409
|
+
menu: "list",
|
|
63410
|
+
blog: "newspaper",
|
|
63411
|
+
about: "info",
|
|
63412
|
+
contact: "mail",
|
|
63413
|
+
events: "ticket",
|
|
63414
|
+
gallery: "photo",
|
|
63415
|
+
plans: "tag",
|
|
63416
|
+
faq: "help",
|
|
63417
|
+
library: "book",
|
|
63418
|
+
members: "person",
|
|
63419
|
+
other: "globe"
|
|
63420
|
+
};
|
|
63421
|
+
TAB_ROLES = /* @__PURE__ */ new Set(["shop", "book", "menu", "events", "plans", "blog", "gallery", "library"]);
|
|
63422
|
+
SYSTEM_SEGMENT = /^(popup-.*|lightbox.*|.*thank-?you.*|checkout|cart(-page)?|payment-request(-page)?|expired-reset-link|access-restricted|reservation|(event|experience|reservation|order|item)-details|(product|service|category|group|project|collection|reviews-collection|donation-thank-you)-page|post|project|collection|group|booking-(form|calendar)|plan-customization|notifications?|followers?|following|my-(?!account$)[a-z-]+|profile|search(-results)?|blank(-\d+)?|404)$/i;
|
|
63423
|
+
SYSTEM_TITLE = /\b(thank you|\(popup\)|leave (a )?review|notifications|followers|side cart|order error|pending approval|my (rewards|subscriptions|bookings|orders|groups|wallet))\b|\b(group|service|product|project|collection|category|cart|payment request) pages?$|\b(event|experience|reservation|item) details\b/i;
|
|
63424
|
+
HOME_WORD = /^(home|home ?page|main|start|accueil|inicio|início|startseite|home ?sweet ?home|בית|דף הבית|ראשי|الرئيسية|ホーム|首页|홈)$/i;
|
|
63425
|
+
oneLine2 = (s) => s.replace(/[\u0000-\u001F\u007F\s]+/g, " ").trim();
|
|
63426
|
+
}
|
|
63427
|
+
});
|
|
63428
|
+
|
|
63178
63429
|
// ../../node_modules/tldts/dist/cjs/index.js
|
|
63179
63430
|
var require_cjs = __commonJS({
|
|
63180
63431
|
"../../node_modules/tldts/dist/cjs/index.js"(exports) {
|
|
@@ -66298,6 +66549,7 @@ async function createPlaywrightBrowser(load = () => import("playwright"), siteFe
|
|
|
66298
66549
|
const seen = /* @__PURE__ */ new Set();
|
|
66299
66550
|
const pages = [];
|
|
66300
66551
|
const navAll = [];
|
|
66552
|
+
const navLinksAll = [];
|
|
66301
66553
|
const veloHints = [];
|
|
66302
66554
|
let htmlLang;
|
|
66303
66555
|
let faviconUrl;
|
|
@@ -66321,7 +66573,7 @@ async function createPlaywrightBrowser(load = () => import("playwright"), siteFe
|
|
|
66321
66573
|
} catch {
|
|
66322
66574
|
continue;
|
|
66323
66575
|
}
|
|
66324
|
-
let
|
|
66576
|
+
let pageId2 = evaled.velo?.pageId || void 0;
|
|
66325
66577
|
let publishedTitle = "";
|
|
66326
66578
|
try {
|
|
66327
66579
|
const html = await page.content();
|
|
@@ -66333,7 +66585,7 @@ async function createPlaywrightBrowser(load = () => import("playwright"), siteFe
|
|
|
66333
66585
|
}
|
|
66334
66586
|
if (pub.pages.length && !sitePages.length) sitePages = pub.pages;
|
|
66335
66587
|
const hit = matchPublishedPage(url, title, pub.pages, pub.mainPageId);
|
|
66336
|
-
if (!
|
|
66588
|
+
if (!pageId2) pageId2 = hit?.pageId;
|
|
66337
66589
|
publishedTitle = hit?.title ?? "";
|
|
66338
66590
|
if (!seededFromMap && pub.pages.length) {
|
|
66339
66591
|
seededFromMap = true;
|
|
@@ -66365,13 +66617,17 @@ async function createPlaywrightBrowser(load = () => import("playwright"), siteFe
|
|
|
66365
66617
|
ctas: ctasOf(evaled.buttons)
|
|
66366
66618
|
},
|
|
66367
66619
|
screenshotLocal: `evidence/pages/${filename}`,
|
|
66368
|
-
...
|
|
66620
|
+
...pageId2 ? { pageId: pageId2 } : {},
|
|
66369
66621
|
...copyFromEval(evaled)
|
|
66370
66622
|
});
|
|
66371
|
-
const hint = veloHintFromEval(evaled, { url, title, pageId });
|
|
66623
|
+
const hint = veloHintFromEval(evaled, { url, title, pageId: pageId2 });
|
|
66372
66624
|
if (hint) veloHints.push(hint);
|
|
66373
66625
|
if (!htmlLang && evaled.htmlLang) htmlLang = evaled.htmlLang;
|
|
66374
66626
|
for (const n of evaled.nav) if (!navAll.includes(n)) navAll.push(n);
|
|
66627
|
+
for (const l of evaled.navLinks ?? []) {
|
|
66628
|
+
const key2 = `${l.label}\0${l.href.split("#")[0]}`;
|
|
66629
|
+
if (navLinksAll.length < 24 && !navLinksAll.some((x) => `${x.label}\0${x.href.split("#")[0]}` === key2)) navLinksAll.push(l);
|
|
66630
|
+
}
|
|
66375
66631
|
if (!faviconUrl && evaled.velo?.favicon && !isGenericWixFavicon(evaled.velo.favicon)) {
|
|
66376
66632
|
faviconUrl = evaled.velo.favicon;
|
|
66377
66633
|
}
|
|
@@ -66393,6 +66649,7 @@ async function createPlaywrightBrowser(load = () => import("playwright"), siteFe
|
|
|
66393
66649
|
return {
|
|
66394
66650
|
pages,
|
|
66395
66651
|
navLabels: navAll,
|
|
66652
|
+
...navLinksAll.length ? { navLinks: navLinksAll } : {},
|
|
66396
66653
|
theme: Object.keys(wst).length ? {
|
|
66397
66654
|
colors: Object.fromEntries(Object.entries(wst).filter(([k]) => k.includes("color"))),
|
|
66398
66655
|
fonts: Object.fromEntries(Object.entries(wst).filter(([k]) => k.includes("font")))
|
|
@@ -66479,8 +66736,13 @@ var init_crawl_look = __esm({
|
|
|
66479
66736
|
if (probe.parentNode) probe.parentNode.removeChild(probe);
|
|
66480
66737
|
} catch (e3) {}
|
|
66481
66738
|
const txt = (el) => String((el && el.textContent) || "").replace(/\\s+/g, " ").trim();
|
|
66482
|
-
const
|
|
66483
|
-
|
|
66739
|
+
const navAnchors = Array.from(document.querySelectorAll("nav a, header a, [role=navigation] a"));
|
|
66740
|
+
const nav = navAnchors.map((a) => (a.textContent || "").trim()).filter(Boolean).slice(0, 24);
|
|
66741
|
+
// WHERE each label goes \u2014 a site shell orders its tabs by these (RFC 0062). a.href is
|
|
66742
|
+
// already absolute; an anchor with no text or no href is not a page link.
|
|
66743
|
+
const navLinks = navAnchors
|
|
66744
|
+
.map((a) => ({ label: txt(a), href: String(a.href || "") }))
|
|
66745
|
+
.filter((l) => l.label && /^https?:/.test(l.href)).slice(0, 24);
|
|
66484
66746
|
const headings = Array.from(document.querySelectorAll("h1,h2")).map((h) => (h.textContent || "").trim()).filter(Boolean).slice(0, 12);
|
|
66485
66747
|
const hero = ((document.querySelector("h1") && document.querySelector("h1").textContent) || "").trim();
|
|
66486
66748
|
|
|
@@ -66605,7 +66867,7 @@ var init_crawl_look = __esm({
|
|
|
66605
66867
|
if (pid) velo.pageId = pid[1];
|
|
66606
66868
|
}
|
|
66607
66869
|
} catch (e4) {}
|
|
66608
|
-
return { wst, nav, headings, hero, imgs, hrefs, buttons, html, htmlLang, velo, sections, ctaLabels, faq, testimonials, about, meta };
|
|
66870
|
+
return { wst, nav, navLinks, headings, hero, imgs, hrefs, buttons, html, htmlLang, velo, sections, ctaLabels, faq, testimonials, about, meta };
|
|
66609
66871
|
})()`;
|
|
66610
66872
|
CAP4 = {
|
|
66611
66873
|
heading: 120,
|
|
@@ -67271,6 +67533,7 @@ function ownerSiteFor(opts, env = process.env) {
|
|
|
67271
67533
|
return env.WIX_SITE_ID?.trim() || void 0;
|
|
67272
67534
|
}
|
|
67273
67535
|
async function runSiteAnalyze(opts) {
|
|
67536
|
+
if (opts.shell !== void 0) assertKnownShell(opts.shell);
|
|
67274
67537
|
if (!opts.clientId?.trim()) {
|
|
67275
67538
|
if (opts.apply) throw Object.assign(new Error(APPLY_NEEDS_CLIENT), { exit: 2 });
|
|
67276
67539
|
if (opts.redirectUri?.trim()) throw Object.assign(new Error(REDIRECT_NEEDS_CLIENT), { exit: 2 });
|
|
@@ -67303,6 +67566,18 @@ async function runSiteAnalyze(opts) {
|
|
|
67303
67566
|
{ clientId: opts.clientId, siteUrl: opts.siteUrl, msid, redirectUri: opts.redirectUri },
|
|
67304
67567
|
ports
|
|
67305
67568
|
);
|
|
67569
|
+
if (opts.shell !== void 0 && isSiteShell(opts.shell)) {
|
|
67570
|
+
try {
|
|
67571
|
+
const derived = deriveSiteShell({ siteUrl: result.book.input.siteUrl, look: result.book.look });
|
|
67572
|
+
result.provisioningOverlay.site = derived.site;
|
|
67573
|
+
result.warnings = [...result.warnings ?? [], ...derived.notes];
|
|
67574
|
+
} catch (e) {
|
|
67575
|
+
result.warnings = [
|
|
67576
|
+
...result.warnings ?? [],
|
|
67577
|
+
`site pages: could not derive a site block for --shell ${opts.shell} (${e instanceof Error ? e.message : String(e)}) \u2014 write \`site\` into provisioning.overlay.json by hand before --apply.`
|
|
67578
|
+
];
|
|
67579
|
+
}
|
|
67580
|
+
}
|
|
67306
67581
|
const ownerCall = ownerAuth ? ownerTransportFrom(fetchImpl, ownerAuth) : void 0;
|
|
67307
67582
|
const written = await writeBusinessBook(result, {
|
|
67308
67583
|
outDir,
|
|
@@ -67392,6 +67667,8 @@ var init_cli = __esm({
|
|
|
67392
67667
|
init_write_artifacts();
|
|
67393
67668
|
init_net_guard();
|
|
67394
67669
|
init_apply2();
|
|
67670
|
+
init_site_shell_derive();
|
|
67671
|
+
init_brandable_shells();
|
|
67395
67672
|
init_crawl_look();
|
|
67396
67673
|
init_rest();
|
|
67397
67674
|
init_wix_owner();
|
|
@@ -71122,7 +71399,10 @@ var USAGE = `himi \u2014 the Himalaya authoring CLI (remote dev loop)
|
|
|
71122
71399
|
visitor-only pass (published pages, look, copy); --client-id
|
|
71123
71400
|
adds the vertical catalog counts and the app binding, and
|
|
71124
71401
|
--apply requires it. --shell takes the same
|
|
71125
|
-
names 'himi dist --shell' does; default branded-lite.
|
|
71402
|
+
names 'himi dist --shell' does; default branded-lite.
|
|
71403
|
+
A SITE shell (brandy) also derives the site's page map
|
|
71404
|
+
(tabs/drawer from its menu) into the overlay's \`site\`
|
|
71405
|
+
block \u2014 edit it, then --apply. Owner token: WIX_TEST_TOKEN
|
|
71126
71406
|
or 'wix token --site'. Look/screenshots need Chromium:
|
|
71127
71407
|
npx playwright install chromium.
|
|
71128
71408
|
himi site function list|get|put|publish|invoke [--site <msid>] [--url <https>] [--method GET]
|
|
@@ -71233,7 +71513,7 @@ var COMMANDS = [
|
|
|
71233
71513
|
{ name: "login", summary: "obtain a scoped serve-control token from Wix identity and store it in ~/.himalaya/serve-targets.json (so push/promote need no hand-pasted token). Three modes: --browser (your own Wix account, no VPN/BO), --wix (HEADLESS \u2014 the machine's own Wix CLI credential; the mode a CI pod or agent container can satisfy), --dpx (Wix employee, reads ~/.dpx/session/token). RFC 0026 WS3.", required: "[--browser|--wix|--dpx] [--target <t>] [--issue-url <url>]" },
|
|
71234
71514
|
{ name: "logout", summary: "remove the stored control token for a target", required: "[--target <t>]" },
|
|
71235
71515
|
{ name: "notify", summary: "`setup` optionally configures Branded/Ping from local customer key files; `status --refresh` reads live backend readiness. Setup may be deferred while building. These use serve-control and require owner plus Wix account authentication. `send`, `tokens`, `doctor`: send a REAL push notification to registered devices (RFC 0036 WS5) \u2014 APNs .p8 over HTTP/2 for iOS, FCM v1 for Android. `send` targets one device (--token / --device <registry id>) or fans out to the whole app (--all), reporting a per-device result; a token the provider says is uninstalled (APNs 410 Unregistered / FCM UNREGISTERED) is auto-disabled, while a merely wrong one (BadDeviceToken \u2014 usually a sandbox/production mismatch) is recorded and left enabled. `tokens` lists the registry. `doctor` reports which credentials resolve and which sender each platform picks. Talks to the admin-server via --admin-url/HIMALAYA_ADMIN_URL, authenticated with --admin-session/HIMALAYA_ADMIN_SESSION. NOT `himi push`, which publishes a release.", required: "setup|status [--content <dir>] [--target <t>] [--refresh] [--yes] [--no-push-setup] | send|tokens|doctor [--app <a>] [--token <t> | --device <id> | --all] [--title <s>] [--body <s>] [--link <url>] [--platform ios|android] [--badge <n>] [--channel <id>] [--silent] [--dry-run] [--json]" },
|
|
71236
|
-
{ name: "site", summary: "PROVISION a Wix project, then analyze or extend it. `create` is the one door that makes a site instead of adopting one: POST /funnel/projects/v1/create (a WIX site, a HEADLESS backend, a BRANDED_APP, or a VIBE site), and for headless it also mints the OAuth app whose id IS the `WIX_CLIENT_ID` \u2014 with --redirect-uri already registered, because an unregistered redirect makes native signInDirect fail at redirect-session. `--verticals` REQUIRES `--template` and reports only what Wix confirmed: measured, installing onto a project created from the BLANK template returns 200 while the vertical's API answers 428 forever, because there is no site for it to attach to (the install asks for CREATE_SITE). A real template ships its verticals installed and populated, and installing further ones onto it then works. It MUTATES your Wix account and needs --yes; without it you get the payload and nothing is sent. `list` is the read-only site inventory (with each site's premium flag, which is what explains an installed-but-428 vertical). Auth is the account-scoped `wix token` (no --site), falling back to WIX_API_KEY + WIX_ACCOUNT_ID. `client` is the same OAuth step for a site that ALREADY exists \u2014 the one himi adopts rather than makes \u2014 so a clientId no longer means a manual trip to the dashboard: `client ensure` reconciles rather than mints, because a site can already carry a client with NO registered redirect and shipping that one fails signInDirect at runtime; it reuses a client that carries --redirect-uri, PATCHes one that matches --name but lacks it (unioning, so another app's redirect survives), and creates only when there is nothing to reuse (--new forces a fresh one). --name IS the idempotency key. `client` auth is SITE-scoped (`wix token --site <msid>`) because minting is owner-of-that-site, and --yes gates every mutation: a site that already has a usable client resolves WITHOUT it, but --write-provisioning needs --yes even then because it rewrites a manifest on disk (the dry run's planned.provisioning names the file). That query endpoint IGNORES paging (measured: query.paging, cursorPaging and a top-level paging all return the full set at offset 0), so when pagingMetadata reports more clients than came back, `ensure` REFUSES EVERY outcome \u2014 create, patch AND reuse. Reuse is refused too because pickClient breaks ties on the OLDEST createdDate, so an omitted older same-named MOBILE client with the same redirect would win a later complete read and the resolved clientId would MOVE between runs \u2014 and it gets written into provisioning.json; convergence is what makes a stray duplicate untidy rather than harmful. --name cannot narrow the query (no filter is sent; the name is applied to the rows after they arrive), so the recovery is the dashboard; --new skips the query entirely. A `patched` result is verified against what Wix STORED \u2014 the redirect list is read off the PATCH response, and re-read via GET when the response omits it, because falling back to the list himi just sent would make the guard pass vacuously on exactly the silent no-op it exists to catch. `client list` is the read-only inventory of a site's clients: act on its `shippable` column rather than `hasRedirect`, because shippable ALSO requires a MOBILE applicationType and `ensure` refuses a WEB client \u2014 a WEB one carrying your redirect looks right and is not a candidate \u2014 and it sets truncated:true rather than presenting a partial inventory as the whole one. `analyze --read-only` returns API-only generation context as JSON (identity, access probes, CMS permissions and selected redacted Velo source); it needs no URL/browser and never uploads or applies anything. `analyze` reads a site into a business-book folder (REST + Playwright, GET-only); `--url` alone is the visitor-only pass over the published pages, and `--client-id` adds the vertical probes and the app binding `--apply` requires; `site function` list/get/put/publish/invokes that site's Velo HTTP functions and is not `himi functions` (serve-plane jobs). `--apply` bakes into a brandable shell; `--shell` takes the same names `himi dist --shell` does and defaults to branded-lite, and a shell that ships no prepare:customer is refused by name rather than half-built. It never overwrites any shell's committed apps/<shell>/provisioning.json.", required: "create <name> [--type wix|headless|branded-app|vibe] [--template <guid>] [--verticals stores,bookings,\u2026] [--folder <guid>] [--redirect-uri <uri>] [--no-oauth-app] [--write-provisioning [path]] [--site-url <url>] [--json] --yes | list | client ensure|list --site <msid> [--name <name>] [--redirect-uri <uri>] [--new] [--write-provisioning [path]] [--site-url <url>] [--json] --yes | analyze --read-only [--site <msid>] [--client-id <id>] [--json] | analyze --url <https> [--client-id <id>] [--site <msid>] [--out <dir>] [--redirect-uri <uri>] [--apply] [--shell " + SHELL_ENUM + "] | function list|get|put|publish|invoke [--site <msid>] [--url <https>] [--method GET|POST|PUT|DELETE] [--source <file>] [--body <json>] [--publish] [--invoke]" },
|
|
71516
|
+
{ name: "site", summary: "PROVISION a Wix project, then analyze or extend it. `create` is the one door that makes a site instead of adopting one: POST /funnel/projects/v1/create (a WIX site, a HEADLESS backend, a BRANDED_APP, or a VIBE site), and for headless it also mints the OAuth app whose id IS the `WIX_CLIENT_ID` \u2014 with --redirect-uri already registered, because an unregistered redirect makes native signInDirect fail at redirect-session. `--verticals` REQUIRES `--template` and reports only what Wix confirmed: measured, installing onto a project created from the BLANK template returns 200 while the vertical's API answers 428 forever, because there is no site for it to attach to (the install asks for CREATE_SITE). A real template ships its verticals installed and populated, and installing further ones onto it then works. It MUTATES your Wix account and needs --yes; without it you get the payload and nothing is sent. `list` is the read-only site inventory (with each site's premium flag, which is what explains an installed-but-428 vertical). Auth is the account-scoped `wix token` (no --site), falling back to WIX_API_KEY + WIX_ACCOUNT_ID. `client` is the same OAuth step for a site that ALREADY exists \u2014 the one himi adopts rather than makes \u2014 so a clientId no longer means a manual trip to the dashboard: `client ensure` reconciles rather than mints, because a site can already carry a client with NO registered redirect and shipping that one fails signInDirect at runtime; it reuses a client that carries --redirect-uri, PATCHes one that matches --name but lacks it (unioning, so another app's redirect survives), and creates only when there is nothing to reuse (--new forces a fresh one). --name IS the idempotency key. `client` auth is SITE-scoped (`wix token --site <msid>`) because minting is owner-of-that-site, and --yes gates every mutation: a site that already has a usable client resolves WITHOUT it, but --write-provisioning needs --yes even then because it rewrites a manifest on disk (the dry run's planned.provisioning names the file). That query endpoint IGNORES paging (measured: query.paging, cursorPaging and a top-level paging all return the full set at offset 0), so when pagingMetadata reports more clients than came back, `ensure` REFUSES EVERY outcome \u2014 create, patch AND reuse. Reuse is refused too because pickClient breaks ties on the OLDEST createdDate, so an omitted older same-named MOBILE client with the same redirect would win a later complete read and the resolved clientId would MOVE between runs \u2014 and it gets written into provisioning.json; convergence is what makes a stray duplicate untidy rather than harmful. --name cannot narrow the query (no filter is sent; the name is applied to the rows after they arrive), so the recovery is the dashboard; --new skips the query entirely. A `patched` result is verified against what Wix STORED \u2014 the redirect list is read off the PATCH response, and re-read via GET when the response omits it, because falling back to the list himi just sent would make the guard pass vacuously on exactly the silent no-op it exists to catch. `client list` is the read-only inventory of a site's clients: act on its `shippable` column rather than `hasRedirect`, because shippable ALSO requires a MOBILE applicationType and `ensure` refuses a WEB client \u2014 a WEB one carrying your redirect looks right and is not a candidate \u2014 and it sets truncated:true rather than presenting a partial inventory as the whole one. `analyze --read-only` returns API-only generation context as JSON (identity, access probes, CMS permissions and selected redacted Velo source); it needs no URL/browser and never uploads or applies anything. `analyze` reads a site into a business-book folder (REST + Playwright, GET-only); `--url` alone is the visitor-only pass over the published pages, and `--client-id` adds the vertical probes and the app binding `--apply` requires; `site function` list/get/put/publish/invokes that site's Velo HTTP functions and is not `himi functions` (serve-plane jobs). `--apply` bakes into a brandable shell; `--shell` takes the same names `himi dist --shell` does and defaults to branded-lite, and a shell that ships no prepare:customer is refused by name rather than half-built. `--shell brandy` (the site shell, RFC 0062) also derives the site's page map from its published pages and header menu \u2014 Home first, up to four tabs for the pages a visitor returns to, the rest in the drawer \u2014 into the overlay's `site` block, so it can be edited before `--apply`; only a site shell ever receives that block. It never overwrites any shell's committed apps/<shell>/provisioning.json.", required: "create <name> [--type wix|headless|branded-app|vibe] [--template <guid>] [--verticals stores,bookings,\u2026] [--folder <guid>] [--redirect-uri <uri>] [--no-oauth-app] [--write-provisioning [path]] [--site-url <url>] [--json] --yes | list | client ensure|list --site <msid> [--name <name>] [--redirect-uri <uri>] [--new] [--write-provisioning [path]] [--site-url <url>] [--json] --yes | analyze --read-only [--site <msid>] [--client-id <id>] [--json] | analyze --url <https> [--client-id <id>] [--site <msid>] [--out <dir>] [--redirect-uri <uri>] [--apply] [--shell " + SHELL_ENUM + "] | function list|get|put|publish|invoke [--site <msid>] [--url <https>] [--method GET|POST|PUT|DELETE] [--source <file>] [--body <json>] [--publish] [--invoke]" },
|
|
71237
71517
|
{ name: "doctor", summary: 'off-VPN preflight in one shot: probe the PUBLIC data plane (www.wixapis.com \u2014 reachable off-VPN), the INTERNAL serve/control plane for the selected target (VPN-gated), and report auth state (dpx session on disk + stored control token). --dpx additionally runs a live, EADDRINUSE-safe `dpx whoami`. Machine-readable with --json (an unreachable internal plane carries a stable code:"needs_vpn" so an agent branches on the code, not the prose); human-readable otherwise. Never loads the authoring runtime \u2014 works off-repo.', required: "[--target <t>] [--dpx] [--json] [--data-url <url>] [--timeout <ms>]" },
|
|
71238
71518
|
{ name: "upgrade", summary: "install the newest published CLI (`npm i -g @wix/himalaya-cli@latest`) and report what moved. This is the explicit door: himi also updates itself when the running build is more than a week old \u2014 unattended it just does it and re-runs your command, at a terminal it asks first \u2014 and `HIMI_NO_UPDATE_CHECK=1` turns that off, leaving this command as the way to catch up. Reports `unchanged` rather than claiming success when npm exits 0 without moving the version, which is what a registry mirror serving its own pinned copy looks like.", required: "[--json]" },
|
|
71239
71519
|
{ name: "push", summary: "lint + build + publish a release (default --draft: servable via ?release= but NOT live). REFUSES to publish on any error unless --force; --strict promotes warnings. Prints preview + agent-context links. A successful draft push also rebuilds the making-of (.himi/making-of.html, local and offline) and names it as `reel` \u2014 the file to hand the owner beside the preview link. Its postcard carries the home shot only when that shot is newer than the last source edit; otherwise the postcard says why and names `himi render <home> --png`, and the envelope's `postcardPicture: {skipped, render}` leads next[] with that render (the push never renders it itself). The published slug is NAMESPACED per owner \u2014 `<ownerPrefix>.<name>`, composed offline from the control token's ownerPrefix claim, so the CLI and the server derive the identical string and himalaya.content.json is NOT rewritten (a legacy token with no ownerPrefix publishes the declared name unchanged). An app claimed BEFORE namespacing is stored under its FLAT slug, so the claim route answers `alreadyYours` naming that slug and the push adopts it \u2014 reported as `adoptedSlug`, since it is the one case where the published `app` differs from what the declared name composes to. `--no-claim` skips the route that knows this, so a pre-namespacing app pushed with it still fails 403. --visibility public|unlisted decides whether /v1/apps + the Himi Player picker LIST the app (also declarable as `visibility` in himalaya.content.json; omitted, a brand-new app defaults to unlisted \u2014 share by link \u2014 and an existing setting is kept). --account-id names which account owns the app when your Wix session resolves to several (the auto-claim of a brand-new slug cannot guess \u2014 without it a multi-account caller is told to name one). An unforced push of a release that carries SCREENS also refuses when `.himi/ux-audit.json` holds no mobile-UX drive recorded against that release id, or holds one that FAILED (#2955) \u2014 a published draft IS the owner-private preview a customer is handed; `himi ux record` clears it and `--force` overrides it, which the success envelope then says out loud. `--only <selector>` publishes ONLY the named items as a release derived from the app's live release (or `--from-release <id>`), running the identical build + lint gate and simply publishing less; it requires an explicit `--draft` or `--live` because a partial publish has no safe default, never claims a slug, and carries neither attestation nor a source archive (both named in the output). Selectors are comma-separated in ONE `--only`: `changed` (every item whose bytes differ from the base), `screen:<id|glob>`, `bundle:<name>`, `tokens`, `app-config` \u2014 a selected screen drags its logic bundle and a selected bundle drags the screens that reference it, or the bytes land under a key nothing reads.", required: "[--content <dir>] [--draft] [--live] [--force] [--strict] [--label] [--notes] [--visibility public|unlisted] [--no-claim] [--account-id <id>] [--only <selector>] [--from-release <id>] [--accept-regressions] [--accept-partial] [--app <slug>] (--control-token)" },
|
|
@@ -78437,7 +78717,7 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
|
|
|
78437
78717
|
}
|
|
78438
78718
|
}
|
|
78439
78719
|
if (sub !== "analyze") {
|
|
78440
|
-
io.error(JSON.stringify({ error: sub ? `unknown site subcommand "${sub}"` : "site needs a subcommand", usage: `himi site create <name> [--type wix|headless|branded-app|vibe] --yes | himi site list | himi site client ensure|list --site <msid> | himi site analyze --url <https://\u2026> [--client-id <id>] [--site <msid>] [--out <dir>] [--
|
|
78720
|
+
io.error(JSON.stringify({ error: sub ? `unknown site subcommand "${sub}"` : "site needs a subcommand", usage: `himi site create <name> [--type wix|headless|branded-app|vibe] --yes | himi site list | himi site client ensure|list --site <msid> | himi site analyze --url <https://\u2026> [--client-id <id>] [--site <msid>] [--out <dir>] [--shell <id>] [--apply] | himi site function list|get|put|publish|invoke \u2026` }));
|
|
78441
78721
|
return 2;
|
|
78442
78722
|
}
|
|
78443
78723
|
const clientFlag = str8(flags["client-id"]);
|
|
@@ -78471,7 +78751,7 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
|
|
|
78471
78751
|
print({ ok: true, context });
|
|
78472
78752
|
return 0;
|
|
78473
78753
|
}
|
|
78474
|
-
const analyzeUsage = "himi site analyze --url https://\u2026 [--client-id <headless-oauth-client-id>] [--site <msid>] [--out .himi/business-book] [--redirect-uri <uri>] [--
|
|
78754
|
+
const analyzeUsage = "himi site analyze --url https://\u2026 [--client-id <headless-oauth-client-id>] [--site <msid>] [--out .himi/business-book] [--redirect-uri <uri>] [--shell " + SHELL_ENUM + "] [--apply]";
|
|
78475
78755
|
if (!siteUrl) {
|
|
78476
78756
|
io.error(JSON.stringify({ error: "himi site analyze needs --url", usage: analyzeUsage }));
|
|
78477
78757
|
return 2;
|
|
@@ -156,6 +156,28 @@ The plane has no headless browser (`look.unavailable: no_browser_on_plane`). Own
|
|
|
156
156
|
|
|
157
157
|
`--apply` writes `appearance.homeLayout` + `navigation.navKind` plus identity/colors. It never silently overwrites committed Amit1 `apps/himi-branded-lite/provisioning.json`.
|
|
158
158
|
|
|
159
|
+
### A site shell: `--shell brandy`
|
|
160
|
+
|
|
161
|
+
`himi-brandy`, the site shell, opens the customer's live website as native-framed tabs, so its contract is a `site` block: which website, and which of its pages are tabs, drawer rows or overflow rows. `--shell brandy` derives that block into `provisioning.overlay.json`:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
himi site analyze --url https://owner.wixsite.com/site --client-id <id> --shell brandy # writes site.pages
|
|
165
|
+
# edit site.pages in .himi/business-book/provisioning.overlay.json if the map needs it
|
|
166
|
+
himi site analyze --url https://owner.wixsite.com/site --client-id <id> --shell brandy --apply
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
The map comes from what the analysis already reads without owner credentials, because Wix has no public menu API: the published page list (`look.sitePages`), the header menu the crawl saw (`look.navLinks`, label and href), and each page's role.
|
|
170
|
+
|
|
171
|
+
- **Order and labels** follow the site's own menu. Links to other hosts, and repeat links to the same page, are dropped.
|
|
172
|
+
- **No menu crawled** (no browser, or the crawl failed): the published page list is used instead, and a note says so.
|
|
173
|
+
- **Home** is always the first tab, with the menu's own word for it.
|
|
174
|
+
- **Tabs:** the pages a visitor comes back to (shop, book, menu, events, plans, blog, gallery) take up to three more, in menu order. A small site fills its bar in menu order rather than show a single tab.
|
|
175
|
+
- **Drawer and overflow:** About, Contact and other pages go to the drawer; account pages go to overflow.
|
|
176
|
+
- **Size:** at most 10 pages, with titles capped at 40 characters.
|
|
177
|
+
- **Chrome:** the site's own header, footer and Wix ads are hidden (the site shell's default).
|
|
178
|
+
|
|
179
|
+
The block is validated with the shell's own rules before it is written. Only a site shell ever receives it: the analysis leaves it out for any other `--shell`, and the merge drops it for a shell whose committed contract has no `site`. `--apply --shell brandy` without a `site` block in the overlay is refused, because baking would ship the shell's demo site under the customer's brand.
|
|
180
|
+
|
|
159
181
|
When the analysis recognized at least one vertical, `--apply` also patches the shell's baked home
|
|
160
182
|
(`dev/index.ts`) to what the site actually runs. The Explore grid keeps only the site's
|
|
161
183
|
destinations (adding a card the template baked none for, and leaving off a vertical the template
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1104.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "himi — the Himalaya authoring CLI. Build a Tier-5 content package on your own machine, push it to the production serve as a draft, preview it on web + Himi Player, and read worker logs back — the remote dev loop. Wraps @himalaya/serve-cli for transport.",
|
|
6
6
|
"keywords": [
|
|
@@ -67,5 +67,5 @@
|
|
|
67
67
|
"artifactId": "himalaya-cli"
|
|
68
68
|
}
|
|
69
69
|
},
|
|
70
|
-
"falconPackageHash": "
|
|
70
|
+
"falconPackageHash": "3b9d4a5bc87c7f44c95094ff409a54b61fb726b2c3062b7a587718be"
|
|
71
71
|
}
|