@wix/himalaya-cli 0.1351.0 → 0.1352.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 +538 -71
- package/guides/himi-json-output.md +26 -1
- package/package.json +2 -2
package/dist/cli.mjs
CHANGED
|
@@ -7706,7 +7706,6 @@ function resolveTranslation(value, catalog3, sourceCatalog) {
|
|
|
7706
7706
|
var BINDING_SIGILS, BINDING_SIGIL_RE, TRANSLATION_PREFIX, TRANSLATION_KEY_RE;
|
|
7707
7707
|
var init_bindings = __esm({
|
|
7708
7708
|
"../../core/ts/src/bindings.ts"() {
|
|
7709
|
-
"use strict";
|
|
7710
7709
|
BINDING_SIGILS = ["service", "flag", "item", "t"];
|
|
7711
7710
|
BINDING_SIGIL_RE = new RegExp(
|
|
7712
7711
|
`^\\$(?:${BINDING_SIGILS.filter((s2) => s2 !== "t").join("|")})\\b|^\\$t:`
|
|
@@ -32826,8 +32825,15 @@ var init_app_identity = __esm({
|
|
|
32826
32825
|
});
|
|
32827
32826
|
|
|
32828
32827
|
// ../../core/ts/src/registry-app-normalize.ts
|
|
32828
|
+
function isPlayerRequirements(v2) {
|
|
32829
|
+
if (!v2 || typeof v2 !== "object") return false;
|
|
32830
|
+
const r2 = v2;
|
|
32831
|
+
return PLAYER_REQUIREMENT_KINDS.every((kind) => Array.isArray(r2[kind]) && r2[kind].every((id) => typeof id === "string"));
|
|
32832
|
+
}
|
|
32833
|
+
var PLAYER_REQUIREMENT_KINDS;
|
|
32829
32834
|
var init_registry_app_normalize = __esm({
|
|
32830
32835
|
"../../core/ts/src/registry-app-normalize.ts"() {
|
|
32836
|
+
PLAYER_REQUIREMENT_KINDS = ["capabilities", "nativeComponents", "authProviders"];
|
|
32831
32837
|
}
|
|
32832
32838
|
});
|
|
32833
32839
|
|
|
@@ -37418,7 +37424,7 @@ function newRicosRequestId() {
|
|
|
37418
37424
|
async function runRicosImageUpload(o2) {
|
|
37419
37425
|
const { session, uploadService: svc, requestId: requestId2, file: file2, deps } = o2;
|
|
37420
37426
|
const t2 = deps.timers ?? { setTimeout: (fn2, ms2) => setTimeout(fn2, ms2), clearTimeout: (h2) => clearTimeout(h2) };
|
|
37421
|
-
const
|
|
37427
|
+
const fail5 = (reason) => {
|
|
37422
37428
|
session.failMedia(requestId2);
|
|
37423
37429
|
return { ok: false, reason };
|
|
37424
37430
|
};
|
|
@@ -37444,32 +37450,32 @@ async function runRicosImageUpload(o2) {
|
|
|
37444
37450
|
});
|
|
37445
37451
|
deps.dispatch({ actionId: `tier5.${svc}.genUpload`, args: { requestId: requestId2, mimeType: file2.mimeType, fileName: file2.fileName, ...file2.sizeBytes !== void 0 ? { sizeBytes: file2.sizeBytes } : {} } });
|
|
37446
37452
|
});
|
|
37447
|
-
if (!entry) return
|
|
37448
|
-
if (entry.status !== "ready" || !entry.uploadUrl || !/^https:\/\//i.test(entry.uploadUrl)) return
|
|
37453
|
+
if (!entry) return fail5("timeout");
|
|
37454
|
+
if (entry.status !== "ready" || !entry.uploadUrl || !/^https:\/\//i.test(entry.uploadUrl)) return fail5("gen_upload");
|
|
37449
37455
|
let body;
|
|
37450
37456
|
try {
|
|
37451
37457
|
body = typeof file2.body === "function" ? await file2.body() : file2.body;
|
|
37452
37458
|
} catch {
|
|
37453
|
-
return
|
|
37459
|
+
return fail5("read");
|
|
37454
37460
|
}
|
|
37455
37461
|
const sep21 = entry.uploadUrl.includes("?") ? "&" : "?";
|
|
37456
37462
|
let res;
|
|
37457
37463
|
try {
|
|
37458
37464
|
res = await deps.fetch(`${entry.uploadUrl}${sep21}filename=${encodeURIComponent(file2.fileName)}`, { method: "PUT", headers: { "Content-Type": file2.mimeType }, body });
|
|
37459
37465
|
} catch {
|
|
37460
|
-
return
|
|
37466
|
+
return fail5("put");
|
|
37461
37467
|
}
|
|
37462
|
-
if (!res.ok) return
|
|
37468
|
+
if (!res.ok) return fail5("put");
|
|
37463
37469
|
let json6;
|
|
37464
37470
|
try {
|
|
37465
37471
|
json6 = await res.json();
|
|
37466
37472
|
} catch {
|
|
37467
|
-
return
|
|
37473
|
+
return fail5("bad_descriptor");
|
|
37468
37474
|
}
|
|
37469
37475
|
const root = json6 && typeof json6 === "object" ? json6 : {};
|
|
37470
37476
|
const d2 = root.file && typeof root.file === "object" ? root.file : root;
|
|
37471
37477
|
const id = typeof d2.id === "string" ? d2.id : "";
|
|
37472
|
-
if (!id) return
|
|
37478
|
+
if (!id) return fail5("bad_descriptor");
|
|
37473
37479
|
const ok2 = session.resolveMedia(requestId2, {
|
|
37474
37480
|
id,
|
|
37475
37481
|
url: typeof d2.url === "string" ? d2.url : "",
|
|
@@ -134518,7 +134524,7 @@ async function crawlScreen(opts) {
|
|
|
134518
134524
|
async function crawlScreenJourney(opts) {
|
|
134519
134525
|
return withSwallowedRejections(async () => {
|
|
134520
134526
|
const findings = [];
|
|
134521
|
-
const
|
|
134527
|
+
const fail5 = (message, step) => {
|
|
134522
134528
|
findings.push({
|
|
134523
134529
|
screen: opts.screenId,
|
|
134524
134530
|
trigger: step ? { tap: step.component ?? null, key: "journey", action: step.action } : "boot",
|
|
@@ -134529,7 +134535,7 @@ async function crawlScreenJourney(opts) {
|
|
|
134529
134535
|
});
|
|
134530
134536
|
};
|
|
134531
134537
|
if (!opts.bundleJs) {
|
|
134532
|
-
|
|
134538
|
+
fail5(`journey "${opts.journey.name}" targets a screen without a worker bundle`);
|
|
134533
134539
|
return { screen: opts.screenId, journey: opts.journey.name, stepsExercised: 0, findings };
|
|
134534
134540
|
}
|
|
134535
134541
|
const { call: wixCall } = layeredTransport({ rules: opts.rules, cmsSeed: opts.cmsSeed, canned: opts.canned });
|
|
@@ -134554,23 +134560,23 @@ async function crawlScreenJourney(opts) {
|
|
|
134554
134560
|
for (const step of opts.journey.steps) {
|
|
134555
134561
|
const declared = sites.find((site2) => site2.actionId === step.action && (step.component === void 0 || site2.componentId === step.component));
|
|
134556
134562
|
if (!declared) {
|
|
134557
|
-
|
|
134563
|
+
fail5(`journey "${opts.journey.name}" cannot find ${step.component ? `${step.component} \u2192 ` : ""}${step.action} in this screen`, step);
|
|
134558
134564
|
continue;
|
|
134559
134565
|
}
|
|
134560
134566
|
const state = snapshot(worker).state;
|
|
134561
134567
|
const site = effectiveSiteFor(declared, state);
|
|
134562
134568
|
if (!site) {
|
|
134563
|
-
|
|
134569
|
+
fail5(`journey "${opts.journey.name}" cannot dispatch ${step.action}: its list has no rendered row`, step);
|
|
134564
134570
|
continue;
|
|
134565
134571
|
}
|
|
134566
134572
|
const parsed = parseWorkerAction(site.actionId);
|
|
134567
134573
|
if (!parsed) {
|
|
134568
|
-
|
|
134574
|
+
fail5(`journey "${opts.journey.name}" step ${step.action} is not a worker action; cross-screen navigation belongs in the regular edge pass`, step);
|
|
134569
134575
|
continue;
|
|
134570
134576
|
}
|
|
134571
134577
|
const handle = worker.handles[parsed.service];
|
|
134572
134578
|
if (!handle || !handle.actionNames().includes(parsed.action)) {
|
|
134573
|
-
|
|
134579
|
+
fail5(`journey "${opts.journey.name}" names unavailable worker action ${step.action}`, step);
|
|
134574
134580
|
continue;
|
|
134575
134581
|
}
|
|
134576
134582
|
const mark = { wix: worker.calls.length, host: worker.hostCalls.length };
|
|
@@ -134579,18 +134585,18 @@ async function crawlScreenJourney(opts) {
|
|
|
134579
134585
|
for (let i2 = 0; i2 < 8; i2++) await yieldMacrotask();
|
|
134580
134586
|
stepsExercised += 1;
|
|
134581
134587
|
} catch (error) {
|
|
134582
|
-
|
|
134588
|
+
fail5(`journey "${opts.journey.name}" step ${step.action} threw: ${errText(error)}`, step);
|
|
134583
134589
|
}
|
|
134584
134590
|
const stepEffect = effectSince(worker, mark, site.actionId, site.componentId);
|
|
134585
134591
|
if (stepEffect) effects.push(stepEffect);
|
|
134586
134592
|
}
|
|
134587
134593
|
const settled = snapshot(worker);
|
|
134588
134594
|
if (worker.errors.length) {
|
|
134589
|
-
for (const error of worker.errors)
|
|
134595
|
+
for (const error of worker.errors) fail5(`journey "${opts.journey.name}" worker error: ${error.service}: ${error.message}`);
|
|
134590
134596
|
}
|
|
134591
134597
|
const values = collectObservations(opts.descriptor, settled.state).join("\n");
|
|
134592
134598
|
for (const expected of opts.journey.expectText) {
|
|
134593
|
-
if (!values.includes(expected))
|
|
134599
|
+
if (!values.includes(expected)) fail5(`journey "${opts.journey.name}" never rendered its expected visible result: ${JSON.stringify(expected)}`);
|
|
134594
134600
|
}
|
|
134595
134601
|
return { screen: opts.screenId, journey: opts.journey.name, stepsExercised, findings, ...effects.length ? { effects } : {} };
|
|
134596
134602
|
});
|
|
@@ -136054,12 +136060,14 @@ __export(build_exports2, {
|
|
|
136054
136060
|
bakeCatalogs: () => bakeCatalogs,
|
|
136055
136061
|
bakeNeedsLiveOrigin: () => bakeNeedsLiveOrigin,
|
|
136056
136062
|
bakeWidgets: () => bakeWidgets,
|
|
136063
|
+
buildFromLoaded: () => buildFromLoaded,
|
|
136057
136064
|
buildRelease: () => buildRelease,
|
|
136058
136065
|
buildReleaseFromContent: () => buildReleaseFromContent,
|
|
136059
136066
|
bundleNameFromUrl: () => bundleNameFromUrl,
|
|
136060
136067
|
collectComponentTypes: () => collectComponentTypes,
|
|
136061
136068
|
contentReleaseId: () => contentReleaseId,
|
|
136062
136069
|
countingWixCall: () => countingWixCall,
|
|
136070
|
+
declaresHostProvidedIdentity: () => declaresHostProvidedIdentity,
|
|
136063
136071
|
gitSha: () => gitSha,
|
|
136064
136072
|
isMonorepoCheckout: () => isMonorepoCheckout,
|
|
136065
136073
|
l10nLintOptions: () => l10nLintOptions,
|
|
@@ -137218,6 +137226,11 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
|
|
|
137218
137226
|
nativeComponents: [...requiredNativeComponents].sort(),
|
|
137219
137227
|
authProviders: [config.auth.providerId].filter(Boolean).sort()
|
|
137220
137228
|
},
|
|
137229
|
+
// #4091 — the app takes its Wix identity from a HOST (Spaces Lite) instead of signing in
|
|
137230
|
+
// itself (#4088 `hostProvided` on its auth provider). A host that lends its identity only
|
|
137231
|
+
// opens an app that accepts it. Written only when true, so every other app's release — and
|
|
137232
|
+
// its releaseId — is byte-identical to one built before the field existed.
|
|
137233
|
+
...declaresHostProvidedIdentity(config.auth) ? { hostProvidedIdentity: true } : {},
|
|
137221
137234
|
iconHash,
|
|
137222
137235
|
...brandFonts.length ? { brandFonts } : {},
|
|
137223
137236
|
handlers,
|
|
@@ -137344,6 +137357,10 @@ function listBuildableApps() {
|
|
|
137344
137357
|
const appsDir = join47(REPO_ROOT7, "apps");
|
|
137345
137358
|
return readdirSync25(appsDir, { withFileTypes: true }).filter((d2) => d2.isDirectory() && !d2.name.startsWith("_")).map((d2) => d2.name);
|
|
137346
137359
|
}
|
|
137360
|
+
function declaresHostProvidedIdentity(auth) {
|
|
137361
|
+
const config = auth?.config;
|
|
137362
|
+
return typeof config === "object" && config !== null && config.hostProvided === true;
|
|
137363
|
+
}
|
|
137347
137364
|
var BAKE_OFFLINE_BASE, KNOWN_ICON_NAMES, KNOWN_ICONS, REPO_ROOT7, TIER5_DIR, requireFromHere, SOURCEMAP_ON_DEMAND_PATH, BAKED_SERVER_BASE_URL;
|
|
137348
137365
|
var init_build3 = __esm({
|
|
137349
137366
|
"../release-build/build.ts"() {
|
|
@@ -152375,30 +152392,30 @@ function logicalCollection(spec, app) {
|
|
|
152375
152392
|
}
|
|
152376
152393
|
function assertFieldValue(type, key2, value) {
|
|
152377
152394
|
if (value === null) return;
|
|
152378
|
-
const
|
|
152395
|
+
const fail5 = () => {
|
|
152379
152396
|
throw new Error(`field "${key2}" must be ${type}`);
|
|
152380
152397
|
};
|
|
152381
152398
|
if (type === "NUMBER") {
|
|
152382
|
-
if (typeof value !== "number" || !Number.isFinite(value))
|
|
152399
|
+
if (typeof value !== "number" || !Number.isFinite(value)) fail5();
|
|
152383
152400
|
return;
|
|
152384
152401
|
}
|
|
152385
152402
|
if (type === "BOOLEAN") {
|
|
152386
|
-
if (typeof value !== "boolean")
|
|
152403
|
+
if (typeof value !== "boolean") fail5();
|
|
152387
152404
|
return;
|
|
152388
152405
|
}
|
|
152389
152406
|
if (type === "ARRAY_STRING") {
|
|
152390
|
-
if (!Array.isArray(value) || value.some((item) => typeof item !== "string"))
|
|
152407
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) fail5();
|
|
152391
152408
|
return;
|
|
152392
152409
|
}
|
|
152393
152410
|
if (type === "ADDRESS" || type === "RICH_CONTENT") {
|
|
152394
|
-
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
152411
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) fail5();
|
|
152395
152412
|
return;
|
|
152396
152413
|
}
|
|
152397
152414
|
if (type === "MEDIA_GALLERY") {
|
|
152398
|
-
if (!Array.isArray(value))
|
|
152415
|
+
if (!Array.isArray(value)) fail5();
|
|
152399
152416
|
return;
|
|
152400
152417
|
}
|
|
152401
|
-
if (typeof value !== "string")
|
|
152418
|
+
if (typeof value !== "string") fail5();
|
|
152402
152419
|
}
|
|
152403
152420
|
function createFunctionDataCapability(options) {
|
|
152404
152421
|
const declaredKv = new Map((options.data?.kv ?? []).map((spec) => [spec.name, spec]));
|
|
@@ -155819,6 +155836,9 @@ ${releaseId}`;
|
|
|
155819
155836
|
...m2.publishedAt ? { publishedAt: m2.publishedAt } : {},
|
|
155820
155837
|
...publicationKind ? { publicationKind } : {},
|
|
155821
155838
|
...m2.playerRequirements ? { playerRequirements: m2.playerRequirements } : {},
|
|
155839
|
+
// #4091 — whether the app accepts its host's identity; Spaces opens an owner-picked
|
|
155840
|
+
// member app only when it does. Absent = it signs in itself (or predates the field).
|
|
155841
|
+
...m2.hostProvidedIdentity === true ? { hostProvidedIdentity: true } : {},
|
|
155822
155842
|
// RFC 0051 §3.6 — the release's surface envelope, for tooling that has no
|
|
155823
155843
|
// source tree (hosted admin surface picker, gallery). Absent on releases
|
|
155824
155844
|
// built before the envelope rode the manifest.
|
|
@@ -155939,11 +155959,11 @@ ${releaseId}`;
|
|
|
155939
155959
|
if (pin) {
|
|
155940
155960
|
const m3 = app ? await pinnedManifest(app, pin) : null;
|
|
155941
155961
|
if (!m3) return json4(404, { error: "release_not_found", app, releaseId: pin });
|
|
155942
|
-
return json4(200, { releaseId: m3.releaseId, app: m3.app, pinned: true, ...m3.minBinaryVersion ? { minBinaryVersion: m3.minBinaryVersion } : {}, ...m3.playerRequirements ? { playerRequirements: m3.playerRequirements } : {}, ...m3.platforms ? { platforms: m3.platforms } : {} });
|
|
155962
|
+
return json4(200, { releaseId: m3.releaseId, app: m3.app, pinned: true, ...m3.minBinaryVersion ? { minBinaryVersion: m3.minBinaryVersion } : {}, ...m3.playerRequirements ? { playerRequirements: m3.playerRequirements } : {}, ...m3.hostProvidedIdentity === true ? { hostProvidedIdentity: true } : {}, ...m3.platforms ? { platforms: m3.platforms } : {} });
|
|
155943
155963
|
}
|
|
155944
155964
|
const m2 = app ? await manifest(app) : null;
|
|
155945
155965
|
if (!m2) return json4(404, { error: "no_release", app });
|
|
155946
|
-
return json4(200, { releaseId: m2.releaseId, app: m2.app, ...m2.minBinaryVersion ? { minBinaryVersion: m2.minBinaryVersion } : {}, ...m2.playerRequirements ? { playerRequirements: m2.playerRequirements } : {}, ...m2.platforms ? { platforms: m2.platforms } : {} });
|
|
155966
|
+
return json4(200, { releaseId: m2.releaseId, app: m2.app, ...m2.minBinaryVersion ? { minBinaryVersion: m2.minBinaryVersion } : {}, ...m2.playerRequirements ? { playerRequirements: m2.playerRequirements } : {}, ...m2.hostProvidedIdentity === true ? { hostProvidedIdentity: true } : {}, ...m2.platforms ? { platforms: m2.platforms } : {} });
|
|
155947
155967
|
}
|
|
155948
155968
|
const bundleMatch = /^\/v1\/bundles\/([a-f0-9]{64})\.bundle\.js$/.exec(path2);
|
|
155949
155969
|
if (bundleMatch) {
|
|
@@ -160575,19 +160595,19 @@ async function runWixMobileRelease(pos, flags, io2, deps) {
|
|
|
160575
160595
|
const invokedAs = pos[0];
|
|
160576
160596
|
const app = invokedAs === "testflight" ? pos[1] : pos[2];
|
|
160577
160597
|
const print = (value) => io2.log(JSON.stringify(value, null, 2));
|
|
160578
|
-
const
|
|
160598
|
+
const fail5 = (error, extra = {}) => {
|
|
160579
160599
|
io2.error(JSON.stringify({ error, provider: "wix-mobile-release", ...extra }));
|
|
160580
160600
|
return 2;
|
|
160581
160601
|
};
|
|
160582
|
-
if (invokedAs !== "testflight" && !(invokedAs === "store" && pos[1] === "upload")) return
|
|
160583
|
-
if (app !== "himi-player") return
|
|
160584
|
-
if (str5(flags.artifact)) return
|
|
160585
|
-
if (on2(flags["no-wait"])) return
|
|
160602
|
+
if (invokedAs !== "testflight" && !(invokedAs === "store" && pos[1] === "upload")) return fail5("Wix Mobile Release only supports `himi testflight <app>` or `himi store upload <app>`");
|
|
160603
|
+
if (app !== "himi-player") return fail5("Wix Mobile Release is reserved for the Wix-owned Himi Player binary", { app });
|
|
160604
|
+
if (str5(flags.artifact)) return fail5("--artifact is not accepted for Himi Player; pass --release so deployed serve can validate the Job Service IPA and call MRE with its service identity");
|
|
160605
|
+
if (on2(flags["no-wait"])) return fail5("--no-wait is not supported for Himi Player TestFlight releases; wait for MRE processing to complete");
|
|
160586
160606
|
const release2 = str5(flags.release);
|
|
160587
160607
|
const version4 = str5(flags.version);
|
|
160588
|
-
if (!release2) return
|
|
160589
|
-
if (!version4 || !/^\d+(?:\.\d+){0,2}$/.test(version4)) return
|
|
160590
|
-
if (str5(flags.track) && str5(flags.track) !== "testflight" && str5(flags.track) !== "internal") return
|
|
160608
|
+
if (!release2) return fail5("--release is required for a Himi Player TestFlight release");
|
|
160609
|
+
if (!version4 || !/^\d+(?:\.\d+){0,2}$/.test(version4)) return fail5("--version needs the Player marketing version (for example 1.0.0)");
|
|
160610
|
+
if (str5(flags.track) && str5(flags.track) !== "testflight" && str5(flags.track) !== "internal") return fail5("Wix Mobile Release only supports TestFlight upload; public App Store release remains a separate human step");
|
|
160591
160611
|
const plan = {
|
|
160592
160612
|
ok: true,
|
|
160593
160613
|
dryRun: on2(flags["dry-run"]),
|
|
@@ -160602,9 +160622,9 @@ async function runWixMobileRelease(pos, flags, io2, deps) {
|
|
|
160602
160622
|
print(plan);
|
|
160603
160623
|
return 0;
|
|
160604
160624
|
}
|
|
160605
|
-
if (!deps.releasePlayerJob) return
|
|
160625
|
+
if (!deps.releasePlayerJob) return fail5("this Himi CLI cannot create a service-side Himi Player TestFlight job; target deployed serve");
|
|
160606
160626
|
if (!on2(flags.yes)) {
|
|
160607
|
-
if (io2.isTTY !== true) return
|
|
160627
|
+
if (io2.isTTY !== true) return fail5("refusing to dispatch a Wix TestFlight release without --yes in a non-interactive shell");
|
|
160608
160628
|
if (!await deps.confirm(` Dispatch Himi Player ${version4} to Wix TestFlight?`)) {
|
|
160609
160629
|
io2.log(" aborted \u2014 no release was dispatched.");
|
|
160610
160630
|
return 1;
|
|
@@ -160613,11 +160633,11 @@ async function runWixMobileRelease(pos, flags, io2, deps) {
|
|
|
160613
160633
|
try {
|
|
160614
160634
|
const released = await deps.releasePlayerJob(release2, version4);
|
|
160615
160635
|
const status = released.status.toUpperCase();
|
|
160616
|
-
if (mreStatusKind(status) !== "completed") return
|
|
160636
|
+
if (mreStatusKind(status) !== "completed") return fail5(`Himi Player TestFlight job ${status || "FAILED"}`, { jobId: released.jobId, ...released.requestId ? { requestId: released.requestId } : {}, ...released.error ? { error: released.error } : {} });
|
|
160617
160637
|
print({ ok: true, provider: "wix-mobile-release", app, jobId: released.jobId, ...released.requestId ? { requestId: released.requestId } : {}, status, ...released.url ? { url: released.url } : {} });
|
|
160618
160638
|
return 0;
|
|
160619
160639
|
} catch (error) {
|
|
160620
|
-
return
|
|
160640
|
+
return fail5(`could not complete the Himi Player TestFlight Job Service release: ${error.message}`);
|
|
160621
160641
|
}
|
|
160622
160642
|
}
|
|
160623
160643
|
var str5, on2;
|
|
@@ -160673,23 +160693,23 @@ async function runStore(pos, flags, io2, deps) {
|
|
|
160673
160693
|
const app = invokedAs === "testflight" ? pos[1] : pos[2];
|
|
160674
160694
|
const json6 = on3(flags.json);
|
|
160675
160695
|
const print = (o2) => io2.log(JSON.stringify(o2, null, 2));
|
|
160676
|
-
const
|
|
160696
|
+
const fail5 = (error, extra = {}) => {
|
|
160677
160697
|
io2.error(JSON.stringify({ error, ...extra }));
|
|
160678
160698
|
return 2;
|
|
160679
160699
|
};
|
|
160680
160700
|
if (!sub || !["preflight", "upload", "status"].includes(sub)) {
|
|
160681
|
-
return
|
|
160701
|
+
return fail5(`unknown store subcommand ${sub ? `"${sub}"` : ""}`.trim(), {
|
|
160682
160702
|
usage: "himi store preflight|upload|status <app> \xB7 himi testflight <app>"
|
|
160683
160703
|
});
|
|
160684
160704
|
}
|
|
160685
|
-
if (!app) return
|
|
160705
|
+
if (!app) return fail5(`store ${sub} needs an <app>`);
|
|
160686
160706
|
if (flags.provider !== void 0) {
|
|
160687
|
-
return
|
|
160707
|
+
return fail5(`unknown release provider "${String(flags.provider)}"`, {
|
|
160688
160708
|
known: ["wix-mobile-release"]
|
|
160689
160709
|
});
|
|
160690
160710
|
}
|
|
160691
160711
|
if (!deps.hasRepoCheckout()) {
|
|
160692
|
-
return
|
|
160712
|
+
return fail5(
|
|
160693
160713
|
"himi store needs a Himalaya monorepo checkout \u2014 it builds and signs apps/<app>'s native target, which does not exist off-repo. Content changes (screens, Tier-5 bundles, tokens, app-config) ship over the air with `himi push` and need no binary.",
|
|
160694
160714
|
{ app }
|
|
160695
160715
|
);
|
|
@@ -160698,14 +160718,14 @@ async function runStore(pos, flags, io2, deps) {
|
|
|
160698
160718
|
try {
|
|
160699
160719
|
cfg = deps.loadStoreConfig(app);
|
|
160700
160720
|
} catch (e2) {
|
|
160701
|
-
return
|
|
160721
|
+
return fail5(e2.message);
|
|
160702
160722
|
}
|
|
160703
160723
|
if (sub === "status") {
|
|
160704
160724
|
let creds2;
|
|
160705
160725
|
try {
|
|
160706
160726
|
creds2 = deps.resolveCredentials({ app, cfg, profileFlag: str6(flags.profile) });
|
|
160707
160727
|
} catch (e2) {
|
|
160708
|
-
return
|
|
160728
|
+
return fail5(e2.message);
|
|
160709
160729
|
}
|
|
160710
160730
|
try {
|
|
160711
160731
|
const s2 = await deps.ascStatus(app, credsToEnv(creds2));
|
|
@@ -160718,14 +160738,14 @@ async function runStore(pos, flags, io2, deps) {
|
|
|
160718
160738
|
}
|
|
160719
160739
|
return 0;
|
|
160720
160740
|
} catch (e2) {
|
|
160721
|
-
return
|
|
160741
|
+
return fail5(`could not read App Store Connect status: ${e2.message}`);
|
|
160722
160742
|
}
|
|
160723
160743
|
}
|
|
160724
160744
|
let findings;
|
|
160725
160745
|
try {
|
|
160726
160746
|
findings = await deps.preflightApp(app, { profileFlag: str6(flags.profile) });
|
|
160727
160747
|
} catch (e2) {
|
|
160728
|
-
return
|
|
160748
|
+
return fail5(e2.message);
|
|
160729
160749
|
}
|
|
160730
160750
|
const { errors, warnings } = partitionFindings(findings);
|
|
160731
160751
|
if (sub === "preflight") {
|
|
@@ -160742,12 +160762,12 @@ async function runStore(pos, flags, io2, deps) {
|
|
|
160742
160762
|
const configTrack = cfg.review?.defaultTrackIos;
|
|
160743
160763
|
const track = explicitTrack ?? (invokedAs === "testflight" ? "testflight" : configTrack ?? "testflight");
|
|
160744
160764
|
if (track === "appstore") {
|
|
160745
|
-
return
|
|
160765
|
+
return fail5(
|
|
160746
160766
|
"himi store does not submit for public App Store review \u2014 that stays a human step. Use TestFlight here, then /submit-ios-app when you mean to go public." + (explicitTrack ? "" : ` (inherited from review.defaultTrackIos; pass --track testflight to upload.)`)
|
|
160747
160767
|
);
|
|
160748
160768
|
}
|
|
160749
160769
|
if (!TRACKS.has(track)) {
|
|
160750
|
-
return
|
|
160770
|
+
return fail5(`unknown --track "${track}"`, { known: [...TRACKS] });
|
|
160751
160771
|
}
|
|
160752
160772
|
const bundleId = cfg.ios?.bundleId ?? "(unset)";
|
|
160753
160773
|
let creds;
|
|
@@ -160756,10 +160776,10 @@ async function runStore(pos, flags, io2, deps) {
|
|
|
160756
160776
|
creds = deps.resolveCredentials({ app, cfg, profileFlag: str6(flags.profile) });
|
|
160757
160777
|
version4 = deps.readVersion(app);
|
|
160758
160778
|
} catch (e2) {
|
|
160759
|
-
return
|
|
160779
|
+
return fail5(e2.message);
|
|
160760
160780
|
}
|
|
160761
160781
|
if (!Number.isInteger(version4.build)) {
|
|
160762
|
-
return
|
|
160782
|
+
return fail5(
|
|
160763
160783
|
`${app} has a non-integer CFBundleVersion (${JSON.stringify(version4.build)}) \u2014 this command bumps and matches build numbers arithmetically. Use an integer CFBundleVersion.`,
|
|
160764
160784
|
{ app, marketing: version4.marketing }
|
|
160765
160785
|
);
|
|
@@ -160774,7 +160794,7 @@ async function runStore(pos, flags, io2, deps) {
|
|
|
160774
160794
|
for (const f2 of findings) io2.log(` ${f2.level === "error" ? "\u2717" : "!"} ${f2.message}`);
|
|
160775
160795
|
}
|
|
160776
160796
|
if (errors.length) {
|
|
160777
|
-
return
|
|
160797
|
+
return fail5(`${app} is not ready to upload \u2014 ${errors.length} blocking preflight issue(s).`, {
|
|
160778
160798
|
findings: errors,
|
|
160779
160799
|
hint: "himi store preflight " + app
|
|
160780
160800
|
});
|
|
@@ -160805,7 +160825,7 @@ async function runStore(pos, flags, io2, deps) {
|
|
|
160805
160825
|
}
|
|
160806
160826
|
if (!on3(flags.yes)) {
|
|
160807
160827
|
if (io2.isTTY !== true) {
|
|
160808
|
-
return
|
|
160828
|
+
return fail5(
|
|
160809
160829
|
"refusing to upload without confirmation in a non-interactive shell. Pass --yes if you really mean to publish this build, or --dry-run to see the plan.",
|
|
160810
160830
|
{ app, track, team: creds.team }
|
|
160811
160831
|
);
|
|
@@ -160820,7 +160840,7 @@ async function runStore(pos, flags, io2, deps) {
|
|
|
160820
160840
|
try {
|
|
160821
160841
|
uploaded = reuseExisting ? version4 : deps.bumpBuild(app);
|
|
160822
160842
|
} catch (e2) {
|
|
160823
|
-
return
|
|
160843
|
+
return fail5(`could not bump the build number: ${e2.message}`);
|
|
160824
160844
|
}
|
|
160825
160845
|
const rollback = () => {
|
|
160826
160846
|
if (reuseExisting) return;
|
|
@@ -160836,11 +160856,11 @@ async function runStore(pos, flags, io2, deps) {
|
|
|
160836
160856
|
r2 = await deps.exec(step, env);
|
|
160837
160857
|
} catch (e2) {
|
|
160838
160858
|
rollback();
|
|
160839
|
-
return
|
|
160859
|
+
return fail5(`${step} failed: ${e2.message}`, { app, step, build: uploaded.build, buildNumberRestored: !reuseExisting });
|
|
160840
160860
|
}
|
|
160841
160861
|
if (r2.code !== 0) {
|
|
160842
160862
|
if (step !== "upload") rollback();
|
|
160843
|
-
return
|
|
160863
|
+
return fail5(`${step} failed (exit ${r2.code})`, {
|
|
160844
160864
|
app,
|
|
160845
160865
|
step,
|
|
160846
160866
|
build: uploaded.build,
|
|
@@ -160864,7 +160884,7 @@ async function runStore(pos, flags, io2, deps) {
|
|
|
160864
160884
|
try {
|
|
160865
160885
|
s2 = await deps.ascStatus(app, env);
|
|
160866
160886
|
} catch (e2) {
|
|
160867
|
-
return
|
|
160887
|
+
return fail5(`uploaded build ${uploaded.build}, but could not read processing status: ${e2.message}`, {
|
|
160868
160888
|
app,
|
|
160869
160889
|
build: uploaded.build,
|
|
160870
160890
|
uploaded: true
|
|
@@ -160880,7 +160900,7 @@ async function runStore(pos, flags, io2, deps) {
|
|
|
160880
160900
|
return 0;
|
|
160881
160901
|
}
|
|
160882
160902
|
if (mine && (mine.processingState === "FAILED" || mine.processingState === "INVALID")) {
|
|
160883
|
-
return
|
|
160903
|
+
return fail5(`build ${uploaded.build} is ${mine.processingState} in App Store Connect`, {
|
|
160884
160904
|
app,
|
|
160885
160905
|
build: uploaded.build,
|
|
160886
160906
|
processingState: mine.processingState,
|
|
@@ -160888,7 +160908,7 @@ async function runStore(pos, flags, io2, deps) {
|
|
|
160888
160908
|
});
|
|
160889
160909
|
}
|
|
160890
160910
|
if (waited >= deadline) {
|
|
160891
|
-
return
|
|
160911
|
+
return fail5(
|
|
160892
160912
|
`build ${uploaded.build} never appeared in App Store Connect after ${Math.round(deadline / 6e4)} minutes. A binary rejected during processing leaves no record and the reason is emailed, not exposed by the API \u2014 check the Apple ID inbox for team ${creds.team}.`,
|
|
160893
160913
|
{ app, build: uploaded.build, uploaded: true, processed: false }
|
|
160894
160914
|
);
|
|
@@ -165460,7 +165480,7 @@ async function ownerPass(appId2, ports, sample) {
|
|
|
165460
165480
|
const gaps = [];
|
|
165461
165481
|
const r2 = { identity: {}, entities: [], functions: [], agents: [], connectors: [], secrets: [], routes: [], sourceFiles: [], gaps };
|
|
165462
165482
|
const client2 = api(ports, appId2);
|
|
165463
|
-
const
|
|
165483
|
+
const fail5 = (chapter, e2) => {
|
|
165464
165484
|
gaps.push({ chapter, reason: e2.message });
|
|
165465
165485
|
};
|
|
165466
165486
|
try {
|
|
@@ -165476,7 +165496,7 @@ async function ownerPass(appId2, ports, sample) {
|
|
|
165476
165496
|
source: "rest"
|
|
165477
165497
|
};
|
|
165478
165498
|
} catch (e2) {
|
|
165479
|
-
|
|
165499
|
+
fail5("auth", e2);
|
|
165480
165500
|
}
|
|
165481
165501
|
let files = /* @__PURE__ */ new Map();
|
|
165482
165502
|
if (!ports.downloadSource) {
|
|
@@ -165493,7 +165513,7 @@ async function ownerPass(appId2, ports, sample) {
|
|
|
165493
165513
|
files = new Map(kept.map((e2) => [e2.path, e2.bytes.toString("utf8")]));
|
|
165494
165514
|
r2.source = { root: "source", files: kept.length, denied: skipped.map((p2) => p2.split("\\").join("/")), secretFlagged: flagged };
|
|
165495
165515
|
} catch (e2) {
|
|
165496
|
-
|
|
165516
|
+
fail5("source", e2);
|
|
165497
165517
|
} finally {
|
|
165498
165518
|
dl2?.cleanup();
|
|
165499
165519
|
}
|
|
@@ -165527,13 +165547,13 @@ async function ownerPass(appId2, ports, sample) {
|
|
|
165527
165547
|
if (typeof f2.name !== "string" || r2.functions.some((x2) => x2.name === f2.name)) continue;
|
|
165528
165548
|
r2.functions.push({ name: f2.name, kind: "unknown", invoke: `base44.functions.invoke(${JSON.stringify(f2.name)}, payload)`, ...typeof f2.entry === "string" ? { sourcePath: f2.entry } : {}, source: "rest" });
|
|
165529
165549
|
}
|
|
165530
|
-
} else if (!r2.functions.length)
|
|
165550
|
+
} else if (!r2.functions.length) fail5("functions", fnList.reason);
|
|
165531
165551
|
if (agentList.status === "fulfilled") {
|
|
165532
165552
|
for (const cfg of agentList.value.items ?? []) {
|
|
165533
165553
|
const a2 = agentFromConfig(cfg, "rest");
|
|
165534
165554
|
if (a2 && !r2.agents.some((x2) => x2.name === a2.name)) r2.agents.push(a2);
|
|
165535
165555
|
}
|
|
165536
|
-
} else if (!r2.agents.length)
|
|
165556
|
+
} else if (!r2.agents.length) fail5("agents", agentList.reason);
|
|
165537
165557
|
if (connList.status === "fulfilled") {
|
|
165538
165558
|
for (const c2 of connList.value.integrations ?? []) {
|
|
165539
165559
|
const type = typeof c2.integration_type === "string" ? c2.integration_type : void 0;
|
|
@@ -165546,9 +165566,9 @@ async function ownerPass(appId2, ports, sample) {
|
|
|
165546
165566
|
if (!existing.scopes.length) existing.scopes = scopes;
|
|
165547
165567
|
} else r2.connectors.push({ type, scopes, ...status ? { status } : {}, source: "rest" });
|
|
165548
165568
|
}
|
|
165549
|
-
} else if (!r2.connectors.length)
|
|
165569
|
+
} else if (!r2.connectors.length) fail5("connectors", connList.reason);
|
|
165550
165570
|
if (secretMap.status === "fulfilled") r2.secrets = Object.keys(secretMap.value ?? {}).sort();
|
|
165551
|
-
else
|
|
165571
|
+
else fail5("secrets", secretMap.reason);
|
|
165552
165572
|
if (sample > 0 && samples.status === "fulfilled") {
|
|
165553
165573
|
const refused2 = [];
|
|
165554
165574
|
samples.value.forEach((settled, i2) => {
|
|
@@ -169707,6 +169727,436 @@ var init_cli = __esm({
|
|
|
169707
169727
|
}
|
|
169708
169728
|
});
|
|
169709
169729
|
|
|
169730
|
+
// ../../apps/himi-spaces-lite/spaces-host-manifest.ts
|
|
169731
|
+
var SPACES_HOST_MANIFEST;
|
|
169732
|
+
var init_spaces_host_manifest = __esm({
|
|
169733
|
+
"../../apps/himi-spaces-lite/spaces-host-manifest.ts"() {
|
|
169734
|
+
SPACES_HOST_MANIFEST = {
|
|
169735
|
+
"version": "1.3.0",
|
|
169736
|
+
"capabilities": [
|
|
169737
|
+
"animation",
|
|
169738
|
+
"app_info",
|
|
169739
|
+
"base44",
|
|
169740
|
+
"browser_auth",
|
|
169741
|
+
"calendar",
|
|
169742
|
+
"clipboard",
|
|
169743
|
+
"file_picker",
|
|
169744
|
+
"files",
|
|
169745
|
+
"godot",
|
|
169746
|
+
"haptics",
|
|
169747
|
+
"himi_apps",
|
|
169748
|
+
"iap",
|
|
169749
|
+
"keyboard",
|
|
169750
|
+
"live_activity",
|
|
169751
|
+
"local_database",
|
|
169752
|
+
"media_playback",
|
|
169753
|
+
"motion",
|
|
169754
|
+
"on_device_ai",
|
|
169755
|
+
"open_url",
|
|
169756
|
+
"pdf",
|
|
169757
|
+
"presigned_upload",
|
|
169758
|
+
"push",
|
|
169759
|
+
"release_control",
|
|
169760
|
+
"secure_storage",
|
|
169761
|
+
"share",
|
|
169762
|
+
"speaker_diarization",
|
|
169763
|
+
"stream",
|
|
169764
|
+
"theme",
|
|
169765
|
+
"ui",
|
|
169766
|
+
"wix_api",
|
|
169767
|
+
"wix_cashier",
|
|
169768
|
+
"wix_platform"
|
|
169769
|
+
],
|
|
169770
|
+
"unlinked": {
|
|
169771
|
+
"ios": [
|
|
169772
|
+
"animation",
|
|
169773
|
+
"base44",
|
|
169774
|
+
"browser_auth",
|
|
169775
|
+
"file_picker",
|
|
169776
|
+
"files",
|
|
169777
|
+
"godot",
|
|
169778
|
+
"himi_apps",
|
|
169779
|
+
"keyboard",
|
|
169780
|
+
"on_device_ai",
|
|
169781
|
+
"pdf",
|
|
169782
|
+
"presigned_upload",
|
|
169783
|
+
"speaker_diarization",
|
|
169784
|
+
"ui",
|
|
169785
|
+
"wix-native",
|
|
169786
|
+
"wix_cashier"
|
|
169787
|
+
],
|
|
169788
|
+
"macos": [
|
|
169789
|
+
"animation",
|
|
169790
|
+
"base44",
|
|
169791
|
+
"browser_auth",
|
|
169792
|
+
"calendar",
|
|
169793
|
+
"file_picker",
|
|
169794
|
+
"files",
|
|
169795
|
+
"godot",
|
|
169796
|
+
"himi_apps",
|
|
169797
|
+
"iap",
|
|
169798
|
+
"keyboard",
|
|
169799
|
+
"live_activity",
|
|
169800
|
+
"motion",
|
|
169801
|
+
"on_device_ai",
|
|
169802
|
+
"pdf",
|
|
169803
|
+
"presigned_upload",
|
|
169804
|
+
"push",
|
|
169805
|
+
"speaker_diarization",
|
|
169806
|
+
"ui",
|
|
169807
|
+
"wix-native",
|
|
169808
|
+
"wix_cashier"
|
|
169809
|
+
],
|
|
169810
|
+
"android": [
|
|
169811
|
+
"animation",
|
|
169812
|
+
"base44",
|
|
169813
|
+
"browser_auth",
|
|
169814
|
+
"file_picker",
|
|
169815
|
+
"files",
|
|
169816
|
+
"godot",
|
|
169817
|
+
"himi_apps",
|
|
169818
|
+
"keyboard",
|
|
169819
|
+
"on_device_ai",
|
|
169820
|
+
"pdf",
|
|
169821
|
+
"presigned_upload",
|
|
169822
|
+
"speaker_diarization",
|
|
169823
|
+
"ui",
|
|
169824
|
+
"wix-native",
|
|
169825
|
+
"wix_cashier"
|
|
169826
|
+
],
|
|
169827
|
+
"web": []
|
|
169828
|
+
},
|
|
169829
|
+
"nativeComponents": [
|
|
169830
|
+
"himi_spaces_lite.HimiSpacesLiteCard"
|
|
169831
|
+
],
|
|
169832
|
+
"authProviders": [
|
|
169833
|
+
"wix-consumer",
|
|
169834
|
+
"wix-native"
|
|
169835
|
+
],
|
|
169836
|
+
"nativeActions": [
|
|
169837
|
+
"himi_spaces_lite.greet"
|
|
169838
|
+
]
|
|
169839
|
+
};
|
|
169840
|
+
}
|
|
169841
|
+
});
|
|
169842
|
+
|
|
169843
|
+
// ../../core/ts/src/host-compatibility.ts
|
|
169844
|
+
function compareVersion(a2, b2) {
|
|
169845
|
+
const parts = (v2) => v2.split("-")[0].split(".").map((p2) => /^\d+$/.test(p2) ? Number(p2) : 0);
|
|
169846
|
+
const av = parts(a2);
|
|
169847
|
+
const bv = parts(b2);
|
|
169848
|
+
for (let i2 = 0; i2 < Math.max(av.length, bv.length); i2 += 1) {
|
|
169849
|
+
if ((av[i2] ?? 0) !== (bv[i2] ?? 0)) return (av[i2] ?? 0) - (bv[i2] ?? 0);
|
|
169850
|
+
}
|
|
169851
|
+
return 0;
|
|
169852
|
+
}
|
|
169853
|
+
function claimsFor(host, shell) {
|
|
169854
|
+
const gaps = shell && host.unlinked[shell] ? host.unlinked[shell] : [...host.unlinked.ios ?? [], ...host.unlinked.android ?? []];
|
|
169855
|
+
const served = (ids) => ids.filter((id) => !gaps.includes(id));
|
|
169856
|
+
return { capabilities: served(host.capabilities), nativeComponents: served(host.nativeComponents), authProviders: served(host.authProviders) };
|
|
169857
|
+
}
|
|
169858
|
+
function missingClaims(requirements, offered) {
|
|
169859
|
+
const out2 = {};
|
|
169860
|
+
for (const kind of HOST_CLAIM_KINDS) {
|
|
169861
|
+
const has = new Set(offered[kind]);
|
|
169862
|
+
out2[kind] = [...new Set(requirements[kind].filter((id) => !has.has(id)))];
|
|
169863
|
+
}
|
|
169864
|
+
return out2;
|
|
169865
|
+
}
|
|
169866
|
+
function missingReasons(missing, hostName = "the host") {
|
|
169867
|
+
const reasons = [];
|
|
169868
|
+
if (missing.capabilities.length) reasons.push(`Missing capabilities: ${missing.capabilities.join(", ")}`);
|
|
169869
|
+
if (missing.nativeComponents.length) reasons.push(`Native components not compiled into ${hostName}: ${missing.nativeComponents.join(", ")}`);
|
|
169870
|
+
if (missing.authProviders.length) reasons.push(`Unsupported auth providers: ${missing.authProviders.join(", ")}`);
|
|
169871
|
+
return reasons;
|
|
169872
|
+
}
|
|
169873
|
+
function checkHostCompatibility(requirements, host, options = {}) {
|
|
169874
|
+
const hostName = options.hostName ?? "the host";
|
|
169875
|
+
const reasons = missingReasons(missingClaims(requirements, claimsFor(host, options.shell)), hostName);
|
|
169876
|
+
const running = options.installedVersion || host.version;
|
|
169877
|
+
if (requirements.minBinaryVersion && compareVersion(running, requirements.minBinaryVersion) < 0) {
|
|
169878
|
+
reasons.push(`Requires ${hostName} ${requirements.minBinaryVersion} or newer (installed ${running})`);
|
|
169879
|
+
}
|
|
169880
|
+
if (options.requiresHostIdentity && !requirements.hostProvidedIdentity) {
|
|
169881
|
+
reasons.push(`Does not accept ${hostName}'s sign-in: the app must take its identity from the host (hostProvided)`);
|
|
169882
|
+
}
|
|
169883
|
+
return reasons.length ? { ok: false, reason: reasons.join("; "), reasons } : { ok: true };
|
|
169884
|
+
}
|
|
169885
|
+
var HOST_CLAIM_KINDS;
|
|
169886
|
+
var init_host_compatibility = __esm({
|
|
169887
|
+
"../../core/ts/src/host-compatibility.ts"() {
|
|
169888
|
+
init_registry_app_normalize();
|
|
169889
|
+
HOST_CLAIM_KINDS = PLAYER_REQUIREMENT_KINDS;
|
|
169890
|
+
}
|
|
169891
|
+
});
|
|
169892
|
+
|
|
169893
|
+
// ../../core/dev-server/tier5-bundles-src/_shared/branded-lite-hosted.ts
|
|
169894
|
+
var VERTICAL_ROOT_SCREENS, VERTICALS;
|
|
169895
|
+
var init_branded_lite_hosted = __esm({
|
|
169896
|
+
"../../core/dev-server/tier5-bundles-src/_shared/branded-lite-hosted.ts"() {
|
|
169897
|
+
VERTICAL_ROOT_SCREENS = {
|
|
169898
|
+
store: ["himi_shop"],
|
|
169899
|
+
bookings: ["himi_services"],
|
|
169900
|
+
restaurants: ["himi_menu", "himi_reserve"],
|
|
169901
|
+
programs: ["himi_programs"],
|
|
169902
|
+
plans: ["himi_plans"],
|
|
169903
|
+
feed: ["himi_feed"],
|
|
169904
|
+
members: ["himi_members"],
|
|
169905
|
+
forum: ["himi_forum"],
|
|
169906
|
+
coupons: ["himi_coupons"],
|
|
169907
|
+
notifications: ["himi_notifications"],
|
|
169908
|
+
loyalty: ["himi_loyalty"],
|
|
169909
|
+
reviews: ["himi_reviews"],
|
|
169910
|
+
portfolio: ["himi_portfolio"],
|
|
169911
|
+
reservations: ["himi_reservations"],
|
|
169912
|
+
invoices: ["himi_invoices"],
|
|
169913
|
+
badges: ["himi_badges"],
|
|
169914
|
+
notifsettings: ["himi_notif_settings"],
|
|
169915
|
+
events: ["himi_events"],
|
|
169916
|
+
blog: ["himi_blog"],
|
|
169917
|
+
groups: ["himi_groups"],
|
|
169918
|
+
cms: ["himi_cms"],
|
|
169919
|
+
donations: ["himi_donations"],
|
|
169920
|
+
giftCards: ["himi_gift_cards"],
|
|
169921
|
+
videos: ["himi_videos"],
|
|
169922
|
+
podcasts: ["himi_podcasts"],
|
|
169923
|
+
forms: ["himi_forms"],
|
|
169924
|
+
galleries: ["himi_galleries"],
|
|
169925
|
+
inbox: ["himi_inbox"],
|
|
169926
|
+
faq: ["himi_faq"]
|
|
169927
|
+
};
|
|
169928
|
+
VERTICALS = new Set(Object.keys(VERTICAL_ROOT_SCREENS));
|
|
169929
|
+
}
|
|
169930
|
+
});
|
|
169931
|
+
|
|
169932
|
+
// ../../apps/himi-branded-lite/hosted-mode.ts
|
|
169933
|
+
var init_hosted_mode = __esm({
|
|
169934
|
+
"../../apps/himi-branded-lite/hosted-mode.ts"() {
|
|
169935
|
+
init_branded_lite_hosted();
|
|
169936
|
+
}
|
|
169937
|
+
});
|
|
169938
|
+
|
|
169939
|
+
// ../../apps/himi-branded-lite/site-provisioning.ts
|
|
169940
|
+
var init_site_provisioning = __esm({
|
|
169941
|
+
"../../apps/himi-branded-lite/site-provisioning.ts"() {
|
|
169942
|
+
}
|
|
169943
|
+
});
|
|
169944
|
+
|
|
169945
|
+
// ../../apps/himi-spaces-lite/site-open.ts
|
|
169946
|
+
var HOSTED_MEMBER_APP;
|
|
169947
|
+
var init_site_open = __esm({
|
|
169948
|
+
"../../apps/himi-spaces-lite/site-open.ts"() {
|
|
169949
|
+
init_hosted_mode();
|
|
169950
|
+
init_site_provisioning();
|
|
169951
|
+
HOSTED_MEMBER_APP = "himi-branded-lite";
|
|
169952
|
+
}
|
|
169953
|
+
});
|
|
169954
|
+
|
|
169955
|
+
// ../../apps/himi-spaces-lite/site-app.ts
|
|
169956
|
+
function siteAppPickFrom(value) {
|
|
169957
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
169958
|
+
const appId2 = value.appId;
|
|
169959
|
+
if (appId2 === null) return null;
|
|
169960
|
+
if (typeof appId2 !== "string") return void 0;
|
|
169961
|
+
const id = appId2.trim();
|
|
169962
|
+
return APP_ID3.test(id) ? id : void 0;
|
|
169963
|
+
}
|
|
169964
|
+
function siteAppRequirementsFrom(appId2, entry) {
|
|
169965
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) return { ok: false, reason: `No release of ${appId2} to judge` };
|
|
169966
|
+
const e2 = entry;
|
|
169967
|
+
const names = e2.id !== void 0 ? e2.id : e2.app;
|
|
169968
|
+
if (names !== appId2) return { ok: false, reason: `No release of ${appId2} to judge` };
|
|
169969
|
+
if (!isPlayerRequirements(e2.playerRequirements)) {
|
|
169970
|
+
return { ok: false, reason: e2.playerRequirements === void 0 ? `${appId2}'s release does not declare what it requires (republish it)` : `${appId2}'s release declares malformed requirements` };
|
|
169971
|
+
}
|
|
169972
|
+
const minBinaryVersion = typeof e2.minBinaryVersion === "string" && e2.minBinaryVersion ? e2.minBinaryVersion : void 0;
|
|
169973
|
+
return {
|
|
169974
|
+
ok: true,
|
|
169975
|
+
requirements: {
|
|
169976
|
+
capabilities: [...e2.playerRequirements.capabilities],
|
|
169977
|
+
nativeComponents: [...e2.playerRequirements.nativeComponents],
|
|
169978
|
+
authProviders: [...e2.playerRequirements.authProviders],
|
|
169979
|
+
...minBinaryVersion ? { minBinaryVersion } : {},
|
|
169980
|
+
// Only an explicit `true` counts: an app that signs in by itself would ask a member to sign
|
|
169981
|
+
// in again inside Spaces, with an identity Spaces does not lend (#4088).
|
|
169982
|
+
...e2.hostProvidedIdentity === true ? { hostProvidedIdentity: true } : {}
|
|
169983
|
+
}
|
|
169984
|
+
};
|
|
169985
|
+
}
|
|
169986
|
+
function messageOf2(err) {
|
|
169987
|
+
const message = err?.message;
|
|
169988
|
+
return typeof message === "string" && message ? message : String(err);
|
|
169989
|
+
}
|
|
169990
|
+
function decideSiteApp(input) {
|
|
169991
|
+
const fallback = (pickedAppId, reason) => ({ appId: DEFAULT_SITE_APP, source: "fallback", pickedAppId, reason });
|
|
169992
|
+
if (input.pick === void 0) return { appId: DEFAULT_SITE_APP, source: "default" };
|
|
169993
|
+
if (!input.pick.ok) return fallback(null, `Could not read the site's member app: ${messageOf2(input.pick.error)}`);
|
|
169994
|
+
const picked = siteAppPickFrom(input.pick.value);
|
|
169995
|
+
if (picked === void 0) return fallback(null, "The site's member app setting is unreadable");
|
|
169996
|
+
if (picked === null || picked === DEFAULT_SITE_APP) return { appId: DEFAULT_SITE_APP, source: "default" };
|
|
169997
|
+
if (input.release === void 0) return fallback(picked, `No release of ${picked} to judge`);
|
|
169998
|
+
if (!input.release.ok) return fallback(picked, `Could not read ${picked}'s release: ${messageOf2(input.release.error)}`);
|
|
169999
|
+
const req = siteAppRequirementsFrom(picked, input.release.value);
|
|
170000
|
+
if (!req.ok) return fallback(picked, req.reason);
|
|
170001
|
+
const verdict = checkHostCompatibility(req.requirements, input.host, {
|
|
170002
|
+
hostName: "Spaces",
|
|
170003
|
+
requiresHostIdentity: true,
|
|
170004
|
+
...input.shell ? { shell: input.shell } : {},
|
|
170005
|
+
...input.installedVersion ? { installedVersion: input.installedVersion } : {}
|
|
170006
|
+
});
|
|
170007
|
+
if (!verdict.ok) return fallback(picked, verdict.reason);
|
|
170008
|
+
if (!(input.hostable ?? NATIVELY_HOSTABLE_APPS).includes(picked)) {
|
|
170009
|
+
return fallback(picked, `This Spaces build cannot host a custom member app yet (${picked} is compatible)`);
|
|
170010
|
+
}
|
|
170011
|
+
return { appId: picked, source: "picked" };
|
|
170012
|
+
}
|
|
170013
|
+
var DEFAULT_SITE_APP, NATIVELY_HOSTABLE_APPS, APP_ID3;
|
|
170014
|
+
var init_site_app = __esm({
|
|
170015
|
+
"../../apps/himi-spaces-lite/site-app.ts"() {
|
|
170016
|
+
init_host_compatibility();
|
|
170017
|
+
init_registry_app_normalize();
|
|
170018
|
+
init_site_open();
|
|
170019
|
+
DEFAULT_SITE_APP = HOSTED_MEMBER_APP;
|
|
170020
|
+
NATIVELY_HOSTABLE_APPS = [DEFAULT_SITE_APP];
|
|
170021
|
+
APP_ID3 = /^[a-z0-9][a-z0-9._-]{0,127}$/i;
|
|
170022
|
+
}
|
|
170023
|
+
});
|
|
170024
|
+
|
|
170025
|
+
// src/site-member-app.ts
|
|
170026
|
+
var site_member_app_exports = {};
|
|
170027
|
+
__export(site_member_app_exports, {
|
|
170028
|
+
SITE_MEMBER_APP_CODES: () => SITE_MEMBER_APP_CODES,
|
|
170029
|
+
SITE_MEMBER_APP_USAGE: () => SITE_MEMBER_APP_USAGE,
|
|
170030
|
+
SPACES_DEFAULT_APP: () => SPACES_DEFAULT_APP,
|
|
170031
|
+
memberAppVerdict: () => memberAppVerdict,
|
|
170032
|
+
runSiteMemberApp: () => runSiteMemberApp
|
|
170033
|
+
});
|
|
170034
|
+
function codeFor(status, serverError) {
|
|
170035
|
+
if (serverError === "forbidden_site" || serverError === "forbidden_app" || serverError === "app_bound_to_other_site") return serverError;
|
|
170036
|
+
if (status === 401) return "unauthorized";
|
|
170037
|
+
return "request_failed";
|
|
170038
|
+
}
|
|
170039
|
+
function memberAppVerdict(appId2, release2, shell) {
|
|
170040
|
+
if (!appId2 || appId2 === SPACES_DEFAULT_APP) return { opens: SPACES_DEFAULT_APP, compatible: null };
|
|
170041
|
+
const input = {
|
|
170042
|
+
pick: { ok: true, value: { appId: appId2 } },
|
|
170043
|
+
...release2 !== void 0 ? { release: { ok: true, value: release2 } } : {},
|
|
170044
|
+
host: SPACES_HOST_MANIFEST,
|
|
170045
|
+
...shell ? { shell } : {}
|
|
170046
|
+
};
|
|
170047
|
+
const fits = decideSiteApp({ ...input, hostable: [SPACES_DEFAULT_APP, appId2] });
|
|
170048
|
+
const opens = decideSiteApp(input);
|
|
170049
|
+
return {
|
|
170050
|
+
opens: opens.appId,
|
|
170051
|
+
compatible: fits.source === "picked",
|
|
170052
|
+
...opens.source === "fallback" ? { reason: opens.reason } : {}
|
|
170053
|
+
};
|
|
170054
|
+
}
|
|
170055
|
+
async function runSiteMemberApp(input, deps = {}) {
|
|
170056
|
+
const op = input.op;
|
|
170057
|
+
if (op !== "set" && op !== "clear" && op !== "show") {
|
|
170058
|
+
return fail4("invalid_usage", op ? `unknown site member-app op "${op}"` : "site member-app needs an op: set | clear | show", { usage: SITE_MEMBER_APP_USAGE });
|
|
170059
|
+
}
|
|
170060
|
+
const site = input.site;
|
|
170061
|
+
if (!site || !SITE_RE2.test(site)) return fail4("invalid_usage", "a metaSiteId (UUID) is required", { usage: SITE_MEMBER_APP_USAGE });
|
|
170062
|
+
if (op === "set" && !input.app) return fail4("invalid_usage", "set needs --app <id>", { usage: SITE_MEMBER_APP_USAGE });
|
|
170063
|
+
if (op === "set" && !isValidAppId(input.app)) return fail4("invalid_usage", `--app "${input.app}" is not a valid app id`, { usage: SITE_MEMBER_APP_USAGE });
|
|
170064
|
+
if (input.shell !== void 0 && input.shell !== "ios" && input.shell !== "android") {
|
|
170065
|
+
return fail4("invalid_usage", `--platform must be ios or android (got "${input.shell}")`, { usage: SITE_MEMBER_APP_USAGE });
|
|
170066
|
+
}
|
|
170067
|
+
let target;
|
|
170068
|
+
try {
|
|
170069
|
+
target = (deps.resolve ?? resolveTarget)({ target: input.target, defaultTarget: input.defaultTarget, controlUrl: input.controlUrl, controlToken: input.controlToken });
|
|
170070
|
+
} catch (err) {
|
|
170071
|
+
return fail4("invalid_usage", err.message);
|
|
170072
|
+
}
|
|
170073
|
+
const insecure = credentialHostRefusal(target.control);
|
|
170074
|
+
if (insecure) return fail4("insecure_target", insecure);
|
|
170075
|
+
if (!target.controlToken) return fail4("control_token_required", "no control token \u2014 run `himi login` (or pass --control-token)");
|
|
170076
|
+
let wixToken;
|
|
170077
|
+
try {
|
|
170078
|
+
wixToken = await (deps.wixToken ?? accountToken)();
|
|
170079
|
+
} catch {
|
|
170080
|
+
return fail4("wix_token_unavailable", "could not mint the account's Wix token (`wix token`) \u2014 the publishing service needs it to verify you own the site");
|
|
170081
|
+
}
|
|
170082
|
+
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
170083
|
+
const control = target.control.replace(/\/+$/, "");
|
|
170084
|
+
const url = `${control}/v1/admin/site/member-app${op === "set" ? "" : `?site=${encodeURIComponent(site)}`}`;
|
|
170085
|
+
let status;
|
|
170086
|
+
let body;
|
|
170087
|
+
try {
|
|
170088
|
+
const response = await fetchImpl(url, {
|
|
170089
|
+
method: op === "set" ? "PUT" : op === "clear" ? "DELETE" : "GET",
|
|
170090
|
+
redirect: "error",
|
|
170091
|
+
signal: AbortSignal.timeout(3e4),
|
|
170092
|
+
headers: {
|
|
170093
|
+
"content-type": "application/json",
|
|
170094
|
+
"x-control-token": target.controlToken,
|
|
170095
|
+
Authorization: wixToken,
|
|
170096
|
+
...target.previewRoute ? { "x-wix-route-serve": target.previewRoute } : {}
|
|
170097
|
+
},
|
|
170098
|
+
...op === "set" ? { body: JSON.stringify({ site, app: input.app }) } : {}
|
|
170099
|
+
});
|
|
170100
|
+
status = response.status;
|
|
170101
|
+
body = await response.json().catch(() => ({}));
|
|
170102
|
+
} catch {
|
|
170103
|
+
return fail4("control_unreachable", `could not reach the publishing service at ${control}`);
|
|
170104
|
+
}
|
|
170105
|
+
if (status < 200 || status >= 300) {
|
|
170106
|
+
return fail4(
|
|
170107
|
+
codeFor(status, body.error),
|
|
170108
|
+
typeof body.error === "string" ? body.error : `HTTP ${status}`,
|
|
170109
|
+
{ status, ...typeof body.error === "string" ? { serverError: body.error } : {} }
|
|
170110
|
+
);
|
|
170111
|
+
}
|
|
170112
|
+
if (op !== "show") return { ok: true, ...body };
|
|
170113
|
+
const pick2 = body.memberAppInSpaces;
|
|
170114
|
+
const appId2 = typeof pick2?.appId === "string" ? pick2.appId : null;
|
|
170115
|
+
let release2;
|
|
170116
|
+
if (appId2 && appId2 !== SPACES_DEFAULT_APP && !body.invalid) {
|
|
170117
|
+
try {
|
|
170118
|
+
const response = await fetchImpl(`${target.serve.replace(/\/+$/, "")}/v1/release/current?app=${encodeURIComponent(appId2)}`, {
|
|
170119
|
+
redirect: "error",
|
|
170120
|
+
signal: AbortSignal.timeout(3e4),
|
|
170121
|
+
// The same deployment the pick was read from (a preview route), never production's release.
|
|
170122
|
+
...target.previewRoute ? { headers: { "x-wix-route-serve": target.previewRoute } } : {}
|
|
170123
|
+
});
|
|
170124
|
+
release2 = response.ok ? await response.json() : void 0;
|
|
170125
|
+
} catch {
|
|
170126
|
+
release2 = void 0;
|
|
170127
|
+
}
|
|
170128
|
+
}
|
|
170129
|
+
const verdict = body.invalid ? { opens: SPACES_DEFAULT_APP, compatible: false, reason: `The pick is no longer valid (${String(body.invalid)}): the site resolves to Branded Lite` } : memberAppVerdict(appId2, release2, input.shell);
|
|
170130
|
+
return { ok: true, ...body, ...verdict, host: { name: "Spaces", version: SPACES_HOST_MANIFEST.version, ...input.shell ? { shell: input.shell } : {} } };
|
|
170131
|
+
}
|
|
170132
|
+
var SPACES_DEFAULT_APP, SITE_MEMBER_APP_USAGE, SITE_MEMBER_APP_CODES, SITE_RE2, fail4;
|
|
170133
|
+
var init_site_member_app = __esm({
|
|
170134
|
+
"src/site-member-app.ts"() {
|
|
170135
|
+
init_config();
|
|
170136
|
+
init_credential_hosts();
|
|
170137
|
+
init_contract();
|
|
170138
|
+
init_spaces_host_manifest();
|
|
170139
|
+
init_site_app();
|
|
170140
|
+
init_wix_owner();
|
|
170141
|
+
SPACES_DEFAULT_APP = DEFAULT_SITE_APP;
|
|
170142
|
+
SITE_MEMBER_APP_USAGE = "himi site member-app set <site> --app <id> | clear <site> | show <site> [--platform ios|android] [--target <name>] [--control-url <url>] [--control-token <t>] (<site> may be given as --site <msid>)";
|
|
170143
|
+
SITE_MEMBER_APP_CODES = [
|
|
170144
|
+
"invalid_usage",
|
|
170145
|
+
"insecure_target",
|
|
170146
|
+
"control_token_required",
|
|
170147
|
+
"wix_token_unavailable",
|
|
170148
|
+
"forbidden_site",
|
|
170149
|
+
"forbidden_app",
|
|
170150
|
+
"app_bound_to_other_site",
|
|
170151
|
+
"unauthorized",
|
|
170152
|
+
"control_unreachable",
|
|
170153
|
+
"request_failed"
|
|
170154
|
+
];
|
|
170155
|
+
SITE_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
170156
|
+
fail4 = (code, error, extra = {}) => ({ ok: false, code, error, ...extra });
|
|
170157
|
+
}
|
|
170158
|
+
});
|
|
170159
|
+
|
|
169710
170160
|
// src/site-analyze/visitor-auth.ts
|
|
169711
170161
|
async function mintVisitorToken(fetchImpl, clientId) {
|
|
169712
170162
|
const res = await fetchImpl(`${WIX_API3}/oauth2/token`, {
|
|
@@ -176466,7 +176916,7 @@ var COMMANDS2 = [
|
|
|
176466
176916
|
{ name: "connector", summary: "personal access tokens for the hosted MCP connector (Wix Native App Builder), for an AI tool that cannot sign in with OAuth (e.g. Base44's builder): `token create` opens a Wix sign-in page and prints a long-lived token once, to paste into the tool as `Authorization: Bearer <token>`; `token list` / `token revoke <id>` manage them with the `himi login --browser` token. The token can only build and publish DRAFTS.", required: "token create [--name <n>] [--days <1-90>] [--no-open] | token list | token revoke <id> [--target <t>]" },
|
|
176467
176917
|
{ name: "notify", summary: "Hosted --all-members requires --yes for a live send; --dry-run checks ownership/readiness and counts approved recipients without sending. `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 to one site member (--member-email) or all approved members (--all-members) 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> | --all-members (--dry-run | --yes)) --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]" },
|
|
176468
176918
|
{ name: "signing", summary: "READ-ONLY App Store Connect inventory for customer BYO TestFlight readiness. `inspect` lists whether the bundle id, distribution certificate, IOS_APP_STORE profile, and ASC app record exist for --bundle-id / --team-id using a local ASC .p8 (flags or ASC_KEY_* env). Never uploads or mutates Apple resources. Optional --cert-file/--profile-file classify on-disk material.", required: "inspect --bundle-id <id> --team-id <id> --asc-key-file <path> --asc-key-id <id> --asc-issuer-id <id> [--cert-file <p12> --cert-password <pw> --profile-file <mobileprovision>] [--json]" },
|
|
176469
|
-
{ 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 browser and never uploads or applies anything. A URL is optional there: `--url` lets it read the published page's Velo code-app ids (credential-free, pinned transport) so the backend source is found on sites where the owner code-app probe 404s. `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>] [--url <https>] [--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]" },
|
|
176919
|
+
{ 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 browser and never uploads or applies anything. A URL is optional there: `--url` lets it read the published page's Velo code-app ids (credential-free, pinned transport) so the backend source is found on sites where the owner code-app probe 404s. `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. `member-app set|clear|show <msid>` is the site's member app in Spaces (#4091): the himi app the site's members open in Spaces Lite instead of Branded Lite. `set --app <id>` takes the site's own app or one your account owns (an owned app not yet tied to the site is linked first; another account's app is refused, 403); `clear` returns the site to Branded Lite; `show` prints the pick plus the COMPUTED verdict \u2014 the picked release's requirements judged against the Spaces host manifest (checkHostCompatibility, `--platform` to judge one phone platform) \u2014 and `reason` when it falls back to Branded Lite. Auth is your `himi login` control token plus the account `wix token`, which the plane uses to verify you own the site.", 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>] [--url <https>] [--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] | member-app set|clear|show <msid> [--app <id>] [--platform ios|android]" },
|
|
176470
176920
|
{ name: "base44", summary: "read a BASE44 app into an app book (book.json + BOOK.md) for the agent building a Himi app from it \u2014 the Base44 counterpart of `site analyze`, READ-ONLY. `analyze --url <published app>` is the VISITOR pass: the app id, name, favicon and colours from the published SPA, its router paths, and screenshots + look tokens from the Playwright crawl. `analyze --app-id <id>` adds the OWNER pass and needs a session: the project source under <out>/source/ (the read half of `base44 eject` \u2014 GET api/apps/<id>/eject \u2014 through the same deny-list and secret scan `himi push` uses, widened by the book's token shapes; `eject` itself is never run because it CREATES a copy of the app), every entity's JSON schema, required fields and RLS rules with up to --sample redacted rows (default 5, 0 = off), backend functions, agents, connectors (names and scopes only, never tokens), secret NAMES (never values), auth visibility + providers, and the route \u2192 component \u2192 entities map from the source router. Every chapter it could not read is listed in `gaps` rather than failing the run. `login` runs Base44's device sign-in and stores the session in ~/.himi/base44/session.json (never the repo; --from-base44-cli imports `npx base44 login`'s session instead); BASE44_ACCESS_TOKEN in the environment wins, for CI. `whoami` prints who is signed in (never the token); `logout` removes the stored session. `auth-check --url <tenant> --ios-app-id <PREFIX.bundle.id>` and/or `--android-package <package> --android-sha256 <fingerprint>` checks public native-login associations and prints missing entries; it never reads an owner token. --json prints the book itself. himi docs base44-app-context", required: "analyze (--url <https://\u2026> | --app-id <id>) [--out .himi/base44-book] [--sample <n>] [--json] | login [--from-base44-cli] | whoami | logout | auth-check --url <https://tenant> [--ios-app-id <PREFIX.bundle.id>] [--android-package <package> --android-sha256 <fingerprint>]" },
|
|
176471
176921
|
{ 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>]" },
|
|
176472
176922
|
{ 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]" },
|
|
@@ -177179,13 +177629,13 @@ function previewTelemetryUrl(serveBase, app, release2) {
|
|
|
177179
177629
|
function diagnoseBody(body) {
|
|
177180
177630
|
const findings = body.findings;
|
|
177181
177631
|
if (!Array.isArray(findings)) return body;
|
|
177182
|
-
const
|
|
177632
|
+
const messageOf3 = (entry) => {
|
|
177183
177633
|
const message = entry && typeof entry === "object" ? entry.message : void 0;
|
|
177184
177634
|
return typeof message === "string" ? message : void 0;
|
|
177185
177635
|
};
|
|
177186
|
-
const shown2 = new Set(findings.map(
|
|
177636
|
+
const shown2 = new Set(findings.map(messageOf3).filter((message) => message !== void 0));
|
|
177187
177637
|
const folded = (value) => Array.isArray(value) && value.length > 0 && value.every((entry) => {
|
|
177188
|
-
const message =
|
|
177638
|
+
const message = messageOf3(entry);
|
|
177189
177639
|
return message !== void 0 && shown2.has(message);
|
|
177190
177640
|
});
|
|
177191
177641
|
const out2 = {};
|
|
@@ -184339,6 +184789,23 @@ Code: ${userCode}`);
|
|
|
184339
184789
|
}
|
|
184340
184790
|
case "site": {
|
|
184341
184791
|
const sub = pos[1];
|
|
184792
|
+
if (sub === "member-app") {
|
|
184793
|
+
const { runSiteMemberApp: runSiteMemberApp2 } = await Promise.resolve().then(() => (init_site_member_app(), site_member_app_exports));
|
|
184794
|
+
const r2 = await runSiteMemberApp2({
|
|
184795
|
+
op: pos[2],
|
|
184796
|
+
site: pos[3] ?? str9(flags.site),
|
|
184797
|
+
app: str9(flags.app),
|
|
184798
|
+
shell: str9(flags.platform),
|
|
184799
|
+
target: str9(flags.target),
|
|
184800
|
+
// Off-repo, `himi login` stores its token under `wix`; resolve where it did.
|
|
184801
|
+
defaultTarget: contextualDefaultTarget,
|
|
184802
|
+
controlUrl: str9(flags["control-url"]),
|
|
184803
|
+
controlToken: str9(flags["control-token"])
|
|
184804
|
+
});
|
|
184805
|
+
if (r2.ok) print(r2);
|
|
184806
|
+
else io2.error(JSON.stringify(r2));
|
|
184807
|
+
return r2.ok ? 0 : r2.code === "invalid_usage" ? 2 : 1;
|
|
184808
|
+
}
|
|
184342
184809
|
if (sub === "function") {
|
|
184343
184810
|
const { runSiteFunctionCli: runSiteFunctionCli2, SITE_FUNCTION_USAGE: SITE_FUNCTION_USAGE2 } = await Promise.resolve().then(() => (init_cli2(), cli_exports2));
|
|
184344
184811
|
try {
|
|
@@ -6,7 +6,7 @@ repurposed when human wording changes. New codes may be added; consumers must
|
|
|
6
6
|
handle an unknown code as a failure, without parsing prose.
|
|
7
7
|
|
|
8
8
|
**Rollout:** this contract is enforced for **`himi push`**, including `--only`,
|
|
9
|
-
first,
|
|
9
|
+
first, for **`himi store iap connect`**, and for **`himi site member-app`**. Other subcommands still have legacy failures without codes and are a
|
|
10
10
|
follow-up migration. This is an additive change: existing `error`, `errors`,
|
|
11
11
|
`message`, `hint`, status, body, and gate-specific fields stay as they were.
|
|
12
12
|
Some legacy envelopes have no singular `error` or `hint`; consumers must not
|
|
@@ -106,6 +106,31 @@ failure codes. A forced push still follows the existing override rules.
|
|
|
106
106
|
| `config_not_applied` | `--content` was given, but the binding is not in its `config.ts` (no config file, a dynamic or symlinked config, an edit `himi validate` rolled back, or no validator); the `config` report or `note` says what to add by hand. |
|
|
107
107
|
| `connect_failed` | An otherwise unclassified error stopped connect (for example an unreadable manifest, or a failed `--out` write). The original message is preserved. |
|
|
108
108
|
|
|
109
|
+
## `himi site member-app` codes
|
|
110
|
+
|
|
111
|
+
`himi site member-app set|clear|show <site>` prints one envelope. A refusal from the publishing service
|
|
112
|
+
keeps the service's own `error` in `serverError` and its HTTP `status`; the CLI `code` is one of:
|
|
113
|
+
|
|
114
|
+
| Code | Meaning |
|
|
115
|
+
|---|---|
|
|
116
|
+
| `invalid_usage` | Missing or malformed op, site id, `--app` or `--platform`. Nothing was sent. |
|
|
117
|
+
| `insecure_target` | The target's control URL is not an https `wix.com` host (or loopback), so the Wix credential was neither minted nor sent. Nothing was sent. |
|
|
118
|
+
| `control_token_required` | No control token for the target — run `himi login`. Nothing was sent. |
|
|
119
|
+
| `wix_token_unavailable` | The account Wix token (`wix token`) could not be minted; the publishing service needs it to verify site ownership. Nothing was sent. |
|
|
120
|
+
| `forbidden_site` | The publishing service could not verify that your account owns the site (403). |
|
|
121
|
+
| `forbidden_app` | The app is not yours, or does not exist (403). Nothing was stored. |
|
|
122
|
+
| `app_bound_to_other_site` | The app is another site's own app (403). |
|
|
123
|
+
| `unauthorized` | The control token was refused or revoked (401). |
|
|
124
|
+
| `control_unreachable` | The publishing service could not be reached. |
|
|
125
|
+
| `request_failed` | Any other refusal; `status` and `serverError` say which. |
|
|
126
|
+
|
|
127
|
+
`show` succeeds with `opens` (what members get: the picked app or `himi-branded-lite`), `compatible`
|
|
128
|
+
(whether the picked release fits the Spaces host manifest, judged with `checkHostCompatibility`), and —
|
|
129
|
+
whenever members get Branded Lite instead of the pick — `reason`. `opens` is Spaces' own decision, so a
|
|
130
|
+
compatible pick that this Spaces build cannot host yet reports `compatible: true` with `opens:
|
|
131
|
+
"himi-branded-lite"` and that reason. An incompatible pick is not a failure: it is `ok: true` with
|
|
132
|
+
`compatible: false`.
|
|
133
|
+
|
|
109
134
|
## Follow-ups
|
|
110
135
|
|
|
111
136
|
- Migrate failure envelopes in subcommands other than `push`, keeping this contract.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1352.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": [
|
|
@@ -71,5 +71,5 @@
|
|
|
71
71
|
"artifactId": "himalaya-cli"
|
|
72
72
|
}
|
|
73
73
|
},
|
|
74
|
-
"falconPackageHash": "
|
|
74
|
+
"falconPackageHash": "3d6e10a135511ba6f09d842a8dd9aee9013e5b36a3f4d79fe5a3f266"
|
|
75
75
|
}
|