@wix/himalaya-cli 0.1115.0 → 0.1116.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 +17 -10
- package/guides/wix-business-context.md +4 -2
- package/package.json +2 -2
- package/template-icons/brandy.png +0 -0
- package/templates/brandy/README.md +60 -0
- package/templates/brandy/config.ts +76 -0
- package/templates/brandy/dev/index.ts +25 -0
- package/templates/brandy/himalaya.content.json +5 -0
- package/templates/brandy/himalaya.template.json +6 -0
- package/templates/brandy/icon.png +0 -0
- package/templates/brandy/platforms.json +1 -0
- package/templates/brandy/provisioning.json +12 -0
- package/templates/brandy/tokens.json +128 -0
package/dist/cli.mjs
CHANGED
|
@@ -13140,7 +13140,6 @@ function resolveIdiom(tokens, ctx = {}) {
|
|
|
13140
13140
|
var IDIOM_CONTEXTS, UNSAFE_KEYS;
|
|
13141
13141
|
var init_idiom = __esm({
|
|
13142
13142
|
"../../core/ts/src/idiom.ts"() {
|
|
13143
|
-
"use strict";
|
|
13144
13143
|
IDIOM_CONTEXTS = {
|
|
13145
13144
|
ios: { native: ["ios"] },
|
|
13146
13145
|
android: { native: ["material"] },
|
|
@@ -24719,7 +24718,6 @@ function shouldRevealError(args) {
|
|
|
24719
24718
|
var EMAIL_RE, URL_HOST_RE, INTEGER_RE, NUMBER_RE;
|
|
24720
24719
|
var init_validation = __esm({
|
|
24721
24720
|
"../../core/ts/src/validation.ts"() {
|
|
24722
|
-
"use strict";
|
|
24723
24721
|
EMAIL_RE = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}$/;
|
|
24724
24722
|
URL_HOST_RE = /^[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*(:[0-9]+)?$/;
|
|
24725
24723
|
INTEGER_RE = /^[+-]?[0-9]+$/;
|
|
@@ -29120,7 +29118,6 @@ function validateWorkerSubtree(raw, slotId, policy, actionCatalog) {
|
|
|
29120
29118
|
var WORKER_SUBTREE_CEILINGS, ID_PART, ACTION_ID;
|
|
29121
29119
|
var init_worker_subtree = __esm({
|
|
29122
29120
|
"../../core/ts/src/worker-subtree.ts"() {
|
|
29123
|
-
"use strict";
|
|
29124
29121
|
init_worker_subtree_safe_types_generated();
|
|
29125
29122
|
WORKER_SUBTREE_CEILINGS = Object.freeze({
|
|
29126
29123
|
maxEncodedBytes: 65536,
|
|
@@ -68216,6 +68213,7 @@ __export(cli_exports, {
|
|
|
68216
68213
|
APPLY_NEEDS_CLIENT: () => APPLY_NEEDS_CLIENT,
|
|
68217
68214
|
REDIRECT_NEEDS_CLIENT: () => REDIRECT_NEEDS_CLIENT,
|
|
68218
68215
|
SITE_FUNCTION_USAGE: () => SITE_FUNCTION_USAGE,
|
|
68216
|
+
applyNeedsClient: () => applyNeedsClient,
|
|
68219
68217
|
assetFetchFor: () => assetFetchFor,
|
|
68220
68218
|
noteWithWarnings: () => noteWithWarnings,
|
|
68221
68219
|
ownerSiteFor: () => ownerSiteFor,
|
|
@@ -68224,6 +68222,10 @@ __export(cli_exports, {
|
|
|
68224
68222
|
});
|
|
68225
68223
|
import { readFileSync as readFileSync78 } from "node:fs";
|
|
68226
68224
|
import { resolve as resolve52 } from "node:path";
|
|
68225
|
+
function applyNeedsClient(shell) {
|
|
68226
|
+
if (shell === void 0 || !SHELL_NAMES2.includes(shell)) return true;
|
|
68227
|
+
return !isSiteShell(shell);
|
|
68228
|
+
}
|
|
68227
68229
|
function assetFetchFor(_opts) {
|
|
68228
68230
|
return pinnedFetch2;
|
|
68229
68231
|
}
|
|
@@ -68236,7 +68238,7 @@ function ownerSiteFor(opts, env = process.env) {
|
|
|
68236
68238
|
async function runSiteAnalyze(opts) {
|
|
68237
68239
|
if (opts.shell !== void 0) assertKnownShell(opts.shell);
|
|
68238
68240
|
if (!opts.clientId?.trim()) {
|
|
68239
|
-
if (opts.apply) throw Object.assign(new Error(APPLY_NEEDS_CLIENT), { exit: 2 });
|
|
68241
|
+
if (opts.apply && applyNeedsClient(opts.shell)) throw Object.assign(new Error(APPLY_NEEDS_CLIENT), { exit: 2 });
|
|
68240
68242
|
if (opts.redirectUri?.trim()) throw Object.assign(new Error(REDIRECT_NEEDS_CLIENT), { exit: 2 });
|
|
68241
68243
|
}
|
|
68242
68244
|
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
@@ -68271,7 +68273,10 @@ async function runSiteAnalyze(opts) {
|
|
|
68271
68273
|
try {
|
|
68272
68274
|
const derived = deriveSiteShell({ siteUrl: result.book.input.siteUrl, look: result.book.look });
|
|
68273
68275
|
result.provisioningOverlay.site = derived.site;
|
|
68274
|
-
|
|
68276
|
+
const warnings2 = (result.warnings ?? []).map(
|
|
68277
|
+
(w) => !opts.clientId?.trim() && w.startsWith("no --client-id:") ? `no --client-id: fine for --shell ${opts.shell} \u2014 a site shell binds no client, so --apply works without one. Only the vertical probes were skipped, so the catalog has no counts.` : w
|
|
68278
|
+
);
|
|
68279
|
+
result.warnings = [...warnings2, ...derived.notes];
|
|
68275
68280
|
} catch (e) {
|
|
68276
68281
|
result.warnings = [
|
|
68277
68282
|
...result.warnings ?? [],
|
|
@@ -72116,7 +72121,8 @@ var USAGE = `himi \u2014 the Himalaya authoring CLI (remote dev loop)
|
|
|
72116
72121
|
a brandable shell's content package. --url alone is the
|
|
72117
72122
|
visitor-only pass (published pages, look, copy); --client-id
|
|
72118
72123
|
adds the vertical catalog counts and the app binding, and
|
|
72119
|
-
--apply requires it
|
|
72124
|
+
--apply requires it (not for a site shell, which binds no
|
|
72125
|
+
client). --shell takes the same
|
|
72120
72126
|
names 'himi dist --shell' does; default branded-lite.
|
|
72121
72127
|
A SITE shell (brandy) also derives the site's page map
|
|
72122
72128
|
(tabs/drawer from its menu) into the overlay's \`site\`
|
|
@@ -72231,7 +72237,7 @@ var COMMANDS = [
|
|
|
72231
72237
|
{ 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>]" },
|
|
72232
72238
|
{ name: "logout", summary: "remove the stored control token for a target", required: "[--target <t>]" },
|
|
72233
72239
|
{ 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. `send --provider ping` is the hosted alternative: the serve plane sends one test notification to one site member through Ping as Himalaya, with owner login instead of provider keys, and reports acceptance, never delivery. NOT `himi push`, which publishes a release.", required: "setup|status [--content <dir>] [--target <t>] [--refresh] [--yes] [--no-push-setup] | send --provider ping [--content <dir>] [--app <a>] [--site <msid>] --member-email <email> --title <s> [--body <s>] --link <url> [--request-id <uuid>] [--dry-run] [--json] | 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]" },
|
|
72234
|
-
{ 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]" },
|
|
72240
|
+
{ 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 (a site shell needs no `--client-id`: it is visitor-only and binds no client); `--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]" },
|
|
72235
72241
|
{ 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>]" },
|
|
72236
72242
|
{ 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]" },
|
|
72237
72243
|
{ 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)" },
|
|
@@ -79552,10 +79558,11 @@ ${report3.ok ? "OK \u2014 data + serve plane reachable." : typeof report3.hint =
|
|
|
79552
79558
|
return 2;
|
|
79553
79559
|
}
|
|
79554
79560
|
const redirectFlag = str8(flags["redirect-uri"]);
|
|
79555
|
-
|
|
79556
|
-
|
|
79561
|
+
const { APPLY_NEEDS_CLIENT: APPLY_NEEDS_CLIENT2, REDIRECT_NEEDS_CLIENT: REDIRECT_NEEDS_CLIENT2, applyNeedsClient: applyNeedsClient2 } = await Promise.resolve().then(() => (init_cli(), cli_exports));
|
|
79562
|
+
const applyWantsClient = flags.apply === true && applyNeedsClient2(str8(flags.shell));
|
|
79563
|
+
if (!clientId && (applyWantsClient || redirectFlag)) {
|
|
79557
79564
|
io.error(JSON.stringify({
|
|
79558
|
-
error:
|
|
79565
|
+
error: applyWantsClient ? APPLY_NEEDS_CLIENT2 : REDIRECT_NEEDS_CLIENT2,
|
|
79559
79566
|
usage: analyzeUsage
|
|
79560
79567
|
}));
|
|
79561
79568
|
return 2;
|
|
@@ -161,11 +161,13 @@ The plane has no headless browser (`look.unavailable: no_browser_on_plane`). Own
|
|
|
161
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
162
|
|
|
163
163
|
```bash
|
|
164
|
-
himi site analyze --url https://owner.wixsite.com/site --
|
|
164
|
+
himi site analyze --url https://owner.wixsite.com/site --shell brandy # writes site.pages
|
|
165
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 --
|
|
166
|
+
himi site analyze --url https://owner.wixsite.com/site --shell brandy --apply
|
|
167
167
|
```
|
|
168
168
|
|
|
169
|
+
No `--client-id` is needed here: a site shell is visitor-only, its pages are the site itself, and its contract binds no Headless client. For an off-repo brandy app (`himi init --template brandy`), run the `--apply` inside the app folder: it writes the derived `site` block into the package's own `provisioning.json`, which the template's `config.ts` builds every tab and screen from.
|
|
170
|
+
|
|
169
171
|
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
172
|
|
|
171
173
|
- **Order and labels** follow the site's own menu. Links to other hosts, and repeat links to the same page, are dropped.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1116.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": "6d8f58d4b9f65728efd1d2728c9c1567bbe8ea1cb014bda9ee1afc50"
|
|
71
71
|
}
|
|
Binary file
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# __HIMI_APP_NAME__ — your website as an app
|
|
2
|
+
|
|
3
|
+
A **site shell**: your live Wix website, framed as a native app. Every tab and drawer row is one of
|
|
4
|
+
your site's own pages, shown in a WebView under a native tab bar, drawer and splash in your brand
|
|
5
|
+
colours. The site's own header, footer and Wix ads are hidden. It is the fastest way to ship an
|
|
6
|
+
existing website as an app, and each tab can later be replaced by a native screen.
|
|
7
|
+
|
|
8
|
+
## Point it at your site
|
|
9
|
+
|
|
10
|
+
The whole app is the `site` block in `provisioning.json`:
|
|
11
|
+
|
|
12
|
+
```json
|
|
13
|
+
{
|
|
14
|
+
"site": {
|
|
15
|
+
"origin": "https://your-account.wixsite.com/your-site",
|
|
16
|
+
"kind": "wix",
|
|
17
|
+
"pages": [
|
|
18
|
+
{ "id": "home", "title": "Home", "path": "/", "icon": "home" },
|
|
19
|
+
{ "id": "blog", "title": "Blog", "path": "/blog", "icon": "newspaper" },
|
|
20
|
+
{ "id": "contact", "title": "Contact", "path": "/contact", "icon": "mail", "placement": "drawer" }
|
|
21
|
+
],
|
|
22
|
+
"chrome": { "hideSiteHeader": true, "hideSiteFooter": true, "hideWixAds": true }
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The placeholder origin above is not a real site. Replace it by deriving the block from your site's
|
|
28
|
+
own menu, from inside this folder:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
himi site analyze --url https://your-account.wixsite.com/your-site --shell brandy --apply
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
That writes the derived `site` block into this `provisioning.json` and your site's colours into
|
|
35
|
+
`tokens.json`. No `--client-id` is needed, because a site shell reads nothing through a Wix client.
|
|
36
|
+
To review the map first, leave out `--apply`: the block is then only written to
|
|
37
|
+
`.himi/business-book/provisioning.overlay.json`. You can always edit the block by hand.
|
|
38
|
+
|
|
39
|
+
- **`origin`** is your published site, `https` only. A free site's path (`/your-site`) is part of it.
|
|
40
|
+
- **`pages`** are paths relative to the origin. Each needs a unique `id` (`a-z`, `0-9`, `_`) and must
|
|
41
|
+
not use `page`, which is reserved.
|
|
42
|
+
- **`placement`** is `tab` (the default), `drawer` or `overflow`. At most four tabs are shown, and
|
|
43
|
+
`home` must be the first of them: the app opens on its first tab.
|
|
44
|
+
- **`icon`** is a design-system icon name (`home`, `bag`, `calendar`, `ticket`, `newspaper`, `mail`,
|
|
45
|
+
`info`, `tag`, `photo`, `person`, `globe`, …).
|
|
46
|
+
- **`chrome`** hides the site's own header (on inner pages), its footer and the Wix ads banner.
|
|
47
|
+
Every flag defaults to hidden.
|
|
48
|
+
|
|
49
|
+
`config.ts` validates the block whenever the app loads, so an `http` origin, a duplicate id or a map
|
|
50
|
+
with no tab fails `himi validate`, `himi render` and `himi push` rather than shipping.
|
|
51
|
+
|
|
52
|
+
## Loop
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
himi build && himi validate --strict # derive the screens and check them
|
|
56
|
+
himi render site_home # the home tab (a WebView: headless render reports it, it does not paint it)
|
|
57
|
+
himi push --draft # publish a draft release and open the web preview
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Your colours live in `tokens.json` and your name in `config.ts`.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// Your app's configuration — a SITE SHELL. Your live website is the app: every tab and drawer
|
|
2
|
+
// row is one of its pages, shown in a native-framed WebView under a native tab bar and drawer.
|
|
3
|
+
//
|
|
4
|
+
// Nothing here names a page. The pages come from the `site` block of ./provisioning.json, so you
|
|
5
|
+
// change the app by changing that block — by hand, or with
|
|
6
|
+
// himi site analyze --url https://<your-site> --shell brandy
|
|
7
|
+
// which derives it from your site's own menu. Inspect the live values any time with
|
|
8
|
+
// `himi context`; see `himi docs app-config`.
|
|
9
|
+
import {
|
|
10
|
+
assertSiteShellConfig,
|
|
11
|
+
defineApp,
|
|
12
|
+
siteLinkableScreens,
|
|
13
|
+
siteNav,
|
|
14
|
+
siteNavConfig,
|
|
15
|
+
type SiteShellConfig,
|
|
16
|
+
} from "@himalaya/core";
|
|
17
|
+
import { ConsoleTelemetrySink } from "@himalaya/telemetry-console";
|
|
18
|
+
import provisioning from "./provisioning.json" with { type: "json" };
|
|
19
|
+
|
|
20
|
+
/** Your website and its page map. Validated here, so a mistake in provisioning.json (an http
|
|
21
|
+
* origin, a duplicate page id, no tab) fails `himi validate`, `render` and `push` instead of
|
|
22
|
+
* shipping a broken app. */
|
|
23
|
+
export const site = provisioning.site as SiteShellConfig;
|
|
24
|
+
assertSiteShellConfig(site);
|
|
25
|
+
const nav = siteNav(site);
|
|
26
|
+
// The app opens on its first tab, and everything that names the home screen (`himi init`,
|
|
27
|
+
// `himi render`, agent tooling) names `site_home` — so the `home` page must BE the first tab.
|
|
28
|
+
if (nav.tabs[0]?.screenId !== "site_home") {
|
|
29
|
+
throw new Error('provisioning.json: the "home" page must be the first tab — list it first in site.pages');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default defineApp({
|
|
33
|
+
id: "__HIMI_APP_DOTID__",
|
|
34
|
+
name: "__HIMI_APP_NAME__",
|
|
35
|
+
bundleId: "__HIMI_APP_DOTID__",
|
|
36
|
+
applicationId: "__HIMI_APP_DOTID__",
|
|
37
|
+
// Placeholders — an over-the-air app never consumes these. Leave as-is.
|
|
38
|
+
schemaPackage: "@example/__HIMI_APP_SLUG__-schema",
|
|
39
|
+
schemaPackageRange: { min: 9900, max: 9909 },
|
|
40
|
+
// Placeholders — only a local server would read these. Leave as-is.
|
|
41
|
+
ports: { devServer: 8190, web: 5390 },
|
|
42
|
+
// Visitor-only: your site's own pages handle anything a visitor does.
|
|
43
|
+
auth: { providerId: "none", config: {} },
|
|
44
|
+
telemetry: ConsoleTelemetrySink(),
|
|
45
|
+
serverUrls: {
|
|
46
|
+
screen: "http://localhost:8190/v1",
|
|
47
|
+
actions: "http://localhost:8190/v1/actions",
|
|
48
|
+
sync: "http://localhost:8190/v1/sync",
|
|
49
|
+
},
|
|
50
|
+
capabilities: [],
|
|
51
|
+
// Your brand colours paint the NATIVE chrome (tabs, drawer, splash); the site paints its pages.
|
|
52
|
+
designTokensPath: "./tokens.json",
|
|
53
|
+
// "Ready" means the first page has painted, not just the app shell — otherwise the splash
|
|
54
|
+
// fades into a blank WebView. It still dismisses after 5s on a slow link.
|
|
55
|
+
splash: {
|
|
56
|
+
enabled: true,
|
|
57
|
+
backgroundColor: "accentPrimary",
|
|
58
|
+
caption: "__HIMI_APP_NAME__",
|
|
59
|
+
minVisibleMs: 400,
|
|
60
|
+
maxHoldMs: 5000,
|
|
61
|
+
readySignal: "first_content",
|
|
62
|
+
},
|
|
63
|
+
navigation: {
|
|
64
|
+
// Bottom tabs on a phone, a sidebar on a larger screen; the drawer lists every page that is
|
|
65
|
+
// not `overflow`. At most four tabs — each keeps its page loaded while you switch.
|
|
66
|
+
navKind: "responsive",
|
|
67
|
+
scheme: "himalaya-__HIMI_APP_SLUG__",
|
|
68
|
+
deepLinkPatterns: [],
|
|
69
|
+
linkableScreens: siteLinkableScreens(site),
|
|
70
|
+
// A notification or app link carrying one of your site's URLs opens that page's tab.
|
|
71
|
+
site: siteNavConfig(site),
|
|
72
|
+
tabBar: { items: nav.tabs },
|
|
73
|
+
drawer: { items: nav.drawer },
|
|
74
|
+
},
|
|
75
|
+
entities: {},
|
|
76
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Your app's screens. Each one is a page of your website — a WebView screen built from the
|
|
2
|
+
// `site` block of ../provisioning.json — so this file holds no screen of its own. Change the
|
|
3
|
+
// pages by changing that block, never this file.
|
|
4
|
+
import { siteScreens } from "@himalaya/core";
|
|
5
|
+
import config, { site } from "../config.js";
|
|
6
|
+
|
|
7
|
+
const SCREENS = siteScreens(site);
|
|
8
|
+
// The home screen is always the `home` page's: `site_home`. A literal on purpose — `himi init`
|
|
9
|
+
// and the agent tooling read `homeScreenId` from this file as written; config.ts refuses a map
|
|
10
|
+
// whose first tab is anything else, so the literal and the tab bar cannot disagree.
|
|
11
|
+
|
|
12
|
+
export default {
|
|
13
|
+
config,
|
|
14
|
+
homeScreenId: "site_home",
|
|
15
|
+
screens: {
|
|
16
|
+
// A fresh copy per build: descriptors are pure functions of the site block.
|
|
17
|
+
exact: Object.fromEntries(Object.keys(SCREENS).map((id) => [id, () => structuredClone(SCREENS[id])])),
|
|
18
|
+
templated: [],
|
|
19
|
+
},
|
|
20
|
+
actions: [],
|
|
21
|
+
createStore: () => ({}),
|
|
22
|
+
// Every page is seeded, so the whole tab bar and drawer work on a cold offline start (each
|
|
23
|
+
// WebView then shows its own offline state until the network returns).
|
|
24
|
+
seed: { screens: SCREENS, data: {} },
|
|
25
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "Brandy — your website as an app",
|
|
3
|
+
"description": "A site shell: the customer's live Wix website as a native app. Every tab and drawer row is one of the site's own pages in a native-framed WebView, with a native tab bar, drawer, splash and brand colours; the site's header, footer and Wix ads are hidden. The page map lives in provisioning.json (`site`), and `himi site analyze --url <site> --shell brandy` derives it from the site's own menu. Start here to ship an existing website as an app today and move tabs to native screens later.",
|
|
4
|
+
"tags": ["wix", "website", "site-shell", "webview", "tabs", "drawer", "no-code", "day-zero", "consumer"],
|
|
5
|
+
"category": "consumer"
|
|
6
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"macos":false}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"site": {
|
|
3
|
+
"origin": "https://your-account.wixsite.com/your-site",
|
|
4
|
+
"kind": "wix",
|
|
5
|
+
"pages": [
|
|
6
|
+
{ "id": "home", "title": "Home", "path": "/", "icon": "home" },
|
|
7
|
+
{ "id": "blog", "title": "Blog", "path": "/blog", "icon": "newspaper" },
|
|
8
|
+
{ "id": "contact", "title": "Contact", "path": "/contact", "icon": "mail", "placement": "drawer" }
|
|
9
|
+
],
|
|
10
|
+
"chrome": { "hideSiteHeader": true, "hideSiteFooter": true, "hideWixAds": true }
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
{
|
|
2
|
+
"colors": {
|
|
3
|
+
"surfacePrimary": {
|
|
4
|
+
"light": "#FFFFFF",
|
|
5
|
+
"dark": "#0D1117",
|
|
6
|
+
"highContrast": "#000000"
|
|
7
|
+
},
|
|
8
|
+
"surfaceSecondary": {
|
|
9
|
+
"light": "#F4F7F8",
|
|
10
|
+
"dark": "#161B22",
|
|
11
|
+
"highContrast": "#111111"
|
|
12
|
+
},
|
|
13
|
+
"surfaceElevated": {
|
|
14
|
+
"light": "#FFFFFF",
|
|
15
|
+
"dark": "#1D2228",
|
|
16
|
+
"highContrast": "#111111"
|
|
17
|
+
},
|
|
18
|
+
"surfaceSubtle": {
|
|
19
|
+
"light": "#F8FAF9",
|
|
20
|
+
"dark": "#121821",
|
|
21
|
+
"highContrast": "#111111"
|
|
22
|
+
},
|
|
23
|
+
"surfaceTertiary": {
|
|
24
|
+
"light": "#E9EEF0",
|
|
25
|
+
"dark": "#232A32",
|
|
26
|
+
"highContrast": "#1A1A1A"
|
|
27
|
+
},
|
|
28
|
+
"textPrimary": {
|
|
29
|
+
"light": "#1F2328",
|
|
30
|
+
"dark": "#E6EDF3",
|
|
31
|
+
"highContrast": "#FFFFFF"
|
|
32
|
+
},
|
|
33
|
+
"textSecondary": {
|
|
34
|
+
"light": "#59636E",
|
|
35
|
+
"dark": "#848D98",
|
|
36
|
+
"highContrast": "#CCCCCC"
|
|
37
|
+
},
|
|
38
|
+
"textTertiary": {
|
|
39
|
+
"light": "#7D8791",
|
|
40
|
+
"dark": "#6E7681",
|
|
41
|
+
"highContrast": "#CCCCCC"
|
|
42
|
+
},
|
|
43
|
+
"textOnAccent": {
|
|
44
|
+
"light": "#FFFFFF",
|
|
45
|
+
"dark": "#FFFFFF",
|
|
46
|
+
"highContrast": "#000000"
|
|
47
|
+
},
|
|
48
|
+
"accentPrimary": {
|
|
49
|
+
"light": "#0969DA",
|
|
50
|
+
"dark": "#1E72C7",
|
|
51
|
+
"highContrast": "#58A6FF"
|
|
52
|
+
},
|
|
53
|
+
"accentSecondary": {
|
|
54
|
+
"light": "#087F5B",
|
|
55
|
+
"dark": "#1C8968",
|
|
56
|
+
"highContrast": "#FFFFFF"
|
|
57
|
+
},
|
|
58
|
+
"accentSurface": {
|
|
59
|
+
"light": "#E2EDF8",
|
|
60
|
+
"dark": "#0C2540",
|
|
61
|
+
"highContrast": "#FFFFFF"
|
|
62
|
+
},
|
|
63
|
+
"success": {
|
|
64
|
+
"light": "#1A7F37",
|
|
65
|
+
"dark": "#3FB950",
|
|
66
|
+
"highContrast": "#3FB950"
|
|
67
|
+
},
|
|
68
|
+
"successSurface": {
|
|
69
|
+
"light": "#E9F8EC",
|
|
70
|
+
"dark": "#12331B",
|
|
71
|
+
"highContrast": "#FFFFFF"
|
|
72
|
+
},
|
|
73
|
+
"warning": {
|
|
74
|
+
"light": "#9A6700",
|
|
75
|
+
"dark": "#D29922",
|
|
76
|
+
"highContrast": "#D29922"
|
|
77
|
+
},
|
|
78
|
+
"warningSurface": {
|
|
79
|
+
"light": "#FFF5D8",
|
|
80
|
+
"dark": "#3A2C0A",
|
|
81
|
+
"highContrast": "#FFFFFF"
|
|
82
|
+
},
|
|
83
|
+
"danger": {
|
|
84
|
+
"light": "#CF222E",
|
|
85
|
+
"dark": "#F85149",
|
|
86
|
+
"highContrast": "#FF5555"
|
|
87
|
+
},
|
|
88
|
+
"dangerSurface": {
|
|
89
|
+
"light": "#FFEDEA",
|
|
90
|
+
"dark": "#3A1513",
|
|
91
|
+
"highContrast": "#FFFFFF"
|
|
92
|
+
},
|
|
93
|
+
"border": {
|
|
94
|
+
"light": "#D8DEE4",
|
|
95
|
+
"dark": "#30363D",
|
|
96
|
+
"highContrast": "#FFFFFF"
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"spacing": {
|
|
100
|
+
"xs": 4,
|
|
101
|
+
"sm": 8,
|
|
102
|
+
"md": 12,
|
|
103
|
+
"lg": 16,
|
|
104
|
+
"xl": 24
|
|
105
|
+
},
|
|
106
|
+
"typography": {
|
|
107
|
+
"title1": {
|
|
108
|
+
"size": 28,
|
|
109
|
+
"weight": 700,
|
|
110
|
+
"line": 1.2
|
|
111
|
+
},
|
|
112
|
+
"body": {
|
|
113
|
+
"size": 16,
|
|
114
|
+
"weight": 400,
|
|
115
|
+
"line": 1.5
|
|
116
|
+
},
|
|
117
|
+
"caption": {
|
|
118
|
+
"size": 13,
|
|
119
|
+
"weight": 400,
|
|
120
|
+
"line": 1.4
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
"radius": {
|
|
124
|
+
"sm": 4,
|
|
125
|
+
"md": 8,
|
|
126
|
+
"lg": 12
|
|
127
|
+
}
|
|
128
|
+
}
|