@wix/himalaya-cli 0.969.0 → 0.971.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 +196 -162
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/tier-5-add-a-screen.md +8 -4
- package/guides/wix-business-context.md +10 -0
- package/guides/wix-site-to-himi-app.md +8 -5
- package/package.json +2 -2
- package/templates/beauty-salon-owner/config.ts +1 -1
- package/templates/beauty-salon-owner/dev/index.ts +79 -1
- package/templates/beauty-salon-owner/tier5-src/_shared/aria-chat.ts +176 -6
- package/templates/beauty-salon-owner/tier5-src/himi-owner-lite-aria/index.ts +15 -0
- package/templates/community-club-owner/config.ts +1 -1
- package/templates/community-club-owner/dev/index.ts +79 -1
- package/templates/community-club-owner/tier5-src/_shared/aria-chat.ts +176 -6
- package/templates/community-club-owner/tier5-src/himi-owner-lite-aria/index.ts +15 -0
- package/templates/events-meetups-owner/config.ts +1 -1
- package/templates/events-meetups-owner/dev/index.ts +79 -1
- package/templates/events-meetups-owner/tier5-src/_shared/aria-chat.ts +176 -6
- package/templates/events-meetups-owner/tier5-src/himi-owner-lite-aria/index.ts +15 -0
- package/templates/gym-fitness-owner/config.ts +1 -1
- package/templates/gym-fitness-owner/dev/index.ts +79 -1
- package/templates/gym-fitness-owner/tier5-src/_shared/aria-chat.ts +176 -6
- package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-aria/index.ts +15 -0
- package/templates/nonprofit-cause-owner/config.ts +1 -1
- package/templates/nonprofit-cause-owner/dev/index.ts +79 -1
- package/templates/nonprofit-cause-owner/tier5-src/_shared/aria-chat.ts +176 -6
- package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-aria/index.ts +15 -0
- package/templates/owner-lite/config.ts +1 -1
- package/templates/owner-lite/dev/index.ts +79 -1
- package/templates/owner-lite/tier5-src/_shared/aria-chat.ts +176 -6
- package/templates/owner-lite/tier5-src/himi-owner-lite-aria/index.ts +15 -0
- package/templates/podcast-creator-owner/config.ts +1 -1
- package/templates/podcast-creator-owner/dev/index.ts +79 -1
- package/templates/podcast-creator-owner/tier5-src/_shared/aria-chat.ts +176 -6
- package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-aria/index.ts +15 -0
- package/templates/portfolio-creative-owner/config.ts +1 -1
- package/templates/portfolio-creative-owner/dev/index.ts +79 -1
- package/templates/portfolio-creative-owner/tier5-src/_shared/aria-chat.ts +176 -6
- package/templates/portfolio-creative-owner/tier5-src/himi-owner-lite-aria/index.ts +15 -0
- package/templates/restaurant-owner/config.ts +1 -1
- package/templates/restaurant-owner/dev/index.ts +79 -1
- package/templates/restaurant-owner/tier5-src/_shared/aria-chat.ts +176 -6
- package/templates/restaurant-owner/tier5-src/himi-owner-lite-aria/index.ts +15 -0
- package/templates/retail-store-owner/config.ts +1 -1
- package/templates/retail-store-owner/dev/index.ts +79 -1
- package/templates/retail-store-owner/tier5-src/_shared/aria-chat.ts +176 -6
- package/templates/retail-store-owner/tier5-src/himi-owner-lite-aria/index.ts +15 -0
- package/templates/yoga-studio-owner/config.ts +1 -1
- package/templates/yoga-studio-owner/dev/index.ts +79 -1
- package/templates/yoga-studio-owner/tier5-src/_shared/aria-chat.ts +176 -6
- package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-aria/index.ts +15 -0
package/dist/cli.mjs
CHANGED
|
@@ -18715,7 +18715,6 @@ function shouldRevealError(args) {
|
|
|
18715
18715
|
var EMAIL_RE, URL_HOST_RE, INTEGER_RE, NUMBER_RE;
|
|
18716
18716
|
var init_validation = __esm({
|
|
18717
18717
|
"../../core/ts/src/validation.ts"() {
|
|
18718
|
-
"use strict";
|
|
18719
18718
|
EMAIL_RE = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}$/;
|
|
18720
18719
|
URL_HOST_RE = /^[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*(:[0-9]+)?$/;
|
|
18721
18720
|
INTEGER_RE = /^[+-]?[0-9]+$/;
|
|
@@ -22140,7 +22139,6 @@ function validateWorkerSubtree(raw, slotId, policy, actionCatalog) {
|
|
|
22140
22139
|
var WORKER_SUBTREE_CEILINGS, ID_PART, ACTION_ID;
|
|
22141
22140
|
var init_worker_subtree = __esm({
|
|
22142
22141
|
"../../core/ts/src/worker-subtree.ts"() {
|
|
22143
|
-
"use strict";
|
|
22144
22142
|
init_worker_subtree_safe_types_generated();
|
|
22145
22143
|
WORKER_SUBTREE_CEILINGS = Object.freeze({
|
|
22146
22144
|
maxEncodedBytes: 65536,
|
|
@@ -43594,19 +43592,19 @@ var init_preview_assets_generated = __esm({
|
|
|
43594
43592
|
"../../packages/serve/src/preview-assets.generated.ts"() {
|
|
43595
43593
|
init_preview_assets_format();
|
|
43596
43594
|
PREVIEW_ASSET_MANIFEST = [
|
|
43597
|
-
{ key: "assets/index-
|
|
43598
|
-
{ key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset:
|
|
43599
|
-
{ key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset:
|
|
43600
|
-
{ key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset:
|
|
43601
|
-
{ key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset:
|
|
43602
|
-
{ key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset:
|
|
43603
|
-
{ key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset:
|
|
43604
|
-
{ key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset:
|
|
43605
|
-
{ key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset:
|
|
43606
|
-
{ key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset:
|
|
43607
|
-
{ key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset:
|
|
43608
|
-
{ key: "index.html", contentType: "text/html; charset=utf-8", offset:
|
|
43609
|
-
{ key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset:
|
|
43595
|
+
{ key: "assets/index-CRa9DnKn.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 985527, sha256: "1c58488280b45b11e8bbe7fa084de9f7413518465af6e7c9fea5c200befef90b" },
|
|
43596
|
+
{ key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 985535, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
|
|
43597
|
+
{ key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1076459, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
|
|
43598
|
+
{ key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1167443, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
|
|
43599
|
+
{ key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1258423, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
|
|
43600
|
+
{ key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1349295, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
|
|
43601
|
+
{ key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 1440275, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
|
|
43602
|
+
{ key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 1548911, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
|
|
43603
|
+
{ key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 1657995, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
|
|
43604
|
+
{ key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 1767043, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
|
|
43605
|
+
{ key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 1874743, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
|
|
43606
|
+
{ key: "index.html", contentType: "text/html; charset=utf-8", offset: 1962851, length: 4448, sha256: "4cb74dd5b24622561a40f778caca44cb69451235a60d393f210d026f27bd51f6" },
|
|
43607
|
+
{ key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 1967299, length: 13784, sha256: "cfb9465254fab84f0e084bb4542c282758ea29774b5f172840cc0b9e4194ef89" }
|
|
43610
43608
|
];
|
|
43611
43609
|
}
|
|
43612
43610
|
});
|
|
@@ -44152,7 +44150,7 @@ async function runStore(pos, flags, io, deps) {
|
|
|
44152
44150
|
}
|
|
44153
44151
|
let findings;
|
|
44154
44152
|
try {
|
|
44155
|
-
findings = await deps.preflightApp(app);
|
|
44153
|
+
findings = await deps.preflightApp(app, { profileFlag: str2(flags.profile) });
|
|
44156
44154
|
} catch (e) {
|
|
44157
44155
|
return fail2(e.message);
|
|
44158
44156
|
}
|
|
@@ -44425,6 +44423,125 @@ var init_preflight = __esm({
|
|
|
44425
44423
|
}
|
|
44426
44424
|
});
|
|
44427
44425
|
|
|
44426
|
+
// ../store-release/credential-profile.ts
|
|
44427
|
+
var credential_profile_exports = {};
|
|
44428
|
+
__export(credential_profile_exports, {
|
|
44429
|
+
credentialEnv: () => credentialEnv,
|
|
44430
|
+
credentialsDir: () => credentialsDir,
|
|
44431
|
+
maskIssuer: () => maskIssuer,
|
|
44432
|
+
namedProfile: () => namedProfile,
|
|
44433
|
+
parseProfile: () => parseProfile,
|
|
44434
|
+
profilePath: () => profilePath,
|
|
44435
|
+
resolveStoreCredentials: () => resolveStoreCredentials
|
|
44436
|
+
});
|
|
44437
|
+
import { existsSync as existsSync50, readFileSync as readFileSync57 } from "node:fs";
|
|
44438
|
+
import { homedir as homedir6 } from "node:os";
|
|
44439
|
+
import { join as join47 } from "node:path";
|
|
44440
|
+
function credentialsDir(home = homedir6()) {
|
|
44441
|
+
return join47(home, ".himalaya", "store-credentials");
|
|
44442
|
+
}
|
|
44443
|
+
function profilePath(name, home = homedir6()) {
|
|
44444
|
+
if (!PROFILE_NAME.test(name)) {
|
|
44445
|
+
throw new Error(
|
|
44446
|
+
`credential profile ${JSON.stringify(name)} is not a profile name \u2014 use letters, digits, ".", "_" or "-" starting with a letter or digit. It names ${join47(credentialsDir(home), "<name>.json")}; it is never a path.`
|
|
44447
|
+
);
|
|
44448
|
+
}
|
|
44449
|
+
return join47(credentialsDir(home), `${name}.json`);
|
|
44450
|
+
}
|
|
44451
|
+
function parseProfile(text2, label2) {
|
|
44452
|
+
let doc;
|
|
44453
|
+
try {
|
|
44454
|
+
doc = JSON.parse(text2);
|
|
44455
|
+
} catch (e) {
|
|
44456
|
+
throw new Error(`${label2} is not valid JSON: ${e.message}`);
|
|
44457
|
+
}
|
|
44458
|
+
if (!doc || typeof doc !== "object" || Array.isArray(doc)) {
|
|
44459
|
+
throw new Error(`${label2} must be a JSON object with ${FIELDS.join(", ")}.`);
|
|
44460
|
+
}
|
|
44461
|
+
const rec = doc;
|
|
44462
|
+
const out = {};
|
|
44463
|
+
for (const f of FIELDS) {
|
|
44464
|
+
const v = rec[f];
|
|
44465
|
+
if (typeof v !== "string" || !v.trim() || /^TODO/i.test(v.trim())) {
|
|
44466
|
+
throw new Error(`${label2} is missing a usable "${f}" (got ${JSON.stringify(v)}).`);
|
|
44467
|
+
}
|
|
44468
|
+
out[f] = v.trim();
|
|
44469
|
+
}
|
|
44470
|
+
return out;
|
|
44471
|
+
}
|
|
44472
|
+
function namedProfile(cfg, profileFlag) {
|
|
44473
|
+
const ios = cfg.ios ?? {};
|
|
44474
|
+
return profileFlag?.trim() || ios.credentialProfile?.trim() || void 0;
|
|
44475
|
+
}
|
|
44476
|
+
function resolveStoreCredentials(opts) {
|
|
44477
|
+
const { app, cfg } = opts;
|
|
44478
|
+
const env = opts.env ?? process.env;
|
|
44479
|
+
const home = opts.home ?? homedir6();
|
|
44480
|
+
const read = opts.readProfile ?? ((p) => readFileSync57(p, "utf8"));
|
|
44481
|
+
const exists = opts.profileExists ?? existsSync50;
|
|
44482
|
+
const ios = cfg.ios ?? {};
|
|
44483
|
+
const flagName = opts.profileFlag?.trim();
|
|
44484
|
+
const named = namedProfile(cfg, opts.profileFlag);
|
|
44485
|
+
if (named) {
|
|
44486
|
+
const source = flagName ? "flag" : "config";
|
|
44487
|
+
const p = profilePath(named, home);
|
|
44488
|
+
assertCredentialOutsideRepo(`credential profile "${named}"`, p);
|
|
44489
|
+
if (!exists(p)) {
|
|
44490
|
+
throw new Error(
|
|
44491
|
+
`credential profile "${named}" not found at ${p}. Create it with the App Store Connect identifiers for that account: { "team": \u2026, "ascKeyId": \u2026, "ascIssuerId": \u2026, "ascKeyPath": \u2026 }. The .p8 itself stays outside the repo and is never committed.`
|
|
44492
|
+
);
|
|
44493
|
+
}
|
|
44494
|
+
const doc = parseProfile(read(p), `credential profile "${named}" (${p})`);
|
|
44495
|
+
assertCredentialOutsideRepo(`credential profile "${named}" ascKeyPath`, doc.ascKeyPath);
|
|
44496
|
+
if (ios.team && !/^TODO/i.test(ios.team) && ios.team !== doc.team) {
|
|
44497
|
+
throw new Error(
|
|
44498
|
+
`apps/${app}/store/store.config.yaml declares ios.team "${ios.team}" but credential profile "${named}" is for team "${doc.team}". Fix whichever is stale \u2014 never upload to a team the app config does not name.`
|
|
44499
|
+
);
|
|
44500
|
+
}
|
|
44501
|
+
return { ...doc, source, profile: named };
|
|
44502
|
+
}
|
|
44503
|
+
const missing = ["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"].filter((n) => !env[n]);
|
|
44504
|
+
if (missing.length) {
|
|
44505
|
+
throw new Error(
|
|
44506
|
+
`no App Store Connect account resolved for "${app}": ${missing.join(", ")} unset and no credential profile declared. Either export the ASC_* vars, or set ios.credentialProfile in apps/${app}/store/store.config.yaml (see /setup-store-signing).`
|
|
44507
|
+
);
|
|
44508
|
+
}
|
|
44509
|
+
const ascKeyPath = env.ASC_KEY_PATH;
|
|
44510
|
+
assertCredentialOutsideRepo("ASC_KEY_PATH", ascKeyPath);
|
|
44511
|
+
const team = env.HIMALAYA_APPLE_TEAM_ID || ios.team;
|
|
44512
|
+
if (!team || /^TODO/i.test(team)) {
|
|
44513
|
+
throw new Error(
|
|
44514
|
+
`no Apple team for "${app}": set ios.team in apps/${app}/store/store.config.yaml or export HIMALAYA_APPLE_TEAM_ID.`
|
|
44515
|
+
);
|
|
44516
|
+
}
|
|
44517
|
+
return {
|
|
44518
|
+
team,
|
|
44519
|
+
ascKeyId: env.ASC_KEY_ID,
|
|
44520
|
+
ascIssuerId: env.ASC_ISSUER_ID,
|
|
44521
|
+
ascKeyPath,
|
|
44522
|
+
source: "env"
|
|
44523
|
+
};
|
|
44524
|
+
}
|
|
44525
|
+
function credentialEnv(c) {
|
|
44526
|
+
return {
|
|
44527
|
+
ASC_KEY_ID: c.ascKeyId,
|
|
44528
|
+
ASC_ISSUER_ID: c.ascIssuerId,
|
|
44529
|
+
ASC_KEY_PATH: c.ascKeyPath,
|
|
44530
|
+
HIMALAYA_APPLE_TEAM_ID: c.team
|
|
44531
|
+
};
|
|
44532
|
+
}
|
|
44533
|
+
function maskIssuer(issuer) {
|
|
44534
|
+
return issuer.length <= 8 ? issuer : `${issuer.slice(0, 8)}\u2026`;
|
|
44535
|
+
}
|
|
44536
|
+
var PROFILE_NAME, FIELDS;
|
|
44537
|
+
var init_credential_profile = __esm({
|
|
44538
|
+
"../store-release/credential-profile.ts"() {
|
|
44539
|
+
init_preflight();
|
|
44540
|
+
PROFILE_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
44541
|
+
FIELDS = ["team", "ascKeyId", "ascIssuerId", "ascKeyPath"];
|
|
44542
|
+
}
|
|
44543
|
+
});
|
|
44544
|
+
|
|
44428
44545
|
// ../store-release/preflight-app.ts
|
|
44429
44546
|
var preflight_app_exports = {};
|
|
44430
44547
|
__export(preflight_app_exports, {
|
|
@@ -44438,12 +44555,13 @@ __export(preflight_app_exports, {
|
|
|
44438
44555
|
jpegSize: () => jpegSize,
|
|
44439
44556
|
playListingAssets: () => playListingAssets,
|
|
44440
44557
|
pngSize: () => pngSize,
|
|
44441
|
-
preflightApp: () => preflightApp
|
|
44558
|
+
preflightApp: () => preflightApp,
|
|
44559
|
+
profileAccount: () => profileAccount
|
|
44442
44560
|
});
|
|
44443
|
-
import { readFileSync as
|
|
44561
|
+
import { readFileSync as readFileSync58, existsSync as existsSync51, readdirSync as readdirSync24, statSync as statSync10 } from "node:fs";
|
|
44444
44562
|
import { createHash as createHash23 } from "node:crypto";
|
|
44445
|
-
import { join as
|
|
44446
|
-
function analyze(projectYml, storeConfig, icon) {
|
|
44563
|
+
import { join as join48 } from "node:path";
|
|
44564
|
+
function analyze(projectYml, storeConfig, icon, account) {
|
|
44447
44565
|
const f = [];
|
|
44448
44566
|
const has = (re, s) => re.test(s);
|
|
44449
44567
|
const iconNameSet = has(/ASSETCATALOG_COMPILER_APPICON_NAME:\s*\S+/, projectYml);
|
|
@@ -44482,18 +44600,39 @@ function analyze(projectYml, storeConfig, icon) {
|
|
|
44482
44600
|
f.push({ level: "warn", message: "Declares associated-domains \u2192 requires ASSOCIATED_DOMAINS enabled on the App ID (and a real applinks host, not localhost) or signing/AASA breaks. Enable + set the host, or remove the entitlement." });
|
|
44483
44601
|
}
|
|
44484
44602
|
const todo = (key2) => new RegExp(`${key2}:\\s*TODO`).test(storeConfig) || !new RegExp(`${key2}:`).test(storeConfig);
|
|
44485
|
-
if (
|
|
44486
|
-
|
|
44487
|
-
|
|
44603
|
+
if (account) {
|
|
44604
|
+
if (account.error) f.push({ level: "error", message: account.error });
|
|
44605
|
+
} else {
|
|
44606
|
+
if (!/team:\s*\S+/.test(storeConfig) || /team:\s*TODO/.test(storeConfig)) f.push({ level: "error", message: "store.config.yaml ios.team is unset/TODO." });
|
|
44607
|
+
for (const k of ["ascKeyId", "ascIssuerId"]) {
|
|
44608
|
+
if (todo(k)) f.push({ level: "error", message: `store.config.yaml ios.${k} is unset/TODO (needed to sign + upload).` });
|
|
44609
|
+
}
|
|
44488
44610
|
}
|
|
44489
44611
|
if (todo("appStoreId")) f.push({ level: "warn", message: "store.config.yaml ios.appStoreId is unset/TODO \u2014 create the App Store Connect app record first (the API can't), then fill it." });
|
|
44490
44612
|
return f;
|
|
44491
44613
|
}
|
|
44492
|
-
|
|
44493
|
-
const
|
|
44494
|
-
const
|
|
44614
|
+
function profileAccount(app, storeConfig, opts = {}) {
|
|
44615
|
+
const cfg = parseStoreConfig(storeConfig);
|
|
44616
|
+
const profile = namedProfile(cfg, opts.profileFlag);
|
|
44617
|
+
if (!profile) return void 0;
|
|
44618
|
+
try {
|
|
44619
|
+
resolveStoreCredentials({ app, cfg, ...opts });
|
|
44620
|
+
return { profile };
|
|
44621
|
+
} catch (e) {
|
|
44622
|
+
const why = e instanceof Error ? e.message : String(e ?? "");
|
|
44623
|
+
return { profile, error: why.trim() || `credential profile "${profile}" could not be resolved.` };
|
|
44624
|
+
}
|
|
44625
|
+
}
|
|
44626
|
+
async function preflightApp(app, opts = {}) {
|
|
44627
|
+
const projectYml = existsSync51(iosProjectYml(app)) ? readFileSync58(iosProjectYml(app), "utf8") : "";
|
|
44628
|
+
const storeConfig = existsSync51(storeConfigPath(app)) ? readFileSync58(storeConfigPath(app), "utf8") : "";
|
|
44495
44629
|
if (!storeConfig) return [{ level: "error", message: `no apps/${app}/store/store.config.yaml \u2014 run /setup-store-signing first.` }];
|
|
44496
|
-
const findings = analyze(
|
|
44630
|
+
const findings = analyze(
|
|
44631
|
+
projectYml,
|
|
44632
|
+
storeConfig,
|
|
44633
|
+
await appIconState(join48(appDir(app), "ios")),
|
|
44634
|
+
profileAccount(app, storeConfig, opts)
|
|
44635
|
+
);
|
|
44497
44636
|
findings.push(...analyzeListing(metadataFilesPresent(app), listScreenshots(app)));
|
|
44498
44637
|
findings.push(
|
|
44499
44638
|
...analyzePlayListing(playListingAssets(app)).map((finding) => ({ ...finding, level: "warn" }))
|
|
@@ -44520,17 +44659,17 @@ function analyzeSubmissionRecord(appLevel, review, opts) {
|
|
|
44520
44659
|
return f;
|
|
44521
44660
|
}
|
|
44522
44661
|
function appLevelMetadataFiles(app, locale = "en-US") {
|
|
44523
|
-
const root =
|
|
44662
|
+
const root = join48(storeDir(app), "metadata");
|
|
44524
44663
|
const out = /* @__PURE__ */ new Set();
|
|
44525
|
-
if (
|
|
44664
|
+
if (existsSync51(root)) {
|
|
44526
44665
|
for (const n of readdirSync24(root)) if (n.endsWith(".txt")) out.add(n);
|
|
44527
44666
|
}
|
|
44528
|
-
if (
|
|
44667
|
+
if (existsSync51(join48(root, locale, "privacy_url.txt"))) out.add("privacy_url.txt");
|
|
44529
44668
|
return out;
|
|
44530
44669
|
}
|
|
44531
44670
|
function reviewInfoFiles(app) {
|
|
44532
|
-
const dir =
|
|
44533
|
-
if (!
|
|
44671
|
+
const dir = join48(storeDir(app), "review_information");
|
|
44672
|
+
if (!existsSync51(dir)) return /* @__PURE__ */ new Set();
|
|
44534
44673
|
return new Set(readdirSync24(dir).filter((n) => n.endsWith(".txt")));
|
|
44535
44674
|
}
|
|
44536
44675
|
function isValidAppStoreSize(w, h) {
|
|
@@ -44640,12 +44779,12 @@ function analyzePlayListing(assets) {
|
|
|
44640
44779
|
return f;
|
|
44641
44780
|
}
|
|
44642
44781
|
function playListingAssets(app, locale = "en-US") {
|
|
44643
|
-
const dir =
|
|
44782
|
+
const dir = join48(storeDir(app), "play", locale, "images");
|
|
44644
44783
|
const read = (names) => {
|
|
44645
44784
|
for (const name of names) {
|
|
44646
|
-
const p =
|
|
44785
|
+
const p = join48(dir, name);
|
|
44647
44786
|
try {
|
|
44648
|
-
if (statSync10(p).isFile()) return { name, bytes:
|
|
44787
|
+
if (statSync10(p).isFile()) return { name, bytes: readFileSync58(p) };
|
|
44649
44788
|
} catch {
|
|
44650
44789
|
}
|
|
44651
44790
|
}
|
|
@@ -44676,26 +44815,26 @@ function analyzeListing(metaFiles, shots) {
|
|
|
44676
44815
|
return f;
|
|
44677
44816
|
}
|
|
44678
44817
|
function metadataFilesPresent(app, locale = "en-US") {
|
|
44679
|
-
const dir =
|
|
44680
|
-
if (!
|
|
44818
|
+
const dir = join48(storeDir(app), "metadata", locale);
|
|
44819
|
+
if (!existsSync51(dir)) return /* @__PURE__ */ new Set();
|
|
44681
44820
|
return new Set(readdirSync24(dir).filter((n) => n.endsWith(".txt")));
|
|
44682
44821
|
}
|
|
44683
44822
|
function listScreenshots(app, locale = "en-US") {
|
|
44684
44823
|
const out = [];
|
|
44685
|
-
const flat =
|
|
44686
|
-
if (
|
|
44824
|
+
const flat = join48(storeDir(app), "screenshots", locale);
|
|
44825
|
+
if (existsSync51(flat)) {
|
|
44687
44826
|
for (const png of readdirSync24(flat).filter((n) => n.endsWith(".png"))) {
|
|
44688
|
-
const sz = pngSize(
|
|
44827
|
+
const sz = pngSize(readFileSync58(join48(flat, png)));
|
|
44689
44828
|
if (sz) out.push({ name: png, w: sz.w, h: sz.h });
|
|
44690
44829
|
}
|
|
44691
44830
|
}
|
|
44692
|
-
const legacy =
|
|
44693
|
-
if (
|
|
44831
|
+
const legacy = join48(storeDir(app), "metadata", locale, "screenshots");
|
|
44832
|
+
if (existsSync51(legacy)) {
|
|
44694
44833
|
for (const deviceDir of readdirSync24(legacy)) {
|
|
44695
|
-
const d =
|
|
44834
|
+
const d = join48(legacy, deviceDir);
|
|
44696
44835
|
if (!statSync10(d).isDirectory()) continue;
|
|
44697
44836
|
for (const png of readdirSync24(d).filter((n) => n.endsWith(".png"))) {
|
|
44698
|
-
const sz = pngSize(
|
|
44837
|
+
const sz = pngSize(readFileSync58(join48(d, png)));
|
|
44699
44838
|
if (sz) out.push({ name: `${deviceDir}/${png}`, w: sz.w, h: sz.h });
|
|
44700
44839
|
}
|
|
44701
44840
|
}
|
|
@@ -44703,13 +44842,13 @@ function listScreenshots(app, locale = "en-US") {
|
|
|
44703
44842
|
return out;
|
|
44704
44843
|
}
|
|
44705
44844
|
function placeholderHashes2() {
|
|
44706
|
-
const templateIos =
|
|
44707
|
-
if (!
|
|
44845
|
+
const templateIos = join48(appDir("_template"), "ios");
|
|
44846
|
+
if (!existsSync51(templateIos)) return [LEGACY_PLACEHOLDER_SHA2562];
|
|
44708
44847
|
for (const target of readdirSync24(templateIos)) {
|
|
44709
|
-
const p =
|
|
44848
|
+
const p = join48(templateIos, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
|
|
44710
44849
|
try {
|
|
44711
44850
|
if (!statSync10(p).isFile()) continue;
|
|
44712
|
-
return [LEGACY_PLACEHOLDER_SHA2562, createHash23("sha256").update(
|
|
44851
|
+
return [LEGACY_PLACEHOLDER_SHA2562, createHash23("sha256").update(readFileSync58(p)).digest("hex")];
|
|
44713
44852
|
} catch {
|
|
44714
44853
|
}
|
|
44715
44854
|
}
|
|
@@ -44740,12 +44879,12 @@ async function pixelIssues(bytes2) {
|
|
|
44740
44879
|
}
|
|
44741
44880
|
}
|
|
44742
44881
|
async function appIconState(iosDir) {
|
|
44743
|
-
if (!
|
|
44882
|
+
if (!existsSync51(iosDir)) return { exists: false, isPlaceholder: false, storeIssues: [] };
|
|
44744
44883
|
for (const target of readdirSync24(iosDir)) {
|
|
44745
|
-
const p =
|
|
44884
|
+
const p = join48(iosDir, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
|
|
44746
44885
|
try {
|
|
44747
44886
|
if (!statSync10(p).isFile()) continue;
|
|
44748
|
-
const bytes2 =
|
|
44887
|
+
const bytes2 = readFileSync58(p);
|
|
44749
44888
|
const hash = createHash23("sha256").update(bytes2).digest("hex");
|
|
44750
44889
|
const pixels = await pixelIssues(bytes2);
|
|
44751
44890
|
return {
|
|
@@ -44783,6 +44922,7 @@ var init_preflight_app = __esm({
|
|
|
44783
44922
|
"../store-release/preflight-app.ts"() {
|
|
44784
44923
|
init_paths();
|
|
44785
44924
|
init_preflight();
|
|
44925
|
+
init_credential_profile();
|
|
44786
44926
|
init_app_icon_rules();
|
|
44787
44927
|
APP_STORE_SIZES = [
|
|
44788
44928
|
[1320, 2868],
|
|
@@ -44805,114 +44945,6 @@ var init_preflight_app = __esm({
|
|
|
44805
44945
|
}
|
|
44806
44946
|
});
|
|
44807
44947
|
|
|
44808
|
-
// ../store-release/credential-profile.ts
|
|
44809
|
-
var credential_profile_exports = {};
|
|
44810
|
-
__export(credential_profile_exports, {
|
|
44811
|
-
credentialEnv: () => credentialEnv,
|
|
44812
|
-
credentialsDir: () => credentialsDir,
|
|
44813
|
-
maskIssuer: () => maskIssuer,
|
|
44814
|
-
parseProfile: () => parseProfile,
|
|
44815
|
-
profilePath: () => profilePath,
|
|
44816
|
-
resolveStoreCredentials: () => resolveStoreCredentials
|
|
44817
|
-
});
|
|
44818
|
-
import { existsSync as existsSync51, readFileSync as readFileSync58 } from "node:fs";
|
|
44819
|
-
import { homedir as homedir6 } from "node:os";
|
|
44820
|
-
import { join as join48 } from "node:path";
|
|
44821
|
-
function credentialsDir(home = homedir6()) {
|
|
44822
|
-
return join48(home, ".himalaya", "store-credentials");
|
|
44823
|
-
}
|
|
44824
|
-
function profilePath(name, home = homedir6()) {
|
|
44825
|
-
return join48(credentialsDir(home), `${name}.json`);
|
|
44826
|
-
}
|
|
44827
|
-
function parseProfile(text2, label2) {
|
|
44828
|
-
let doc;
|
|
44829
|
-
try {
|
|
44830
|
-
doc = JSON.parse(text2);
|
|
44831
|
-
} catch (e) {
|
|
44832
|
-
throw new Error(`${label2} is not valid JSON: ${e.message}`);
|
|
44833
|
-
}
|
|
44834
|
-
if (!doc || typeof doc !== "object" || Array.isArray(doc)) {
|
|
44835
|
-
throw new Error(`${label2} must be a JSON object with ${FIELDS.join(", ")}.`);
|
|
44836
|
-
}
|
|
44837
|
-
const rec = doc;
|
|
44838
|
-
const out = {};
|
|
44839
|
-
for (const f of FIELDS) {
|
|
44840
|
-
const v = rec[f];
|
|
44841
|
-
if (typeof v !== "string" || !v.trim() || /^TODO/i.test(v.trim())) {
|
|
44842
|
-
throw new Error(`${label2} is missing a usable "${f}" (got ${JSON.stringify(v)}).`);
|
|
44843
|
-
}
|
|
44844
|
-
out[f] = v.trim();
|
|
44845
|
-
}
|
|
44846
|
-
return out;
|
|
44847
|
-
}
|
|
44848
|
-
function resolveStoreCredentials(opts) {
|
|
44849
|
-
const { app, cfg } = opts;
|
|
44850
|
-
const env = opts.env ?? process.env;
|
|
44851
|
-
const home = opts.home ?? homedir6();
|
|
44852
|
-
const read = opts.readProfile ?? ((p) => readFileSync58(p, "utf8"));
|
|
44853
|
-
const exists = opts.profileExists ?? existsSync51;
|
|
44854
|
-
const ios = cfg.ios ?? {};
|
|
44855
|
-
const flagName = opts.profileFlag?.trim();
|
|
44856
|
-
const named = flagName || ios.credentialProfile?.trim();
|
|
44857
|
-
if (named) {
|
|
44858
|
-
const source = flagName ? "flag" : "config";
|
|
44859
|
-
const p = profilePath(named, home);
|
|
44860
|
-
assertCredentialOutsideRepo(`credential profile "${named}"`, p);
|
|
44861
|
-
if (!exists(p)) {
|
|
44862
|
-
throw new Error(
|
|
44863
|
-
`credential profile "${named}" not found at ${p}. Create it with the App Store Connect identifiers for that account: { "team": \u2026, "ascKeyId": \u2026, "ascIssuerId": \u2026, "ascKeyPath": \u2026 }. The .p8 itself stays outside the repo and is never committed.`
|
|
44864
|
-
);
|
|
44865
|
-
}
|
|
44866
|
-
const doc = parseProfile(read(p), `credential profile "${named}" (${p})`);
|
|
44867
|
-
assertCredentialOutsideRepo(`credential profile "${named}" ascKeyPath`, doc.ascKeyPath);
|
|
44868
|
-
if (ios.team && !/^TODO/i.test(ios.team) && ios.team !== doc.team) {
|
|
44869
|
-
throw new Error(
|
|
44870
|
-
`apps/${app}/store/store.config.yaml declares ios.team "${ios.team}" but credential profile "${named}" is for team "${doc.team}". Fix whichever is stale \u2014 never upload to a team the app config does not name.`
|
|
44871
|
-
);
|
|
44872
|
-
}
|
|
44873
|
-
return { ...doc, source, profile: named };
|
|
44874
|
-
}
|
|
44875
|
-
const missing = ["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"].filter((n) => !env[n]);
|
|
44876
|
-
if (missing.length) {
|
|
44877
|
-
throw new Error(
|
|
44878
|
-
`no App Store Connect account resolved for "${app}": ${missing.join(", ")} unset and no credential profile declared. Either export the ASC_* vars, or set ios.credentialProfile in apps/${app}/store/store.config.yaml (see /setup-store-signing).`
|
|
44879
|
-
);
|
|
44880
|
-
}
|
|
44881
|
-
const ascKeyPath = env.ASC_KEY_PATH;
|
|
44882
|
-
assertCredentialOutsideRepo("ASC_KEY_PATH", ascKeyPath);
|
|
44883
|
-
const team = env.HIMALAYA_APPLE_TEAM_ID || ios.team;
|
|
44884
|
-
if (!team || /^TODO/i.test(team)) {
|
|
44885
|
-
throw new Error(
|
|
44886
|
-
`no Apple team for "${app}": set ios.team in apps/${app}/store/store.config.yaml or export HIMALAYA_APPLE_TEAM_ID.`
|
|
44887
|
-
);
|
|
44888
|
-
}
|
|
44889
|
-
return {
|
|
44890
|
-
team,
|
|
44891
|
-
ascKeyId: env.ASC_KEY_ID,
|
|
44892
|
-
ascIssuerId: env.ASC_ISSUER_ID,
|
|
44893
|
-
ascKeyPath,
|
|
44894
|
-
source: "env"
|
|
44895
|
-
};
|
|
44896
|
-
}
|
|
44897
|
-
function credentialEnv(c) {
|
|
44898
|
-
return {
|
|
44899
|
-
ASC_KEY_ID: c.ascKeyId,
|
|
44900
|
-
ASC_ISSUER_ID: c.ascIssuerId,
|
|
44901
|
-
ASC_KEY_PATH: c.ascKeyPath,
|
|
44902
|
-
HIMALAYA_APPLE_TEAM_ID: c.team
|
|
44903
|
-
};
|
|
44904
|
-
}
|
|
44905
|
-
function maskIssuer(issuer) {
|
|
44906
|
-
return issuer.length <= 8 ? issuer : `${issuer.slice(0, 8)}\u2026`;
|
|
44907
|
-
}
|
|
44908
|
-
var FIELDS;
|
|
44909
|
-
var init_credential_profile = __esm({
|
|
44910
|
-
"../store-release/credential-profile.ts"() {
|
|
44911
|
-
init_preflight();
|
|
44912
|
-
FIELDS = ["team", "ascKeyId", "ascIssuerId", "ascKeyPath"];
|
|
44913
|
-
}
|
|
44914
|
-
});
|
|
44915
|
-
|
|
44916
44948
|
// ../store-release/version.ts
|
|
44917
44949
|
var version_exports = {};
|
|
44918
44950
|
__export(version_exports, {
|
|
@@ -55195,8 +55227,10 @@ var USAGE = `himi \u2014 the Himalaya authoring CLI (remote dev loop)
|
|
|
55195
55227
|
--release <published-release-id> --version <x.y.z> --yes --target bo.
|
|
55196
55228
|
Job Service builds the IPA; deployed serve validates it, then
|
|
55197
55229
|
invokes MRE with its service identity. This is separate from QA himi dist.
|
|
55198
|
-
himi store preflight <app> [--json]
|
|
55199
|
-
|
|
55230
|
+
himi store preflight <app> [--profile <name>] [--json]
|
|
55231
|
+
readiness only \u2014 icon, entitlements, encryption flag,
|
|
55232
|
+
version, store.config ids (or the --profile /
|
|
55233
|
+
ios.credentialProfile account), listing + review record.
|
|
55200
55234
|
No network, nothing built.
|
|
55201
55235
|
himi store upload <app> [--track <t>] [--profile <name>] [--yes] [--dry-run]
|
|
55202
55236
|
the same upload himi testflight runs.
|
|
@@ -55408,7 +55442,7 @@ var COMMANDS = [
|
|
|
55408
55442
|
{ name: "visibility", summary: "read (no value) or set whether the public registry (/v1/apps + the Himi Player picker) LISTS the app. `public` lists it for everyone; `unlisted` hides it from listings while direct reads by app id \u2014 deep links, previews \u2014 keep working. App from --app or the content dir. Setting it needs no republish.", required: "[public|unlisted] [--app <a>] [--content <dir>] (--control-token)" },
|
|
55409
55443
|
{ name: "dist", summary: "build an INSTALLABLE QA binary (signed IPA / APK) on the Wix Job Service Mac pool and return an install link \u2014 the serve plane brokers the job, the pool builds it. WAITS for the build by default (~4 min) and prints the install link; `--no-wait` returns a jobId immediately instead. Omitting `--release` builds whatever is LIVE for the app. A named draft is refused unless `--allow-draft` makes that exceptional build explicit. `status <jobId>` / `watch <jobId>` / `list --app <a>` / `cancel <jobId>` inspect and stop builds (`watch` reports up front whether the job mints its own signing identity or borrows one, so a doomed iOS build is cancellable in seconds rather than after the archive). Off-repo, name a target \u2014 `--target wix` for a self-serve Wix login or `--target bo` for the internal employee path (the in-repo default is a local dev plane that isn't reachable off-repo); self-serve callers may build their OWN apps under a tighter budget (2 in flight / 5 per 24h), while a manage-only owner-role credential is refused. `--shell` picks the native host to sign into (branded-lite | owner-lite | player | demo-app). `--signing` defaults to `wix-managed` \u2014 the Wix Apple account mints a per-app signing identity for the build, so the caller provisions no Apple credentials of their own; `--signing byo` (sign with your own Apple account) is reserved and 501s. `--android-signing` is the Android counterpart and a SEPARATE axis (a keystore, not an Apple account): `qa-keystore` (default \u2014 the repo's committed QA key, identical on every pool machine, so a build installs over the previous one), `wix-keystore` (the Wix key the pool machine carries; the build FAILS naming the paths searched if it carries none, rather than quietly signing with something else), or `debug` (the old per-machine key \u2014 QA must uninstall any previous build first). NOT the normal way to ship: screens, Tier-5 bundles, tokens and app-config all go over the air with `himi push` in seconds \u2014 a binary trip is only needed for a NATIVE delta (a new SDUI component, a new declared capability/entitlement, a new bundle id, or a minBinaryVersion floor bump). Refuses to build an app whose launcher icon is missing, a placeholder, or one a store would reject \u2014 the one thing a binary carries that no later OTA push can fix; `--force` builds anyway", required: "[--app <a>] [--platform ios,android] [--release <id>] [--allow-draft] [--target <t>] [--shell branded-lite|owner-lite|player|demo-app] [--signing wix-managed|byo] [--android-signing qa-keystore|wix-keystore|debug] [--borrow-ios-id <bundleId>] [--no-wait] [--force] | status <jobId> [--target <t>] | watch <jobId> [--target <t>] [--interval <ms>] | list --app <a> [--target <t>] | cancel <jobId> [--target <t>]" },
|
|
55410
55444
|
{ name: "testflight", summary: 'build, sign and upload an app to TestFlight (internal testers \u2014 no Beta App Review), then WAIT until App Store Connect finishes processing it. Sugar for `store upload --track testflight`. Prompts first: a build number is consumed permanently on a real Apple account and cannot be reused \u2014 `--yes` for CI, `--dry-run` to see the plan without touching anything. The wait is the real check, not a nicety: fastlane prints "Successfully uploaded" for a binary App Store Connect then rejects in processing, and a rejected binary leaves NO build record at all (the reason is emailed). Public App Store review is deliberately NOT automatable here \u2014 `--track appstore` is refused; use /submit-ios-app when you mean to go public', required: "<app> [--track testflight|internal] [--profile <name>] [--yes] [--dry-run] [--skip-build] [--no-wait] [--json]" },
|
|
55411
|
-
{ name: "store", summary: "the App Store Connect group behind `testflight`. `preflight <app>` checks readiness offline (icon, entitlements, encryption flag, version, store.config ids, listing + review record); `upload <app>` is what `testflight` runs; `status <app>` reads live build + processing state. `--profile` selects WHICH App Store Connect account: an app built for a Wix customer ships under the CUSTOMER's Apple team (Apple guideline 4.2.6 forbids an app-generation service submitting on a client's behalf), declared per-app as ios.credentialProfile in store.config.yaml and resolved from ~/.himalaya/store-credentials/<name>.json \u2014 the .p8 itself never enters the repo", required: "preflight <app> | upload <app> [--track <t>] [--profile <n>] [--yes] [--dry-run] | status <app> [--profile <n>]" },
|
|
55445
|
+
{ name: "store", summary: "the App Store Connect group behind `testflight`. `preflight <app>` checks readiness offline (icon, entitlements, encryption flag, version, store.config ids, listing + review record); `upload <app>` is what `testflight` runs; `status <app>` reads live build + processing state. `--profile` selects WHICH App Store Connect account: an app built for a Wix customer ships under the CUSTOMER's Apple team (Apple guideline 4.2.6 forbids an app-generation service submitting on a client's behalf), declared per-app as ios.credentialProfile in store.config.yaml and resolved from ~/.himalaya/store-credentials/<name>.json \u2014 the .p8 itself never enters the repo", required: "preflight <app> [--profile <n>] | upload <app> [--track <t>] [--profile <n>] [--yes] [--dry-run] | status <app> [--profile <n>]" },
|
|
55412
55446
|
{ name: "guide", summary: "print the Himalaya overview + headless dev loop + available topics (offline)", required: "[--json]" },
|
|
55413
55447
|
{ name: "docs", summary: "print an authoring guide; no topic = list them (offline)", required: "[<topic>] [--json]" },
|
|
55414
55448
|
{ name: "components", summary: "print the SDUI component vocabulary + props; a name = that component (offline)", required: "[<Name>] [--json]" },
|
|
Binary file
|
|
@@ -515,14 +515,18 @@ What the host guarantees, on every surface:
|
|
|
515
515
|
window stays visible while unfocused), and a **React Native** host must pass
|
|
516
516
|
`installPollLifecycle: makeAppStatePollLifecycle(AppState)` or it never suspends there
|
|
517
517
|
either. See the RFC's per-surface table.
|
|
518
|
-
- **
|
|
518
|
+
- **Worker teardown cancels it; leaving a pooled screen pauses it.** The timer starts with
|
|
519
|
+
the worker and dies with it. A host that keeps a navigated-away screen's worker warm in
|
|
520
|
+
a keep-alive pool suspends its poll while it sits there — it fires immediately when the
|
|
521
|
+
screen reappears, then resumes cadence. The poll ends only when the worker itself is
|
|
522
|
+
torn down: evicted from the pool, or the pool reset.
|
|
519
523
|
|
|
520
524
|
Two things to know before you reach for it:
|
|
521
525
|
|
|
522
526
|
- **`_poll` has no stop form.** The directive can start and replace a poll, not end one.
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
527
|
+
Worker teardown is the only stop; navigating away from a pooled screen pauses the poll
|
|
528
|
+
rather than ending it. Pick a cadence you would be comfortable running on several
|
|
529
|
+
screens at once.
|
|
526
530
|
- **Emit it from the action that runs on every entry**, not only from a first-open path.
|
|
527
531
|
Restored worker state re-paints data but arms no timer, so a poll armed only by `open`
|
|
528
532
|
restores into a screen that *looks* live and never refreshes.
|
|
@@ -137,6 +137,16 @@ The plane has no headless browser (`look.unavailable: no_browser_on_plane`). Own
|
|
|
137
137
|
|
|
138
138
|
`--apply` writes `appearance.homeLayout` + `navigation.navKind` plus identity/colors. It never silently overwrites committed Amit1 `apps/himi-branded-lite/provisioning.json`.
|
|
139
139
|
|
|
140
|
+
When the analysis recognized at least one vertical, `--apply` also patches the shell's baked home
|
|
141
|
+
(`dev/index.ts`) to what the site actually runs. The Explore grid keeps only the site's
|
|
142
|
+
destinations (adding a card the template baked none for, and leaving off a vertical the template
|
|
143
|
+
ships no screen for); home modules that no installed vertical can fill are dropped; and a site
|
|
144
|
+
without `store` loses the home's Shop calls to action, including the one nested in the
|
|
145
|
+
`retail-store` store-first layout. The store screens themselves are untouched — only the home
|
|
146
|
+
stops linking to them. The apply notes name every removed call to action and every installed
|
|
147
|
+
vertical left off Explore, so an intentional omission is distinguishable from a failed patch. An
|
|
148
|
+
analysis with no recognized vertical leaves the home exactly as shipped.
|
|
149
|
+
|
|
140
150
|
It also writes **`cmsCollections`** — the customer's own CMS collections, always present and possibly `[]`. The overlay used to carry no such key, and an absent key inherits the shell's, so an applied app advertised and **queried** the shell's demo collection: another tenant's data model under the customer's brand. `[]` is therefore a value, not an absence — it clears the shell's list and the CMS screen shows its own empty state.
|
|
141
151
|
|
|
142
152
|
Only a collection a shipped app can read **as a visitor** is carried, because `readCms` lists with an **owner** token and the app has no such session. An `ADMIN` read is dropped (no session the app can hold will ever satisfy it), and so is a **member-gated** one — not because the app cannot read it, but because the CMS worker caches fetched rows in the unencrypted `cms_items` store, which outlives the member's session and would be served to the next visitor on the device ([cms-collections.md](cms-collections.md)). A Wix app's own collection (`ownerAppId`) is dropped too; its vertical already renders it. So are the four other ways a collection misses the app, because they need different remedies and are indistinguishable in the artifact: **no owner token** (nothing was looked at), the listing **failing** (any status but 404 — re-authenticate, widen the Wix Data grant, or retry a 429; a 404 means the app is not on the site, which is simply "no collections"), the listing **cap** of 24 counted against the server's `pagingMetadata.total` (the rest were never read), and an **id that cannot be carried unchanged** (surrounded by whitespace, carrying a control character, or over 256 chars — normalizing it would name a different collection in a manifest that still loads). A site that simply has none says nothing — that is the ordinary state, and `--apply` leads its note with warnings.
|
|
@@ -167,11 +167,14 @@ book says which happened on the `cms collections:` line (`(skipped: no owner tok
|
|
|
167
167
|
The `clientId`-is-the-binding rule above is about the **app's** runtime site binding, not this.
|
|
168
168
|
|
|
169
169
|
`--apply` writes `provisioning.json` + token **values**, and patches the branded-lite
|
|
170
|
-
home `onAppear` params (`ownerDefaultLayout`, `brandAccent`,
|
|
171
|
-
`
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
170
|
+
home in `dev/index.ts`: its `onAppear` params (`ownerDefaultLayout`, `brandAccent`,
|
|
171
|
+
`verticals`) and, when the analysis recognized any vertical, the Explore grid, the home
|
|
172
|
+
modules and — on a site without `store` — the Shop calls to action, naming what it
|
|
173
|
+
removed in its notes (`himi docs wix-business-context`). It does **not** rewrite
|
|
174
|
+
`config.ts` tabBar — you still set 2–4 Hebrew/RTL tabs to the site's jobs. If home still
|
|
175
|
+
renders the English Shop/Book/Explore hub after `--apply`, the home patch missed (no
|
|
176
|
+
`dev/index.ts`, a custom home screen, or an analysis with no recognized vertical) — set
|
|
177
|
+
`ownerDefaultLayout` and the home content by hand.
|
|
175
178
|
|
|
176
179
|
**Look:** merge `--wst-*` into `tokens.json` **values only** (`himi docs tokens`), and only into
|
|
177
180
|
the **light** arm — a scraped website colour is never a dark-mode colour, so let the app's own
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.971.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "himi — the Himalaya authoring CLI. Build a Tier-5 content package on your own machine, push it to the production serve as a draft, preview it on web + Himi Player, and read worker logs back — the remote dev loop. Wraps @himalaya/serve-cli for transport.",
|
|
6
6
|
"keywords": [
|
|
@@ -64,5 +64,5 @@
|
|
|
64
64
|
"artifactId": "himalaya-cli"
|
|
65
65
|
}
|
|
66
66
|
},
|
|
67
|
-
"falconPackageHash": "
|
|
67
|
+
"falconPackageHash": "dc35d80213a50f83892eb491d6ec9afd8cf09def367013281612b0aa"
|
|
68
68
|
}
|
|
@@ -37,7 +37,7 @@ export default defineApp({
|
|
|
37
37
|
actions: "http://localhost:8190/v1/actions",
|
|
38
38
|
sync: "http://localhost:8190/v1/sync",
|
|
39
39
|
},
|
|
40
|
-
capabilities: ["live_activity","push","share","secure_storage","open_url","local_database"],
|
|
40
|
+
capabilities: ["live_activity","push","share","secure_storage","open_url","local_database","clipboard"],
|
|
41
41
|
designTokensPath: "./tokens.json",
|
|
42
42
|
navigation: {
|
|
43
43
|
"navKind": "responsive",
|