@wix/himalaya-cli 0.1534.0 → 0.1536.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 CHANGED
@@ -2380,11 +2380,446 @@ var init_app_link = __esm({
2380
2380
  });
2381
2381
 
2382
2382
  // ../../core/serve-control/src/dist-jobs.ts
2383
- var TOKEN_TTL_MS, CUSTOMER_UPLOAD_LEASE_MS, DIST_SHELLS, DEFAULT_DIST_SHELL, ANDROID_SIGNING_POLICIES, ANDROID_SIGNING_ALIASES;
2383
+ var dist_jobs_exports = {};
2384
+ __export(dist_jobs_exports, {
2385
+ ANDROID_FORMATS: () => ANDROID_FORMATS,
2386
+ ANDROID_FORMAT_NOT_BUILT: () => ANDROID_FORMAT_NOT_BUILT,
2387
+ ANDROID_FORMAT_NOT_REQUESTED: () => ANDROID_FORMAT_NOT_REQUESTED,
2388
+ ANDROID_FORMAT_WRONG_SIGNER: () => ANDROID_FORMAT_WRONG_SIGNER,
2389
+ ANDROID_SIGNING_ALIASES: () => ANDROID_SIGNING_ALIASES,
2390
+ ANDROID_SIGNING_POLICIES: () => ANDROID_SIGNING_POLICIES,
2391
+ CUSTOMER_UPLOAD_LEASE_MS: () => CUSTOMER_UPLOAD_LEASE_MS,
2392
+ DEFAULT_ANDROID_FORMAT: () => DEFAULT_ANDROID_FORMAT,
2393
+ DEFAULT_ANDROID_SIGNING: () => DEFAULT_ANDROID_SIGNING,
2394
+ DEFAULT_BORROWABLE_IOS_IDS: () => DEFAULT_BORROWABLE_IOS_IDS,
2395
+ DEFAULT_DIST_SHELL: () => DEFAULT_DIST_SHELL,
2396
+ DEFAULT_DIST_SIGNING: () => DEFAULT_DIST_SIGNING,
2397
+ DEFAULT_GIT_URL: () => DEFAULT_GIT_URL,
2398
+ DIST_PACKAGE_NAME: () => DIST_PACKAGE_NAME,
2399
+ DIST_PARAMS_FLAG: () => DIST_PARAMS_FLAG,
2400
+ DIST_SHELLS: () => DIST_SHELLS,
2401
+ JobServiceBroker: () => JobServiceBroker,
2402
+ JobServiceError: () => JobServiceError,
2403
+ MAX_MEASURABLE_IDENTITY_WINDOW: () => MAX_MEASURABLE_IDENTITY_WINDOW,
2404
+ SCOPE_CANCEL: () => SCOPE_CANCEL,
2405
+ SCOPE_CREATE: () => SCOPE_CREATE,
2406
+ SCOPE_READ: () => SCOPE_READ,
2407
+ WIX_MANAGED_SIGNING_ALIASES: () => WIX_MANAGED_SIGNING_ALIASES,
2408
+ androidFormatSkewFailed: () => androidFormatSkewFailed,
2409
+ borrowableIosIds: () => borrowableIosIds,
2410
+ credsFromConfig: () => credsFromConfig,
2411
+ customerUploadClaimable: () => customerUploadClaimable,
2412
+ distJobSpec: () => distJobSpec,
2413
+ encodeDistParams: () => encodeDistParams,
2414
+ isBorrowableIosId: () => isBorrowableIosId,
2415
+ isSuccess: () => isSuccess,
2416
+ isTerminal: () => isTerminal,
2417
+ isTerminalTestflightStatus: () => isTerminalTestflightStatus,
2418
+ isValidDistAttemptId: () => isValidDistAttemptId,
2419
+ nextCustomerUploadClaim: () => nextCustomerUploadClaim,
2420
+ nextCustomerUploadSettlement: () => nextCustomerUploadSettlement,
2421
+ resolveAndroidFormat: () => resolveAndroidFormat,
2422
+ resolveAndroidSigning: () => resolveAndroidSigning,
2423
+ resolveBorrowedIosId: () => resolveBorrowedIosId,
2424
+ resolveDistSigning: () => resolveDistSigning,
2425
+ testflightStatusRank: () => testflightStatusRank
2426
+ });
2427
+ function isTerminal(status) {
2428
+ return !!status && !IN_FLIGHT.has(status);
2429
+ }
2430
+ function isSuccess(status) {
2431
+ return status === "SUCCESS";
2432
+ }
2433
+ function snapshot(job) {
2434
+ return {
2435
+ id: String(job.id),
2436
+ status: job.status ?? "STATUS_UNKNOWN",
2437
+ ...job.buildUrl ? { buildUrl: String(job.buildUrl) } : {},
2438
+ ...job.output ? { output: String(job.output) } : {},
2439
+ ...typeof job.attemptNumber === "number" ? { attemptNumber: job.attemptNumber } : {}
2440
+ };
2441
+ }
2442
+ function truncate(s2, max = 400) {
2443
+ return s2.length > max ? `${s2.slice(0, max)}\u2026` : s2;
2444
+ }
2445
+ function credsFromConfig(cfg) {
2446
+ const appDefId = cfg("POCO_APP_DEF_ID")?.trim();
2447
+ const appSecret = cfg("POCO_APP_SECRET")?.trim();
2448
+ if (!appDefId || !appSecret) return void 0;
2449
+ return { appDefId, appSecret };
2450
+ }
2451
+ function isValidDistAttemptId(value2) {
2452
+ return typeof value2 === "string" && /^[A-Za-z0-9_-]{1,128}$/.test(value2);
2453
+ }
2454
+ function customerUploadClaimable(pending, now) {
2455
+ if (!pending) return false;
2456
+ if (pending.status === "READY_FOR_UPLOAD") return true;
2457
+ if (pending.status !== "UPLOADING") return false;
2458
+ if (!pending.claimedAt) return true;
2459
+ const claimedAt = Date.parse(pending.claimedAt);
2460
+ const at2 = Date.parse(now);
2461
+ return Number.isFinite(claimedAt) && Number.isFinite(at2) && at2 - claimedAt >= CUSTOMER_UPLOAD_LEASE_MS;
2462
+ }
2463
+ function nextCustomerUploadClaim(record2, now) {
2464
+ if (!record2 || record2.status !== "SUCCESS" || !customerUploadClaimable(record2.customerAppStore, now)) return void 0;
2465
+ return {
2466
+ ...record2,
2467
+ customerAppStore: { ...record2.customerAppStore, status: "UPLOADING", claimedAt: now },
2468
+ updatedAt: now
2469
+ };
2470
+ }
2471
+ function nextCustomerUploadSettlement(record2, claimedAt, update, now) {
2472
+ const pending = record2?.customerAppStore;
2473
+ if (!record2 || pending?.status !== "UPLOADING" || pending.claimedAt !== claimedAt) return void 0;
2474
+ return {
2475
+ ...record2,
2476
+ customerAppStore: {
2477
+ version: pending.version,
2478
+ mode: pending.mode,
2479
+ claimedAt: pending.claimedAt,
2480
+ status: update.status,
2481
+ ...update.error ? { error: update.error } : {},
2482
+ ...update.delivery ? { delivery: update.delivery } : {}
2483
+ },
2484
+ updatedAt: now
2485
+ };
2486
+ }
2487
+ function isTerminalTestflightStatus(status) {
2488
+ return /(?:^|_)(?:COMPLETED|FAILED|NOT_FOUND)$/.test(status?.toUpperCase() ?? "");
2489
+ }
2490
+ function testflightStatusRank(status) {
2491
+ const normalized = status?.toUpperCase() ?? "";
2492
+ if (isTerminalTestflightStatus(normalized)) return 3;
2493
+ if (/(?:^|_)UPLOADING$/.test(normalized)) return 2;
2494
+ if (/(?:^|_)PENDING$/.test(normalized)) return 1;
2495
+ return 0;
2496
+ }
2497
+ function borrowableIosIds(raw) {
2498
+ const parsed = (raw ?? "").split(",").map((s2) => s2.trim().toLowerCase()).filter(Boolean);
2499
+ return parsed.length > 0 ? parsed : DEFAULT_BORROWABLE_IOS_IDS;
2500
+ }
2501
+ function isBorrowableIosId(id, allowed2 = DEFAULT_BORROWABLE_IOS_IDS) {
2502
+ const candidate = id.toLowerCase();
2503
+ return allowed2.some(
2504
+ (pattern) => pattern.endsWith("*") ? candidate.startsWith(pattern.slice(0, -1)) : candidate === pattern
2505
+ );
2506
+ }
2507
+ function resolveBorrowedIosId(opts) {
2508
+ const { requested, platform } = opts;
2509
+ if (requested === void 0 || requested === null || requested === "") return {};
2510
+ if (opts.selfServe || opts.role === "owner") {
2511
+ return {
2512
+ error: {
2513
+ error: "operator_only_borrow_id",
2514
+ message: "borrowIosBundleId is not available to self-serve credentials",
2515
+ hint: "Ship the change over-the-air instead \u2014 OTA needs no rebuild and no borrowed signing identity."
2516
+ }
2517
+ };
2518
+ }
2519
+ if (typeof requested !== "string") {
2520
+ return { error: { error: "invalid_borrow_id", message: "borrowIosBundleId must be a string" } };
2521
+ }
2522
+ const id = requested.trim().toLowerCase();
2523
+ if (platform !== "ios") {
2524
+ return {
2525
+ error: {
2526
+ error: "borrow_id_ios_only",
2527
+ message: `borrowIosBundleId applies to iOS signing only (got platform "${platform}")`,
2528
+ hint: "Android needs no provisioning profile \u2014 drop the flag for android builds."
2529
+ }
2530
+ };
2531
+ }
2532
+ if (!BUNDLE_ID_RE.test(id)) {
2533
+ return {
2534
+ error: {
2535
+ error: "invalid_borrow_id",
2536
+ message: `"${requested}" is not a valid reverse-DNS bundle id`
2537
+ }
2538
+ };
2539
+ }
2540
+ const allowed2 = opts.allowed ?? DEFAULT_BORROWABLE_IOS_IDS;
2541
+ if (!isBorrowableIosId(id, allowed2)) {
2542
+ return {
2543
+ error: {
2544
+ error: "borrow_id_not_allowed",
2545
+ message: `"${id}" is not borrowable; allowed: ${allowed2.join(", ")}`,
2546
+ hint: "Only internal enterprise ids may be borrowed \u2014 a store id would replace the real App Store app on the device. An operator can change this with HIMI_DIST_BORROWABLE_IOS_IDS."
2547
+ }
2548
+ };
2549
+ }
2550
+ return { bundleId: id };
2551
+ }
2552
+ function resolveDistSigning(requested) {
2553
+ if (requested === void 0 || requested === null || requested === "") {
2554
+ return { policy: DEFAULT_DIST_SIGNING };
2555
+ }
2556
+ if (typeof requested !== "string") {
2557
+ return { error: { status: 400, body: { error: "invalid_signing", message: "signing must be a string" } } };
2558
+ }
2559
+ const want = requested.trim().toLowerCase();
2560
+ if (WIX_MANAGED_SIGNING_ALIASES.includes(want)) return { policy: "wix-managed" };
2561
+ if (want === "byo") return { policy: "byo" };
2562
+ return {
2563
+ error: {
2564
+ status: 501,
2565
+ body: {
2566
+ error: "dist_signing_unsupported",
2567
+ message: `signing "${requested}" is not implemented`,
2568
+ supported: [DEFAULT_DIST_SIGNING, "byo"]
2569
+ }
2570
+ }
2571
+ };
2572
+ }
2573
+ function resolveAndroidSigning(requested) {
2574
+ if (requested === void 0 || requested === null || requested === "") {
2575
+ return { policy: DEFAULT_ANDROID_SIGNING };
2576
+ }
2577
+ if (typeof requested !== "string") {
2578
+ return { error: { status: 400, body: { error: "invalid_android_signing", message: "androidSigning must be a string" } } };
2579
+ }
2580
+ const want = requested.trim().toLowerCase();
2581
+ const policy = Object.hasOwn(ANDROID_SIGNING_ALIASES, want) ? ANDROID_SIGNING_ALIASES[want] : void 0;
2582
+ if (policy) return { policy };
2583
+ return {
2584
+ error: {
2585
+ status: 400,
2586
+ body: {
2587
+ error: "invalid_android_signing",
2588
+ message: `androidSigning "${requested}" is not a known policy`,
2589
+ supported: ["qa-keystore", "wix-keystore", "debug"]
2590
+ }
2591
+ }
2592
+ };
2593
+ }
2594
+ function androidFormatSkewFailed(record2) {
2595
+ return record2.platform === "android" && typeof record2.error === "string" && [ANDROID_FORMAT_NOT_BUILT, ANDROID_FORMAT_WRONG_SIGNER, ANDROID_FORMAT_NOT_REQUESTED].some((code) => record2.error.includes(`${code}:`));
2596
+ }
2597
+ function resolveAndroidFormat(requested) {
2598
+ if (requested === void 0 || requested === null || requested === "") return { format: DEFAULT_ANDROID_FORMAT };
2599
+ if (typeof requested === "string" && ANDROID_FORMATS.includes(requested)) {
2600
+ return { format: requested };
2601
+ }
2602
+ return {
2603
+ error: {
2604
+ status: 400,
2605
+ body: {
2606
+ error: "invalid_android_format",
2607
+ message: `androidFormat ${typeof requested === "string" ? `"${requested.slice(0, 40)}"` : `of type ${typeof requested}`} is not a known format`,
2608
+ supported: [...ANDROID_FORMATS]
2609
+ }
2610
+ }
2611
+ };
2612
+ }
2613
+ function encodeDistParams(env) {
2614
+ return Buffer.from(JSON.stringify(env), "utf8").toString("base64url");
2615
+ }
2616
+ function distJobSpec(req) {
2617
+ const envVars = {
2618
+ APP_DIR: req.appDir,
2619
+ // WHICH APP this binary is FOR, as distinct from which shell builds it. Without it the pool
2620
+ // can only infer an app from APP_DIR — i.e. the shell — so it baked the SHELL's content and
2621
+ // resolved the SHELL's OTA app id. A device-verified consequence: `himi dist --app demo-app`
2622
+ // produced a binary rendering himi_branded_home. The shell is the container; this is the app.
2623
+ HIMI_DIST_APP: req.app,
2624
+ // (HIMI_DIST_PROVISIONING_ENV is set at the END of this object, after `req.env` — see there.)
2625
+ // run-dist gates iOS on DIST_ENABLE_IOS / DIST_PROVISIONING_PROFILE / an explicit
2626
+ // `[dist:ios]` IN THE COMMIT MESSAGE. A serve-brokered job has no commit by design, and
2627
+ // `--force` only bypasses the `[dist]` tag gate — so without this an `--platform ios`
2628
+ // request would skip the build and finish as SUCCESS with no install link. Asking for iOS
2629
+ // through the API IS the explicit opt-in that `[dist:ios]` represents.
2630
+ ...req.platform === "ios" ? { DIST_ENABLE_IOS: "1" } : {},
2631
+ ...req.release ? { HIMI_DIST_RELEASE_PIN: req.release } : {},
2632
+ ...req.contractUrl ? { HIMI_DIST_CONTRACT_URL: req.contractUrl } : {},
2633
+ // Where the pool fetches the RELEASE to bake its offline seed from. Its absence is what makes
2634
+ // the classic Falcon `[dist]` path fall back to building the seed from repo source.
2635
+ ...req.seedUrl ? { HIMI_DIST_SEED_URL: req.seedUrl } : {},
2636
+ ...req.platform === "android" && req.androidConfigUrl ? { HIMI_DIST_ANDROID_CONFIG_URL: req.androidConfigUrl } : {},
2637
+ // Where the pool fetches its SIGNING IDENTITY (profile + p12 + password). A URL, not the
2638
+ // bytes: the envelope is ~20KB of base64 and `command` is capped at MAX_COMMAND_CHARS — the
2639
+ // same reason the brand contract travels this way. It also keeps key material out of the
2640
+ // job params, which the pool echoes into its log.
2641
+ ...req.signingUrl ? { HIMI_DIST_SIGNING_URL: req.signingUrl } : {},
2642
+ // WHICH KEYSTORE the Android build signs with. Android only — on an iOS job this would be a
2643
+ // variable nothing reads, and dispatching one implies a decision that was never made.
2644
+ // A bundle dispatches the QA key BY NAME, never `wix-keystore`. `--aab` always means the Wix
2645
+ // production key, and the new run-dist derives that from DIST_ANDROID_FORMAT itself, overriding
2646
+ // this. Naming `wix-keystore` here would reach a run-dist OLDER than `--aab` too (the pool builds
2647
+ // the release's own commit): it ignores the format, builds an installable APK, signs it with the
2648
+ // Wix production key and uploads and announces it — the exact artifact the self-serve 403
2649
+ // withholds. Naming NOTHING is not safe either: a pool machine with DIST_ANDROID_USE_WIX_KEYSTORE=1
2650
+ // then hands that old runner the Wix key anyway. A named QA key outranks that machine setting, so
2651
+ // an old runner signs an ordinary QA APK and the job fails as `android_format_not_built`.
2652
+ ...req.platform === "android" && req.androidSigning ? { DIST_ANDROID_SIGNING: req.androidFormat === "aab" ? "qa-keystore" : req.androidSigning } : {},
2653
+ // A Play bundle instead of an APK. Only when asked: the APK default needs no parameter, and a
2654
+ // runner that predates the variable ignores it — which the result callback catches.
2655
+ ...req.platform === "android" && req.androidFormat === "aab" ? { DIST_ANDROID_FORMAT: "aab" } : {},
2656
+ ...req.previewRoute ? { HIMI_DIST_PREVIEW_ROUTE: req.previewRoute } : {},
2657
+ ...req.callbackUrl ? { HIMI_DIST_CALLBACK_URL: req.callbackUrl } : {},
2658
+ ...req.callbackToken ? { HIMI_DIST_CALLBACK_TOKEN: req.callbackToken } : {},
2659
+ // The per-job artifact path component. Without it two concurrent jobs for one
2660
+ // app+shell+platform+commit wrote the same ipa, manifest.plist and install.html, and the
2661
+ // loser's install page then handed a tester the other build's binary.
2662
+ ...req.jobNonce ? { HIMI_DIST_JOB_NONCE: req.jobNonce } : {},
2663
+ // Who to DM the install link to. See DistJobRequest.requestedBy: the git-history guess the pool
2664
+ // falls back to misroutes brokered builds to an unrelated colleague.
2665
+ ...req.requestedBy ? { HIMI_DIST_REQUESTED_BY: req.requestedBy } : {},
2666
+ ...req.env,
2667
+ ...req.buildOrigin ? { HIMI_DIST_BUILD_ORIGIN: req.buildOrigin } : {},
2668
+ // AFTER `req.env`, deliberately. This one field is the SHELL's declared answer, and it is the
2669
+ // only thing standing between owner-lite and a build that reads the fetched contract under
2670
+ // branded-lite's key — i.e. ignores it and ships unbranded while reporting success. `req.env`
2671
+ // is operator config (`deps.env`), so a stray HIMI_DIST_PROVISIONING_ENV there is a plausible
2672
+ // misconfiguration, and it would silently unbrand EVERY shell at once. Generic overrides do
2673
+ // not get to answer a per-shell question.
2674
+ ...req.provisioningEnv ? { HIMI_DIST_PROVISIONING_ENV: req.provisioningEnv } : {}
2675
+ };
2676
+ const command = `dist:${req.platform} ${DIST_PARAMS_FLAG} ${encodeDistParams(envVars)}`;
2677
+ if (command.length > MAX_COMMAND_CHARS) {
2678
+ throw new Error(
2679
+ `dist command is ${command.length} chars (cap ${MAX_COMMAND_CHARS}); shrink the job env \u2014 pass large values as a URL the Mac job fetches, as the brand contract does`
2680
+ );
2681
+ }
2682
+ return {
2683
+ gitUrl: req.gitUrl ?? DEFAULT_GIT_URL,
2684
+ gitCommitSha: req.gitCommitSha,
2685
+ packageName: DIST_PACKAGE_NAME,
2686
+ command,
2687
+ // Job Service renders this metadata in Buildkite's job label. User labels are sanitized,
2688
+ // and the runner also carries buildOrigin so it does not treat them as GitHub PR refs.
2689
+ branchName: req.buildLabel ?? req.branchName ?? "master",
2690
+ envVars,
2691
+ ...req.xcodeVersion ? { xcodeVersion: req.xcodeVersion } : {}
2692
+ };
2693
+ }
2694
+ var IN_FLIGHT, SCOPE_CREATE, SCOPE_READ, SCOPE_CANCEL, DEFAULT_BASE_URL, DEFAULT_OAUTH_URL, TOKEN_TTL_MS, JobServiceError, JobServiceBroker, CUSTOMER_UPLOAD_LEASE_MS, MAX_MEASURABLE_IDENTITY_WINDOW, DIST_SHELLS, DEFAULT_DIST_SHELL, DEFAULT_BORROWABLE_IOS_IDS, BUNDLE_ID_RE, DEFAULT_DIST_SIGNING, WIX_MANAGED_SIGNING_ALIASES, DEFAULT_ANDROID_SIGNING, ANDROID_SIGNING_POLICIES, ANDROID_SIGNING_ALIASES, DEFAULT_ANDROID_FORMAT, ANDROID_FORMATS, ANDROID_FORMAT_NOT_BUILT, ANDROID_FORMAT_WRONG_SIGNER, ANDROID_FORMAT_NOT_REQUESTED, DEFAULT_GIT_URL, DIST_PACKAGE_NAME, DIST_PARAMS_FLAG, MAX_COMMAND_CHARS;
2384
2695
  var init_dist_jobs = __esm({
2385
2696
  "../../core/serve-control/src/dist-jobs.ts"() {
2697
+ IN_FLIGHT = /* @__PURE__ */ new Set(["CREATED", "QUEUED", "WORKING"]);
2698
+ SCOPE_CREATE = "MRE.JOB_CREATE";
2699
+ SCOPE_READ = "MRE.JOB_READ";
2700
+ SCOPE_CANCEL = "MRE.CANCEL_JOB";
2701
+ DEFAULT_BASE_URL = "https://bo.wix.com/job-service";
2702
+ DEFAULT_OAUTH_URL = "https://www.wixapis.com/oauth/access";
2386
2703
  TOKEN_TTL_MS = 5 * 60 * 1e3;
2704
+ JobServiceError = class extends Error {
2705
+ constructor(message2, status, body) {
2706
+ super(message2);
2707
+ this.status = status;
2708
+ this.body = body;
2709
+ this.name = "JobServiceError";
2710
+ }
2711
+ };
2712
+ JobServiceBroker = class {
2713
+ baseUrl;
2714
+ oauthUrl;
2715
+ fetchImpl;
2716
+ now;
2717
+ creds;
2718
+ /** scope -> { token, expiresAt } */
2719
+ tokens = /* @__PURE__ */ new Map();
2720
+ constructor(opts) {
2721
+ if (!opts.creds?.appDefId || !opts.creds?.appSecret) {
2722
+ throw new JobServiceError("job service credentials missing (POCO_APP_DEF_ID / POCO_APP_SECRET)");
2723
+ }
2724
+ this.creds = opts.creds;
2725
+ this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
2726
+ this.oauthUrl = opts.oauthUrl ?? DEFAULT_OAUTH_URL;
2727
+ this.fetchImpl = opts.fetchImpl ?? fetch;
2728
+ this.now = opts.now ?? Date.now;
2729
+ }
2730
+ /** Mint (or reuse) a token for one MRE scope. */
2731
+ async token(scope2) {
2732
+ const cached3 = this.tokens.get(scope2);
2733
+ if (cached3 && cached3.expiresAt > this.now()) return cached3.token;
2734
+ const res = await this.fetchImpl(this.oauthUrl, {
2735
+ method: "POST",
2736
+ headers: { "content-type": "application/json" },
2737
+ body: JSON.stringify({
2738
+ grant_type: "client_credentials",
2739
+ client_id: this.creds.appDefId,
2740
+ client_secret: this.creds.appSecret,
2741
+ scope: scope2
2742
+ })
2743
+ });
2744
+ const text11 = await res.text();
2745
+ if (!res.ok) {
2746
+ throw new JobServiceError(`oauth failed for scope ${scope2}`, res.status, truncate(text11));
2747
+ }
2748
+ let token;
2749
+ try {
2750
+ token = JSON.parse(text11).access_token;
2751
+ } catch {
2752
+ throw new JobServiceError(`oauth returned non-JSON for scope ${scope2}`, res.status, truncate(text11));
2753
+ }
2754
+ if (!token) throw new JobServiceError(`oauth returned no access_token for scope ${scope2}`, res.status);
2755
+ this.tokens.set(scope2, { token, expiresAt: this.now() + TOKEN_TTL_MS });
2756
+ return token;
2757
+ }
2758
+ async call(scope2, method, path2, body) {
2759
+ const token = await this.token(scope2);
2760
+ const res = await this.fetchImpl(`${this.baseUrl}${path2}`, {
2761
+ method,
2762
+ // BARE token, not `Bearer <token>` — matches jobServiceApi's own header.
2763
+ headers: { Authorization: token, ...body ? { "content-type": "application/json" } : {} },
2764
+ ...body ? { body: JSON.stringify(body) } : {}
2765
+ });
2766
+ const text11 = await res.text();
2767
+ if (!res.ok) {
2768
+ throw new JobServiceError(`job service ${method} ${path2} failed`, res.status, truncate(text11));
2769
+ }
2770
+ if (!text11) return {};
2771
+ try {
2772
+ return JSON.parse(text11);
2773
+ } catch {
2774
+ throw new JobServiceError(`job service ${method} ${path2} returned non-JSON`, res.status, truncate(text11));
2775
+ }
2776
+ }
2777
+ /**
2778
+ * Create a NODE_COMMAND job on the Mac (or Linux) pool. Returns as soon as Job Service has
2779
+ * queued it — this never waits for the build.
2780
+ */
2781
+ async createNodeCommand(spec, os2 = "mac", notify) {
2782
+ for (const key3 of ["gitUrl", "gitCommitSha", "packageName", "command", "branchName"]) {
2783
+ if (!spec[key3]) throw new JobServiceError(`createNodeCommand: missing ${key3}`);
2784
+ }
2785
+ const optionsKey = os2 === "linux" ? "linuxNodeCommandOptions" : "nodeCommandOptions";
2786
+ const type = os2 === "linux" ? "LINUX_NODE_COMMAND" : "NODE_COMMAND";
2787
+ const options = {
2788
+ packageManager: "YARN",
2789
+ // the only value Job Service accepts
2790
+ gitUrl: spec.gitUrl,
2791
+ gitCommitSha: spec.gitCommitSha,
2792
+ packageName: spec.packageName,
2793
+ command: spec.command,
2794
+ branchName: spec.branchName,
2795
+ ...spec.envVars ? { envVars: spec.envVars } : {}
2796
+ };
2797
+ if (os2 === "mac" && spec.xcodeVersion) options.xcodeVersion = spec.xcodeVersion;
2798
+ const subscriptions = {
2799
+ ...notify?.ownershipTags?.length ? { subscribedOwnershipTags: notify.ownershipTags } : {},
2800
+ ...notify?.userIds?.length ? { subscribedUserIds: notify.userIds } : {}
2801
+ };
2802
+ const data = await this.call(SCOPE_CREATE, "POST", "/v1/job", {
2803
+ job: { type, [optionsKey]: options, ...subscriptions }
2804
+ });
2805
+ const job = data?.job;
2806
+ if (!job?.id) throw new JobServiceError("job service create returned no job id");
2807
+ return snapshot(job);
2808
+ }
2809
+ /** Current state of a job. */
2810
+ async read(jobId) {
2811
+ const data = await this.call(SCOPE_READ, "GET", `/v1/job/${encodeURIComponent(jobId)}`);
2812
+ const job = data?.job;
2813
+ if (!job) throw new JobServiceError(`job service read returned no job for ${jobId}`);
2814
+ return snapshot({ id: jobId, ...job });
2815
+ }
2816
+ /** Ask Job Service to cancel a queued/running job. */
2817
+ async cancel(jobId) {
2818
+ await this.call(SCOPE_CANCEL, "POST", `/v1/job/${encodeURIComponent(jobId)}/cancel`);
2819
+ }
2820
+ };
2387
2821
  CUSTOMER_UPLOAD_LEASE_MS = 15 * 60 * 1e3;
2822
+ MAX_MEASURABLE_IDENTITY_WINDOW = 100;
2388
2823
  DIST_SHELLS = {
2389
2824
  "branded-lite": {
2390
2825
  appDir: "apps/himi-branded-lite",
@@ -2437,6 +2872,11 @@ var init_dist_jobs = __esm({
2437
2872
  }
2438
2873
  };
2439
2874
  DEFAULT_DIST_SHELL = "branded-lite";
2875
+ DEFAULT_BORROWABLE_IOS_IDS = ["ent.*"];
2876
+ BUNDLE_ID_RE = /^[a-z][a-z0-9]*(\.[a-z][a-z0-9]*)+$/;
2877
+ DEFAULT_DIST_SIGNING = "wix-managed";
2878
+ WIX_MANAGED_SIGNING_ALIASES = ["wix-managed", "wix", "pool-enterprise"];
2879
+ DEFAULT_ANDROID_SIGNING = "qa-keystore";
2440
2880
  ANDROID_SIGNING_POLICIES = ["qa-keystore", "wix-keystore", "debug"];
2441
2881
  ANDROID_SIGNING_ALIASES = {
2442
2882
  // The canonical spellings, derived so the two lists cannot drift apart.
@@ -2446,6 +2886,15 @@ var init_dist_jobs = __esm({
2446
2886
  wix: "wix-keystore",
2447
2887
  oneapp: "wix-keystore"
2448
2888
  };
2889
+ DEFAULT_ANDROID_FORMAT = "apk";
2890
+ ANDROID_FORMATS = ["apk", "aab"];
2891
+ ANDROID_FORMAT_NOT_BUILT = "android_format_not_built";
2892
+ ANDROID_FORMAT_WRONG_SIGNER = "android_format_wrong_signer";
2893
+ ANDROID_FORMAT_NOT_REQUESTED = "android_format_not_requested";
2894
+ DEFAULT_GIT_URL = "https://github.com/wix-private/himalaya";
2895
+ DIST_PACKAGE_NAME = "@himalaya/native-ci";
2896
+ DIST_PARAMS_FLAG = "--himi-dist";
2897
+ MAX_COMMAND_CHARS = 2e3;
2449
2898
  }
2450
2899
  });
2451
2900
 
@@ -9726,7 +10175,6 @@ function resolveTranslation(value2, catalog4, sourceCatalog) {
9726
10175
  var BINDING_SIGILS, COLON_SIGILS, BINDING_SIGIL_RE, APP_BINDING_PREFIX, APP_BINDING_RE, TRANSLATION_PREFIX, TRANSLATION_KEY_RE;
9727
10176
  var init_bindings = __esm({
9728
10177
  "../../core/ts/src/bindings.ts"() {
9729
- "use strict";
9730
10178
  BINDING_SIGILS = ["service", "flag", "item", "t"];
9731
10179
  COLON_SIGILS = /* @__PURE__ */ new Set(["t"]);
9732
10180
  BINDING_SIGIL_RE = new RegExp(
@@ -9874,16 +10322,16 @@ function scanWidgetPayload(node, family, path2, bindings, disallowed, timeRefs,
9874
10322
  scanWidgetPayload(v2, family, `${path2}.${k2}`, bindings, disallowed, timeRefs, intents, actionSites2);
9875
10323
  }
9876
10324
  }
9877
- function validateWidget(snapshot2) {
10325
+ function validateWidget(snapshot3) {
9878
10326
  const validate5 = compileWidgetSchema();
9879
- const schemaOk = validate5(snapshot2);
10327
+ const schemaOk = validate5(snapshot3);
9880
10328
  const schemaErrors = schemaOk ? [] : validate5.errors ?? [];
9881
10329
  const bindingViolations = [];
9882
10330
  const disallowedComponents = [];
9883
10331
  const timeRefViolations = [];
9884
10332
  const intentViolations = [];
9885
10333
  const actionSites2 = [];
9886
- const snap = snapshot2 ?? {};
10334
+ const snap = snapshot3 ?? {};
9887
10335
  const family = snap.family;
9888
10336
  scanWidgetPayload(snap.payload, family, "$.payload", bindingViolations, disallowedComponents, timeRefViolations, intentViolations, actionSites2);
9889
10337
  if (snap.placeholderWhenStale !== void 0) {
@@ -13557,12 +14005,12 @@ function responseBytes(value2) {
13557
14005
  return 0;
13558
14006
  }
13559
14007
  }
13560
- function restoredState(def, snapshot2) {
14008
+ function restoredState(def, snapshot3) {
13561
14009
  const declared = def?.state ?? {};
13562
- if (!snapshot2 || typeof snapshot2 !== "object" || Array.isArray(snapshot2)) return declared;
14010
+ if (!snapshot3 || typeof snapshot3 !== "object" || Array.isArray(snapshot3)) return declared;
13563
14011
  const fresh = [def?.notHydrated, def?.perVisit].flatMap((keys) => Array.isArray(keys) ? keys : []);
13564
14012
  const merged = { ...declared };
13565
- for (const [key3, value2] of Object.entries(snapshot2)) {
14013
+ for (const [key3, value2] of Object.entries(snapshot3)) {
13566
14014
  if (key3 !== "_error" && !fresh.includes(key3)) merged[key3] = value2;
13567
14015
  }
13568
14016
  return merged;
@@ -28063,7 +28511,7 @@ function json(res, status, obj5) {
28063
28511
  res.setHeader("content-type", "application/json; charset=utf-8");
28064
28512
  res.end(body);
28065
28513
  }
28066
- function truncate(s2) {
28514
+ function truncate2(s2) {
28067
28515
  if (s2 === void 0) return void 0;
28068
28516
  return s2.length > BODY_CAP ? s2.slice(0, BODY_CAP) + `\u2026[+${s2.length - BODY_CAP}B]` : s2;
28069
28517
  }
@@ -28078,8 +28526,8 @@ function redactHeaders(h2) {
28078
28526
  }
28079
28527
  function recordWixTraffic(gw, app, adminUrl, ev) {
28080
28528
  const full = { ...ev, id: ++gw.seq, app };
28081
- full.reqBody = truncate(redactBodyString(full.reqBody));
28082
- full.respBody = truncate(redactBodyString(full.respBody));
28529
+ full.reqBody = truncate2(redactBodyString(full.reqBody));
28530
+ full.respBody = truncate2(redactBodyString(full.respBody));
28083
28531
  gw.traffic.push(full);
28084
28532
  if (gw.traffic.length > TRAFFIC_CAP) gw.traffic.splice(0, gw.traffic.length - TRAFFIC_CAP);
28085
28533
  const text11 = `event: wix.traffic
@@ -116690,7 +117138,7 @@ function ensureListAnimateRuntime() {
116690
117138
  listAnimateRuntimeInstalled = true;
116691
117139
  const prevRects = /* @__PURE__ */ new WeakMap();
116692
117140
  const rowKey = (c2) => c2.dataset?.componentId ?? c2.querySelector("[data-component-id]")?.dataset?.componentId;
116693
- const snapshot2 = (host) => {
117141
+ const snapshot3 = (host) => {
116694
117142
  const m2 = /* @__PURE__ */ new Map();
116695
117143
  Array.from(host.children).forEach((c2) => {
116696
117144
  const id = rowKey(c2);
@@ -116702,7 +117150,7 @@ function ensureListAnimateRuntime() {
116702
117150
  const flip = (host) => {
116703
117151
  const prev = prevRects.get(host);
116704
117152
  if (!prev) {
116705
- snapshot2(host);
117153
+ snapshot3(host);
116706
117154
  return;
116707
117155
  }
116708
117156
  const next = /* @__PURE__ */ new Map();
@@ -116745,7 +117193,7 @@ function ensureListAnimateRuntime() {
116745
117193
  const scan = () => {
116746
117194
  document.querySelectorAll(hostSel).forEach((h2) => {
116747
117195
  if (!prevRects.has(h2)) {
116748
- snapshot2(h2);
117196
+ snapshot3(h2);
116749
117197
  childObs.observe(h2, { childList: true });
116750
117198
  }
116751
117199
  });
@@ -121245,7 +121693,7 @@ var init_renderNode = __esm({
121245
121693
  }, [startPositionPath, boundStartPosition, status]);
121246
121694
  const emit = React12.useCallback((action, extra = {}) => {
121247
121695
  if (!action || !ctx.onAction) return;
121248
- const snapshot2 = {
121696
+ const snapshot3 = {
121249
121697
  sessionId,
121250
121698
  state: status,
121251
121699
  status,
@@ -121260,7 +121708,7 @@ var init_renderNode = __esm({
121260
121708
  artist: String(item?.artist ?? ""),
121261
121709
  error
121262
121710
  };
121263
- ctx.onAction({ ...action, args: { ...action.args ?? {}, ...snapshot2, ...extra }, params: { ...action.params ?? {}, sessionId, index: String(index), ...Object.fromEntries(Object.entries(extra).map(([k2, v2]) => [k2, String(v2)])) } });
121711
+ ctx.onAction({ ...action, args: { ...action.args ?? {}, ...snapshot3, ...extra }, params: { ...action.params ?? {}, sessionId, index: String(index), ...Object.fromEntries(Object.entries(extra).map(([k2, v2]) => [k2, String(v2)])) } });
121264
121712
  }, [ctx.onAction, sessionId, status, index, position, duration2, item, buffered, rate, props.muted, fullscreen, error]);
121265
121713
  React12.useEffect(() => {
121266
121714
  if (!isUnsupportedProvider || status === "error") return;
@@ -127553,15 +128001,15 @@ function interpretProduce(services, parsed) {
127553
128001
  }
127554
128002
  return { services, widgets, views };
127555
128003
  }
127556
- function contentEtag(snapshot2) {
128004
+ function contentEtag(snapshot3) {
127557
128005
  const canonical7 = JSON.stringify({
127558
- widgetId: snapshot2.widgetId,
127559
- family: snapshot2.family,
127560
- size: snapshot2.size,
127561
- payload: snapshot2.payload,
127562
- deepLink: snapshot2.deepLink,
128006
+ widgetId: snapshot3.widgetId,
128007
+ family: snapshot3.family,
128008
+ size: snapshot3.size,
128009
+ payload: snapshot3.payload,
128010
+ deepLink: snapshot3.deepLink,
127563
128011
  // Lever A — a timeline change must bump the etag (frame values/times are content).
127564
- frames: snapshot2.frames ?? null
128012
+ frames: snapshot3.frames ?? null
127565
128013
  });
127566
128014
  return "sha256-" + createHash15("sha256").update(canonical7).digest("base64");
127567
128015
  }
@@ -127604,8 +128052,8 @@ function freezeCaptured(def, widgetId, opts = {}) {
127604
128052
  generatedAt: opts.generatedAt ?? Math.floor(Date.now() / 1e3),
127605
128053
  ...frames ? { frames } : {}
127606
128054
  };
127607
- const snapshot2 = { ...base, contentEtag: contentEtag(base) };
127608
- const result = validateWidget(snapshot2);
128055
+ const snapshot3 = { ...base, contentEtag: contentEtag(base) };
128056
+ const result = validateWidget(snapshot3);
127609
128057
  if (!result.ok) {
127610
128058
  const reasons = [];
127611
128059
  if (result.bindingViolations.length) {
@@ -127627,7 +128075,7 @@ function freezeCaptured(def, widgetId, opts = {}) {
127627
128075
  }
127628
128076
  throw new Error(`widget "${widgetId}" produced an invalid snapshot \u2014 ${reasons.join(" | ")}`);
127629
128077
  }
127630
- return snapshot2;
128078
+ return snapshot3;
127631
128079
  }
127632
128080
  function viewWidgetId(viewId, family) {
127633
128081
  return `${viewId}.${family}`;
@@ -127727,8 +128175,8 @@ function freezeOverrideSnapshot(input, opts = {}) {
127727
128175
  ...input.placeholderWhenStale !== void 0 ? { placeholderWhenStale: input.placeholderWhenStale } : {},
127728
128176
  ...input.frames !== void 0 ? { frames: input.frames } : {}
127729
128177
  };
127730
- const snapshot2 = { ...base, contentEtag: contentEtag(base) };
127731
- const result = validateWidget(snapshot2);
128178
+ const snapshot3 = { ...base, contentEtag: contentEtag(base) };
128179
+ const result = validateWidget(snapshot3);
127732
128180
  if (!result.ok) {
127733
128181
  const reasons = [];
127734
128182
  if (result.bindingViolations.length) {
@@ -127750,7 +128198,7 @@ function freezeOverrideSnapshot(input, opts = {}) {
127750
128198
  }
127751
128199
  throw new Error(`override snapshot for "${input.widgetId}" is invalid \u2014 ${reasons.join(" | ")}`);
127752
128200
  }
127753
- return snapshot2;
128201
+ return snapshot3;
127754
128202
  }
127755
128203
  var MAX_TIMELINE_FRAMES, WIDGET_BUDGET_MS, realmPromise, WidgetRealmUnavailableError, PRODUCE_CACHE_TTL_MS, MAX_PRODUCE_CACHE_ENTRIES, MAX_PRODUCE_ENTRY_BYTES, MAX_PRODUCE_CACHE_BYTES, produceCache, produceCacheGeneration, CAPTURE_SLOT, READBACK_SERVICE;
127756
128204
  var init_widgets = __esm({
@@ -130388,9 +130836,9 @@ async function buildSnapshotForId(widgetId, dir) {
130388
130836
  try {
130389
130837
  const js2 = loaded.bytes.toString("utf8");
130390
130838
  if (entry.view) {
130391
- const snapshot2 = await buildViewSnapshot(js2, entry.view.viewId, entry.view.surfaceId);
130392
- if (!snapshot2) return { ok: false, status: 404, error: "widget_not_found" };
130393
- return { ok: true, snapshot: snapshot2 };
130839
+ const snapshot3 = await buildViewSnapshot(js2, entry.view.viewId, entry.view.surfaceId);
130840
+ if (!snapshot3) return { ok: false, status: 404, error: "widget_not_found" };
130841
+ return { ok: true, snapshot: snapshot3 };
130394
130842
  }
130395
130843
  return { ok: true, snapshot: await buildWidgetSnapshot(js2, widgetId) };
130396
130844
  } catch (err) {
@@ -133651,7 +134099,7 @@ __export(screen_crawl_exports, {
133651
134099
  recordScreenTraffic: () => recordScreenTraffic,
133652
134100
  renderedNameGaps: () => renderedNameGaps,
133653
134101
  rootOnAppear: () => rootOnAppear,
133654
- snapshot: () => snapshot,
134102
+ snapshot: () => snapshot2,
133655
134103
  structuralSignature: () => structuralSignature,
133656
134104
  unverifiableNodes: () => unverifiableNodes,
133657
134105
  workerArgs: () => workerArgs
@@ -134389,7 +134837,7 @@ function hasOwnError(state) {
134389
134837
  }
134390
134838
  return false;
134391
134839
  }
134392
- function snapshot(w2) {
134840
+ function snapshot2(w2) {
134393
134841
  const state = {};
134394
134842
  const defects = {};
134395
134843
  for (const [name, h2] of Object.entries(w2.handles)) {
@@ -134455,7 +134903,7 @@ async function bootScreenWorker(opts) {
134455
134903
  }
134456
134904
  }
134457
134905
  for (let i2 = 0; i2 < 20; i2++) await yieldMacrotask();
134458
- const { state, defects } = snapshot(w2);
134906
+ const { state, defects } = snapshot2(w2);
134459
134907
  return { ...w2, hostCalls, deniedCapabilities, state: Object.keys(state).length ? state : w2.services, defects, ...deadLifecycle ? { deadLifecycle } : {} };
134460
134908
  }
134461
134909
  function effectSince(w2, mark, action, componentId) {
@@ -134577,7 +135025,7 @@ async function crawlScreenJourney(opts) {
134577
135025
  fail6(`journey "${opts.journey.name}" cannot find ${step.component ? `${step.component} \u2192 ` : ""}${step.action} in this screen`, step);
134578
135026
  continue;
134579
135027
  }
134580
- const state = snapshot(worker).state;
135028
+ const state = snapshot2(worker).state;
134581
135029
  const site = effectiveSiteFor(declared, state);
134582
135030
  if (!site) {
134583
135031
  fail6(`journey "${opts.journey.name}" cannot dispatch ${step.action}: its list has no rendered row`, step);
@@ -134604,7 +135052,7 @@ async function crawlScreenJourney(opts) {
134604
135052
  const stepEffect = effectSince(worker, mark, site.actionId, site.componentId);
134605
135053
  if (stepEffect) effects.push(stepEffect);
134606
135054
  }
134607
- const settled = snapshot(worker);
135055
+ const settled = snapshot2(worker);
134608
135056
  if (worker.errors.length) {
134609
135057
  for (const error of worker.errors) fail6(`journey "${opts.journey.name}" worker error: ${error.service}: ${error.message}`);
134610
135058
  }
@@ -135025,7 +135473,7 @@ async function crawlScreenInner(opts) {
135025
135473
  continue;
135026
135474
  }
135027
135475
  const trigger = { tap: site.componentId, key: site.key, action: site.actionId };
135028
- const preState = snapshot(w2).state;
135476
+ const preState = snapshot2(w2).state;
135029
135477
  const effective = effectiveSiteFor(site, preState);
135030
135478
  if (!effective) {
135031
135479
  actionsSkipped.push({ action: site.actionId, why: "no-row-value" });
@@ -135044,7 +135492,7 @@ async function crawlScreenInner(opts) {
135044
135492
  errors.push({ service: parsed.service, message: `${parsed.action}: ${errText(e2)}`, ...e2.stack ? { stack: e2.stack } : {}, argless: workerArgs(dispatched).length === 0 });
135045
135493
  }
135046
135494
  exercised += 1;
135047
- const { state, defects } = snapshot(w2);
135495
+ const { state, defects } = snapshot2(w2);
135048
135496
  check(trigger, state, errors, defects);
135049
135497
  reportDenied(w2.deniedCapabilities.slice(deniedBefore), trigger);
135050
135498
  const navCountBefore = navEdges.length;
@@ -135303,7 +135751,7 @@ async function bootAndSnapshotState(opts) {
135303
135751
  }
135304
135752
  try {
135305
135753
  for (let i2 = 0; i2 < 20; i2++) await yieldMacrotask();
135306
- return snapshot(w2).state;
135754
+ return snapshot2(w2).state;
135307
135755
  } finally {
135308
135756
  w2.dispose();
135309
135757
  }
@@ -135378,7 +135826,7 @@ async function crawlScreenDeep(opts, deep) {
135378
135826
  threwAt = "unreachable";
135379
135827
  break;
135380
135828
  }
135381
- const effective = effectiveSiteFor(site, snapshot(w2).state);
135829
+ const effective = effectiveSiteFor(site, snapshot2(w2).state);
135382
135830
  if (!effective) {
135383
135831
  threwAt = "unreachable";
135384
135832
  break;
@@ -135417,7 +135865,7 @@ async function crawlScreenDeep(opts, deep) {
135417
135865
  }
135418
135866
  for (let i2 = 0; i2 < 20; i2++) await yieldMacrotask();
135419
135867
  flushStep();
135420
- const { state, defects } = snapshot(w2);
135868
+ const { state, defects } = snapshot2(w2);
135421
135869
  const hash2 = deepStateSignature(state, defects);
135422
135870
  if (visited.has(hash2)) continue;
135423
135871
  visited.add(hash2);
@@ -135551,7 +135999,7 @@ async function crawlScreenRelations(opts) {
135551
135999
  const w2 = await boot();
135552
136000
  try {
135553
136001
  if (w2.errors.length) return null;
135554
- let prev = snapshot(w2).state;
136002
+ let prev = snapshot2(w2).state;
135555
136003
  const bootState = prev;
135556
136004
  for (const [i2, site] of path2.entries()) {
135557
136005
  const parsed = parseWorkerAction(site.actionId);
@@ -135568,7 +136016,7 @@ async function crawlScreenRelations(opts) {
135568
136016
  }
135569
136017
  for (let k2 = 0; k2 < 20; k2++) await yieldMacrotask();
135570
136018
  if (w2.errors.length) return null;
135571
- prev = snapshot(w2).state;
136019
+ prev = snapshot2(w2).state;
135572
136020
  }
135573
136021
  return prev;
135574
136022
  } finally {
@@ -136775,7 +137223,7 @@ async function liveRenderServices(bundleJs, opts) {
136775
137223
  }
136776
137224
  }
136777
137225
  if (opts.host) await settleUnawaitedWork();
136778
- return { services: snapshot(w2).state, calls: w2.calls, errors: w2.errors };
137226
+ return { services: snapshot2(w2).state, calls: w2.calls, errors: w2.errors };
136779
137227
  } finally {
136780
137228
  w2.dispose();
136781
137229
  }
@@ -136790,7 +137238,7 @@ async function loadAndSettle(bundleJs, options) {
136790
137238
  const w2 = await bootBundleWorker(bundleJs, options);
136791
137239
  try {
136792
137240
  await settleUnawaitedWork();
136793
- return { services: snapshot(w2).state, calls: w2.calls, errors: w2.errors };
137241
+ return { services: snapshot2(w2).state, calls: w2.calls, errors: w2.errors };
136794
137242
  } finally {
136795
137243
  w2.dispose();
136796
137244
  }
@@ -137494,7 +137942,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
137494
137942
  }
137495
137943
  }
137496
137944
  }
137497
- const snapshot2 = await snapshotTokens(
137945
+ const snapshot3 = await snapshotTokens(
137498
137946
  app,
137499
137947
  base,
137500
137948
  async () => {
@@ -137524,10 +137972,10 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
137524
137972
  },
137525
137973
  (text11) => store.putTokens(app, text11)
137526
137974
  );
137527
- if (snapshot2.hash) tokensHash = snapshot2.hash;
137528
- if (snapshot2.failure) {
137529
- tokensSnapshotFailure = snapshot2.failure;
137530
- console.error(snapshot2.failure.message);
137975
+ if (snapshot3.hash) tokensHash = snapshot3.hash;
137976
+ if (snapshot3.failure) {
137977
+ tokensSnapshotFailure = snapshot3.failure;
137978
+ console.error(snapshot3.failure.message);
137531
137979
  }
137532
137980
  Object.assign(catalogs, await bakeCatalogs(
137533
137981
  app,
@@ -140161,13 +140609,237 @@ var init_wix_owner = __esm({
140161
140609
  }
140162
140610
  });
140163
140611
 
140612
+ // src/captcha-auth.ts
140613
+ function captchaAuthFinding(auth, siteId, platforms) {
140614
+ const login = auth;
140615
+ if (login?.providerId !== "wix-consumer") return void 0;
140616
+ const inline = login.config?.captcha;
140617
+ const hasInline = typeof inline === "object" && inline !== null;
140618
+ const inlineFor = (platform) => hasInline && !!inline[platform];
140619
+ const inlineKeys = platforms?.length ? platforms.every(inlineFor) : inlineFor("ios") || inlineFor("android");
140620
+ const site = siteId?.trim().toLowerCase();
140621
+ const bound2 = typeof login.config?.siteId === "string" ? login.config.siteId : "";
140622
+ const uncovered = hasInline ? (platforms ?? []).filter((platform) => !inlineFor(platform)) : [];
140623
+ if (bound2 && uncovered.length) return {
140624
+ code: "captcha_auth_inline_key_missing",
140625
+ keyless: true,
140626
+ message: `auth (WixConsumerAuthProvider) declares inline captcha keys but none for ${uncovered.join(" and ")}, and the inline block replaces the baked key file on device \u2014 a native ${uncovered.join("/")} build ships with no member CAPTCHA key. Add captcha.${uncovered[0]} (or remove the captcha block to use the baked key), push a new release, and build from it.`
140627
+ };
140628
+ if (!bound2) return {
140629
+ code: "captcha_auth_site_missing",
140630
+ keyless: true,
140631
+ message: `auth (WixConsumerAuthProvider) names no siteId, so a native build cannot carry a member CAPTCHA key: the build drops the key file and the device refuses the key \u2014 member sign-in on a CAPTCHA-protected site fails with "Complete verification to continue". Add siteId: "${site ?? "<the site's metaSiteId, lower case>"}" to WixConsumerAuthProvider in config.ts, push a new release, and build from it.`
140632
+ };
140633
+ if (bound2 !== bound2.trim().toLowerCase() && !inlineKeys) return {
140634
+ code: "captcha_auth_site_case",
140635
+ keyless: true,
140636
+ message: `auth (WixConsumerAuthProvider) names siteId "${bound2}", but member CAPTCHA keys are stored and matched under the lower-case id, exactly, so a native build would ship without one. Write siteId: "${bound2.trim().toLowerCase()}", push a new release, and build from it.`
140637
+ };
140638
+ if (site && bound2.trim().toLowerCase() !== site) return {
140639
+ code: "captcha_auth_site_mismatch",
140640
+ keyless: false,
140641
+ message: `auth (WixConsumerAuthProvider) names siteId "${bound2}", not ${site}, so a member CAPTCHA key for ${site} cannot bind to this app's login and native member sign-in on a CAPTCHA-protected site fails. Bind the login and the build to the same site.`
140642
+ };
140643
+ return void 0;
140644
+ }
140645
+ var init_captcha_auth = __esm({
140646
+ "src/captcha-auth.ts"() {
140647
+ }
140648
+ });
140649
+
140650
+ // ../../stdlib/auth-providers/wix/src/member-captcha-policy.ts
140651
+ function acceptsClientSiteKeyToken(option) {
140652
+ return CLIENT_SITE_KEY_OPTIONS.includes(option);
140653
+ }
140654
+ function asOption(value2) {
140655
+ return value2 === "ALWAYS" || value2 === "SUSPECTED_BOTS_ONLY" || value2 === "NEVER" ? value2 : "UNKNOWN";
140656
+ }
140657
+ function parseMemberCaptchaPolicy(raw) {
140658
+ const settings = raw?.settings ?? {};
140659
+ return {
140660
+ login: asOption(settings.loginRecaptchaOption),
140661
+ signup: asOption(settings.signupRecaptchaOption)
140662
+ };
140663
+ }
140664
+ var MEMBER_SITE_SETTINGS_URL, CLIENT_SITE_KEY_OPTIONS;
140665
+ var init_member_captcha_policy = __esm({
140666
+ "../../stdlib/auth-providers/wix/src/member-captcha-policy.ts"() {
140667
+ MEMBER_SITE_SETTINGS_URL = "https://manage.wix.com/_api/wix-sm-webapp/v1/collection/settings";
140668
+ CLIENT_SITE_KEY_OPTIONS = ["ALWAYS", "SUSPECTED_BOTS_ONLY"];
140669
+ }
140670
+ });
140671
+
140672
+ // src/site-analyze/rest.ts
140673
+ var rest_exports = {};
140674
+ __export(rest_exports, {
140675
+ WIX_API: () => WIX_API2,
140676
+ WixApiError: () => WixApiError2,
140677
+ classifyHttp: () => classifyHttp,
140678
+ compactWixstaticUrl: () => compactWixstaticUrl,
140679
+ isGenericWixFavicon: () => isGenericWixFavicon,
140680
+ makeTransport: () => makeTransport,
140681
+ mediaUrlFromLogo: () => mediaUrlFromLogo,
140682
+ ownerTransportFrom: () => ownerTransportFrom,
140683
+ probeCall: () => probeCall,
140684
+ resolveWixUrl: () => resolveWixUrl,
140685
+ uploadMediaBytes: () => uploadMediaBytes,
140686
+ visitorTransportFrom: () => visitorTransportFrom,
140687
+ wixMediaFileId: () => wixMediaFileId
140688
+ });
140689
+ function resolveWixUrl(path2) {
140690
+ if (/^https?:\/\//i.test(path2)) return path2;
140691
+ return `${WIX_API2}${path2}`;
140692
+ }
140693
+ function classifyHttp(status, count2) {
140694
+ if (status === 428) return "not-installed";
140695
+ if (status === 404) return "wrong-path";
140696
+ if (status && status >= 400) return "error";
140697
+ return count2 > 0 ? "ok" : "empty";
140698
+ }
140699
+ function makeTransport(fetchImpl, auth, timeoutMs = DEFAULT_TIMEOUT_MS2) {
140700
+ return async (method, path2, body) => {
140701
+ const headers2 = { Accept: "application/json" };
140702
+ if (auth?.token) headers2.Authorization = auth.token;
140703
+ if (auth?.msid) headers2["wix-site-id"] = auth.msid;
140704
+ if (body !== void 0) headers2["Content-Type"] = "application/json";
140705
+ const res = await fetchImpl(resolveWixUrl(path2), {
140706
+ method,
140707
+ headers: headers2,
140708
+ body: body === void 0 ? void 0 : JSON.stringify(body),
140709
+ signal: AbortSignal.timeout(timeoutMs)
140710
+ });
140711
+ const text11 = await res.text();
140712
+ let parsed = text11;
140713
+ try {
140714
+ parsed = text11 ? JSON.parse(text11) : null;
140715
+ } catch {
140716
+ }
140717
+ if (!res.ok) throw new WixApiError2(res.status, method, path2, parsed);
140718
+ return parsed;
140719
+ };
140720
+ }
140721
+ function ownerTransportFrom(fetchImpl, owner) {
140722
+ return makeTransport(fetchImpl, { token: owner.token, msid: owner.msid });
140723
+ }
140724
+ function visitorTransportFrom(fetchImpl, token, msid) {
140725
+ return makeTransport(fetchImpl, { token, msid });
140726
+ }
140727
+ async function probeCall(call, method, path2, body) {
140728
+ try {
140729
+ return { data: await call(method, path2, body), err: null };
140730
+ } catch (e2) {
140731
+ if (e2 instanceof WixApiError2) return { data: null, err: e2 };
140732
+ throw e2;
140733
+ }
140734
+ }
140735
+ function mediaUrlFromLogo(logo) {
140736
+ const s2 = (logo ?? "").trim();
140737
+ if (!s2) return null;
140738
+ if (/^https?:\/\//i.test(s2)) return s2;
140739
+ const id = s2.replace(/^wix:image:\/\/v1\//, "").split("/")[0].split("#")[0];
140740
+ if (!id) return null;
140741
+ if (/^https?:\/\//i.test(id)) return id;
140742
+ return `https://static.wixstatic.com/media/${id}`;
140743
+ }
140744
+ function isGenericWixFavicon(url) {
140745
+ try {
140746
+ const h2 = new URL(url).hostname.toLowerCase();
140747
+ return h2 === "wix.com" || h2.endsWith(".wix.com");
140748
+ } catch {
140749
+ return false;
140750
+ }
140751
+ }
140752
+ function wixMediaFileId(url) {
140753
+ const m2 = url.match(/static\.wixstatic\.com\/media\/([^/?#]+)/i);
140754
+ return m2?.[1] ? decodeURIComponent(m2[1]) : void 0;
140755
+ }
140756
+ function compactWixstaticUrl(url, maxEdge = 800) {
140757
+ if (!/static\.wixstatic\.com\/media\//i.test(url)) return url;
140758
+ if (/\.(svg|ico)(\?|#|$)/i.test(url.split("?")[0] ?? url)) return url;
140759
+ const w2 = url.match(/(?:\/|,)w_(\d+)/)?.[1];
140760
+ if (w2 && Number(w2) <= maxEdge) return url;
140761
+ const id = wixMediaFileId(url);
140762
+ if (!id) return url;
140763
+ return `https://static.wixstatic.com/media/${id}/v1/fill/w_${maxEdge},h_${maxEdge},al_c,q_80,enc_auto/file.jpg`;
140764
+ }
140765
+ async function uploadMediaBytes(call, fetchImpl, bytes2, fileName, mimeType) {
140766
+ const { uploadUrl } = await call(
140767
+ "POST",
140768
+ "/site-media/v1/files/generate-upload-url",
140769
+ { mimeType, fileName: `himi-business-book/${fileName}` }
140770
+ );
140771
+ const put = await fetchImpl(`${uploadUrl}?filename=${encodeURIComponent(fileName)}`, {
140772
+ method: "PUT",
140773
+ headers: { "Content-Type": mimeType },
140774
+ body: bytes2,
140775
+ signal: AbortSignal.timeout(12e4)
140776
+ });
140777
+ if (!put.ok) throw new Error(`media upload PUT failed: ${put.status}`);
140778
+ const payload = await put.json();
140779
+ const file2 = payload.file ?? payload;
140780
+ const id = file2?.id ?? file2?.fileId;
140781
+ const url = file2?.url ?? (id ? `https://static.wixstatic.com/media/${id}` : void 0);
140782
+ if (!id || !url) throw new Error("media upload returned no file id");
140783
+ return { id, url };
140784
+ }
140785
+ var WIX_API2, DEFAULT_TIMEOUT_MS2, WixApiError2;
140786
+ var init_rest = __esm({
140787
+ "src/site-analyze/rest.ts"() {
140788
+ WIX_API2 = "https://www.wixapis.com";
140789
+ DEFAULT_TIMEOUT_MS2 = 8e3;
140790
+ WixApiError2 = class extends Error {
140791
+ constructor(status, method, path2, body) {
140792
+ super(`${method} ${path2} \u2192 ${status}`);
140793
+ this.status = status;
140794
+ this.method = method;
140795
+ this.path = path2;
140796
+ this.body = body;
140797
+ this.name = "WixApiError";
140798
+ }
140799
+ };
140800
+ }
140801
+ });
140802
+
140803
+ // src/site-analyze/visitor-auth.ts
140804
+ var visitor_auth_exports = {};
140805
+ __export(visitor_auth_exports, {
140806
+ mintVisitorToken: () => mintVisitorToken
140807
+ });
140808
+ async function mintVisitorToken(fetchImpl, clientId) {
140809
+ const res = await fetchImpl(`${WIX_API2}/oauth2/token`, {
140810
+ method: "POST",
140811
+ headers: { "Content-Type": "application/json", Accept: "application/json" },
140812
+ body: JSON.stringify({ clientId, grantType: "anonymous" }),
140813
+ signal: AbortSignal.timeout(8e3)
140814
+ });
140815
+ const text11 = await res.text();
140816
+ let parsed = text11;
140817
+ try {
140818
+ parsed = text11 ? JSON.parse(text11) : null;
140819
+ } catch {
140820
+ }
140821
+ if (!res.ok) throw new WixApiError2(res.status, "POST", "/oauth2/token", parsed);
140822
+ const token = parsed?.access_token ?? parsed?.accessToken;
140823
+ if (!token) throw new Error("visitor mint returned no access_token");
140824
+ return token;
140825
+ }
140826
+ var init_visitor_auth = __esm({
140827
+ "src/site-analyze/visitor-auth.ts"() {
140828
+ init_rest();
140829
+ }
140830
+ });
140831
+
140164
140832
  // src/captcha.ts
140165
140833
  var captcha_exports = {};
140166
140834
  __export(captcha_exports, {
140835
+ captchaAuthFinding: () => captchaAuthFinding,
140167
140836
  captchaContentInput: () => captchaContentInput,
140168
- runCaptcha: () => runCaptcha
140837
+ captchaDistGate: () => captchaDistGate,
140838
+ contentCaptchaAuthFinding: () => contentCaptchaAuthFinding,
140839
+ runCaptcha: () => runCaptcha,
140840
+ siteMemberCaptchaPolicy: () => siteMemberCaptchaPolicy
140169
140841
  });
140170
- import { readFileSync as readFileSync40 } from "node:fs";
140842
+ import { existsSync as existsSync36, readFileSync as readFileSync40 } from "node:fs";
140171
140843
  import { resolve as resolve34 } from "node:path";
140172
140844
  function readObject(path2) {
140173
140845
  try {
@@ -140186,6 +140858,64 @@ function captchaContentInput(dir) {
140186
140858
  androidApplicationId: text2(provisioning.native?.androidApplicationId)
140187
140859
  };
140188
140860
  }
140861
+ async function contentAuth(dir, app) {
140862
+ if (!existsSync36(resolve34(dir, "himalaya.content.json"))) return void 0;
140863
+ if (app !== void 0 && captchaContentInput(dir).app !== app) return void 0;
140864
+ try {
140865
+ const { loadAppConfigModule: loadAppConfigModule2 } = await Promise.resolve().then(() => (init_app_config_loader(), app_config_loader_exports));
140866
+ return (await loadAppConfigModule2(dir))?.auth;
140867
+ } catch {
140868
+ return void 0;
140869
+ }
140870
+ }
140871
+ async function contentCaptchaAuthFinding(dir, siteId, app, platforms) {
140872
+ const auth = await contentAuth(dir, app);
140873
+ return auth === void 0 ? void 0 : captchaAuthFinding(auth, siteId, platforms);
140874
+ }
140875
+ async function siteMemberCaptchaPolicy(clientId, fetchImpl = fetch) {
140876
+ const { mintVisitorToken: mintVisitorToken2 } = await Promise.resolve().then(() => (init_visitor_auth(), visitor_auth_exports));
140877
+ const token = await mintVisitorToken2(fetchImpl, clientId);
140878
+ const res = await fetchImpl(MEMBER_SITE_SETTINGS_URL, {
140879
+ headers: { Authorization: token, Accept: "application/json" },
140880
+ signal: AbortSignal.timeout(8e3)
140881
+ });
140882
+ if (!res.ok) throw new Error(`the member settings read answered HTTP ${res.status}`);
140883
+ return parseMemberCaptchaPolicy(await res.json());
140884
+ }
140885
+ async function releaseAuth(client2, app, release2) {
140886
+ try {
140887
+ let previewToken;
140888
+ if (release2) {
140889
+ const minted = await client2.previewToken(app, release2);
140890
+ previewToken = minted.json?.previewToken;
140891
+ if (!minted.ok || typeof previewToken !== "string") return { error: `no preview token for release ${release2} (HTTP ${minted.status})` };
140892
+ }
140893
+ const read = await client2.fetchAppConfig(app, release2, previewToken);
140894
+ if (!read.ok) return { error: `its app-config read answered HTTP ${read.status}` };
140895
+ return { auth: read.json?.authConfig ?? null };
140896
+ } catch (error) {
140897
+ return { error: error?.message ?? String(error) };
140898
+ }
140899
+ }
140900
+ async function captchaDistGate(options) {
140901
+ const { auth, error } = await releaseAuth(options.client, options.app, options.release);
140902
+ if (error) return { advisory: `member CAPTCHA check skipped: the release's login could not be read (${error}). If the login names no siteId and the site requires a member CAPTCHA, member sign-in in this build will fail.` };
140903
+ const finding2 = captchaAuthFinding(auth, options.requestedSite, options.platforms);
140904
+ if (!finding2) return {};
140905
+ if (!finding2.keyless) return { advisory: `${finding2.code}: ${finding2.message}` };
140906
+ const clientId = auth.config?.clientId;
140907
+ const unasked = (why) => ({ advisory: `${finding2.code}: ${finding2.message} Not refused: ${why}, so whether the site requires a member CAPTCHA is unknown \u2014 if it does, member sign-in in this build will fail.` });
140908
+ if (typeof clientId !== "string" || !clientId || clientId === PLACEHOLDER_CLIENT_ID) return unasked("the login has no Wix client to ask with");
140909
+ let policy;
140910
+ try {
140911
+ policy = await siteMemberCaptchaPolicy(clientId, options.fetchImpl ?? fetch);
140912
+ } catch (error2) {
140913
+ return unasked(`the site's member settings could not be read (${error2?.message ?? String(error2)})`);
140914
+ }
140915
+ const demands = ["login", "signup"].filter((source) => acceptsClientSiteKeyToken(policy[source]));
140916
+ if (demands.length === 0) return {};
140917
+ return { refuse: { code: finding2.code, captchaPolicy: policy, message: `${finding2.message} The site requires a CAPTCHA for member ${demands.map((source) => `${source} (${policy[source]})`).join(" and ")}. The key is baked only for a build bound to the site (--site, provisioning.json, or the app's own site binding).` } };
140918
+ }
140189
140919
  async function runCaptcha(pos, flags, io2, deps = {}) {
140190
140920
  const operation = pos[1];
140191
140921
  if (operation !== "setup" && operation !== "status") {
@@ -140215,6 +140945,14 @@ async function runCaptcha(pos, flags, io2, deps = {}) {
140215
140945
  fetchImpl: deps.fetchImpl
140216
140946
  });
140217
140947
  io2.log(JSON.stringify(result.body));
140948
+ const anyReady = (result.body.records ?? []).some((record2) => record2?.status === "ready");
140949
+ const finding2 = operation === "setup" && anyReady ? await contentCaptchaAuthFinding(
140950
+ text2(flags.content) ?? process.cwd(),
140951
+ input.siteId,
140952
+ input.app,
140953
+ [...input.iosBundleId ? ["ios"] : [], ...input.androidApplicationId ? ["android"] : []]
140954
+ ) : void 0;
140955
+ if (finding2) io2.error(`\u26A0 ${finding2.code}: ${finding2.message}`);
140218
140956
  return result.ok ? 0 : 1;
140219
140957
  } catch {
140220
140958
  io2.error(JSON.stringify({ error: "captcha_service_unavailable", complete: false }));
@@ -140228,6 +140966,9 @@ var init_captcha2 = __esm({
140228
140966
  init_captcha();
140229
140967
  init_captcha_service();
140230
140968
  init_wix_owner();
140969
+ init_captcha_auth();
140970
+ init_wix_placeholders();
140971
+ init_member_captcha_policy();
140231
140972
  text2 = (value2) => typeof value2 === "string" ? value2 : void 0;
140232
140973
  }
140233
140974
  });
@@ -140241,7 +140982,7 @@ __export(preflight_exports, {
140241
140982
  parseStoreConfig: () => parseStoreConfig,
140242
140983
  requireEnv: () => requireEnv
140243
140984
  });
140244
- import { existsSync as existsSync36, readFileSync as readFileSync41 } from "node:fs";
140985
+ import { existsSync as existsSync37, readFileSync as readFileSync41 } from "node:fs";
140245
140986
  import { isAbsolute as isAbsolute2, relative as relative7, resolve as resolve35 } from "node:path";
140246
140987
  function isInsideRepo(p2) {
140247
140988
  const rel = relative7(REPO_ROOT, resolve35(p2));
@@ -140298,7 +141039,7 @@ function parseStoreConfig(text11) {
140298
141039
  }
140299
141040
  function loadStoreConfig(app) {
140300
141041
  const p2 = storeConfigPath(app);
140301
- if (!existsSync36(p2)) {
141042
+ if (!existsSync37(p2)) {
140302
141043
  throw new Error(`No store config at ${p2}. Create apps/${app}/store/store.config.yaml first (see /setup-store-signing).`);
140303
141044
  }
140304
141045
  return parseStoreConfig(readFileSync41(p2, "utf8"));
@@ -143989,10 +144730,10 @@ var init_Matcher = __esm({
143989
144730
  * Restore state from snapshot.
143990
144731
  * @param {Object} snapshot
143991
144732
  */
143992
- restore(snapshot2) {
144733
+ restore(snapshot3) {
143993
144734
  this._pathStringCache = null;
143994
- this.path = snapshot2.path.map((node) => ({ ...node }));
143995
- this.siblingStacks = snapshot2.siblingStacks.map((map) => new Map(map));
144735
+ this.path = snapshot3.path.map((node) => ({ ...node }));
144736
+ this.siblingStacks = snapshot3.siblingStacks.map((map) => new Map(map));
143996
144737
  }
143997
144738
  /**
143998
144739
  * Return the read-only {@link MatcherView} for this matcher.
@@ -147030,7 +147771,7 @@ var init_customer_signing_inspect = __esm({
147030
147771
  });
147031
147772
 
147032
147773
  // src/push-onboarding.ts
147033
- import { existsSync as existsSync37, mkdirSync as mkdirSync19, readFileSync as readFileSync42, statSync as statSync9, writeFileSync as writeFileSync13, chmodSync as chmodSync2 } from "node:fs";
147774
+ import { existsSync as existsSync38, mkdirSync as mkdirSync19, readFileSync as readFileSync42, statSync as statSync9, writeFileSync as writeFileSync13, chmodSync as chmodSync2 } from "node:fs";
147034
147775
  import { basename as basename11, dirname as dirname24, join as join32, resolve as resolve36 } from "node:path";
147035
147776
  function readJson4(path2) {
147036
147777
  try {
@@ -147042,7 +147783,7 @@ function readJson4(path2) {
147042
147783
  }
147043
147784
  function pushInputsFromContent(dir) {
147044
147785
  const root = resolve36(dir);
147045
- if (!existsSync37(join32(root, "himalaya.content.json"))) return { initialized: false };
147786
+ if (!existsSync38(join32(root, "himalaya.content.json"))) return { initialized: false };
147046
147787
  const content = readJson4(join32(root, "himalaya.content.json"));
147047
147788
  const provisioning = readJson4(join32(root, "provisioning.json"));
147048
147789
  const native = provisioning.native ?? {};
@@ -147174,7 +147915,7 @@ function buildPushSetupBody(i2, keys) {
147174
147915
  }
147175
147916
  function readPushOnboarding(dir) {
147176
147917
  const path2 = join32(resolve36(dir), PUSH_ONBOARDING_PATH);
147177
- if (!existsSync37(path2)) return { version: 1 };
147918
+ if (!existsSync38(path2)) return { version: 1 };
147178
147919
  const parsed = readJson4(path2);
147179
147920
  return { version: 1, ...parsed };
147180
147921
  }
@@ -147209,7 +147950,7 @@ function recordPushDeferral(dir, d2) {
147209
147950
  }
147210
147951
  function clearPushDeferral(dir) {
147211
147952
  const path2 = join32(resolve36(dir), PUSH_ONBOARDING_PATH);
147212
- if (!existsSync37(path2)) return;
147953
+ if (!existsSync38(path2)) return;
147213
147954
  const { push: _dropped, ...rest } = readPushOnboarding(dir);
147214
147955
  writeFile(dir, { ...rest, version: 1 });
147215
147956
  }
@@ -147277,7 +148018,7 @@ var signing_inspect_exports = {};
147277
148018
  __export(signing_inspect_exports, {
147278
148019
  runSigningInspect: () => runSigningInspect
147279
148020
  });
147280
- import { existsSync as existsSync38, readFileSync as readFileSync43, statSync as statSync10 } from "node:fs";
148021
+ import { existsSync as existsSync39, readFileSync as readFileSync43, statSync as statSync10 } from "node:fs";
147281
148022
  import { isAbsolute as isAbsolute3, resolve as resolve37 } from "node:path";
147282
148023
  function fail4(io2, code, fields = {}) {
147283
148024
  io2.error(JSON.stringify({ ok: false, code, ...fields }));
@@ -147367,7 +148108,7 @@ async function runSigningInspect(pos, flags, io2, deps = {}) {
147367
148108
  } catch (error) {
147368
148109
  return fail4(io2, "signing_inspect_key_inside_repo", { error: error.message });
147369
148110
  }
147370
- if (!existsSync38(certPath) || !existsSync38(profilePath2)) {
148111
+ if (!existsSync39(certPath) || !existsSync39(profilePath2)) {
147371
148112
  return fail4(io2, "signing_inspect_local_assets_unreadable", { error: "cannot read --cert-file or --profile-file" });
147372
148113
  }
147373
148114
  if (statSync10(certPath).size > 1048576 || statSync10(profilePath2).size > 1048576) {
@@ -147901,7 +148642,7 @@ __export(template_trim_exports, {
147901
148642
  routeMatcher: () => routeMatcher,
147902
148643
  runTemplateTrim: () => runTemplateTrim
147903
148644
  });
147904
- import { cpSync, existsSync as existsSync39, mkdirSync as mkdirSync20, readdirSync as readdirSync21, readFileSync as readFileSync45, renameSync as renameSync8, rmSync as rmSync11, statSync as statSync11, writeFileSync as writeFileSync15 } from "node:fs";
148645
+ import { cpSync, existsSync as existsSync40, mkdirSync as mkdirSync20, readdirSync as readdirSync21, readFileSync as readFileSync45, renameSync as renameSync8, rmSync as rmSync11, statSync as statSync11, writeFileSync as writeFileSync15 } from "node:fs";
147905
148646
  import { dirname as dirname25, join as join34 } from "node:path";
147906
148647
  function routeMatcher(pattern) {
147907
148648
  const detail = /^\^([A-Za-z0-9_]+)\(\?:\[_\/\]\(\.\+\)\)\?\$$/.exec(pattern);
@@ -148646,7 +149387,7 @@ function homeModulesPass(app, kept, edited) {
148646
149387
  }
148647
149388
  function listWorkers(dir) {
148648
149389
  const root = join34(dir, "tier5-src");
148649
- if (!existsSync39(root)) return { dirs: [], files: {} };
149390
+ if (!existsSync40(root)) return { dirs: [], files: {} };
148650
149391
  const dirs = readdirSync21(root).filter((n2) => statSync11(join34(root, n2)).isDirectory()).sort();
148651
149392
  const files = {};
148652
149393
  const walk2 = (abs, rel) => {
@@ -148683,7 +149424,7 @@ async function runTemplateTrim(req, deps) {
148683
149424
  const dir = req.dir;
148684
149425
  const devPath = join34(dir, "dev/index.ts");
148685
149426
  const configPath = join34(dir, "config.ts");
148686
- if (!existsSync39(devPath) || !existsSync39(configPath)) {
149427
+ if (!existsSync40(devPath) || !existsSync40(configPath)) {
148687
149428
  return refuse3(new TrimRefusal(`${dir} has no dev/index.ts + config.ts \u2014 point --content at an app scaffolded with \`himi init --template\``));
148688
149429
  }
148689
149430
  if (isTemplateSourceTree(dir)) {
@@ -148730,7 +149471,7 @@ async function runTemplateTrim(req, deps) {
148730
149471
  }
148731
149472
  }
148732
149473
  if (req.dryRun) return { code: 0, result: { ok: true, dryRun: true, ...plan.report, validate: null } };
148733
- const hadHimi = existsSync39(join34(dir, ".himi"));
149474
+ const hadHimi = existsSync40(join34(dir, ".himi"));
148734
149475
  const backupRel = join34(".himi", "trim-backup", (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-"));
148735
149476
  const backup = join34(dir, backupRel);
148736
149477
  const originals = [[devPath, "dev/index.ts"], [configPath, "config.ts"], ...trimmedContent !== void 0 ? [[contentPath, "himalaya.content.json"]] : []];
@@ -148739,7 +149480,7 @@ async function runTemplateTrim(req, deps) {
148739
149480
  for (const [path2, rel] of originals) {
148740
149481
  if (rel === "himalaya.content.json") contentManifestPath(dir);
148741
149482
  const original = readFileSync45(join34(backup, rel));
148742
- if (!existsSync39(path2) || !readFileSync45(path2).equals(original)) {
149483
+ if (!existsSync40(path2) || !readFileSync45(path2).equals(original)) {
148743
149484
  if (rel === "himalaya.content.json") writeContentManifest(dir, original);
148744
149485
  else writeFileSync15(path2, original);
148745
149486
  }
@@ -149096,17 +149837,17 @@ __export(template_adopt_exports, {
149096
149837
  workerReach: () => workerReach,
149097
149838
  writeInventory: () => writeInventory
149098
149839
  });
149099
- import { existsSync as existsSync40, lstatSync as lstatSync11, mkdirSync as mkdirSync21, readdirSync as readdirSync22, readFileSync as readFileSync46, renameSync as renameSync9, statSync as statSync12, writeFileSync as writeFileSync16 } from "node:fs";
149840
+ import { existsSync as existsSync41, lstatSync as lstatSync11, mkdirSync as mkdirSync21, readdirSync as readdirSync22, readFileSync as readFileSync46, renameSync as renameSync9, statSync as statSync12, writeFileSync as writeFileSync16 } from "node:fs";
149100
149841
  import { dirname as dirname26, join as join35, posix as posix2 } from "node:path";
149101
149842
  function readAppSources(dir) {
149102
149843
  const devPath = join35(dir, "dev", "index.ts");
149103
149844
  const configPath = join35(dir, "config.ts");
149104
- if (!existsSync40(devPath) || !existsSync40(configPath)) {
149845
+ if (!existsSync41(devPath) || !existsSync41(configPath)) {
149105
149846
  throw new TrimRefusal(`no dev/index.ts + config.ts under ${dir} \u2014 run this in (or point --content at) an app \`himi init --template\` scaffolded`);
149106
149847
  }
149107
149848
  const workers = /* @__PURE__ */ new Map();
149108
149849
  const root = join35(dir, "tier5-src");
149109
- if (existsSync40(root)) {
149850
+ if (existsSync41(root)) {
149110
149851
  for (const name of readdirSync22(root).sort()) {
149111
149852
  const abs = join35(root, name);
149112
149853
  if (!statSync12(abs).isDirectory()) continue;
@@ -149346,7 +150087,7 @@ function inventoryOf(dir, src, app) {
149346
150087
  sampleCopy: copyHits(dir, SAMPLE_COPY, 50),
149347
150088
  matrix,
149348
150089
  journeys,
149349
- netMocks: existsSync40(join35(dir, "dev", "net-mocks.json"))
150090
+ netMocks: existsSync41(join35(dir, "dev", "net-mocks.json"))
149350
150091
  };
149351
150092
  }
149352
150093
  function matrixMarkdown(rows) {
@@ -149382,9 +150123,9 @@ function inventorySummary(inv) {
149382
150123
  function writeNoFollow(dir, rel, body) {
149383
150124
  const p2 = join35(dir, rel);
149384
150125
  const parent = dirname26(p2);
149385
- if (existsSync40(parent) && lstatSync11(parent).isSymbolicLink()) throw new TrimRefusal(`${dirname26(rel)} is a symlink \u2014 refusing to write through it`);
150126
+ if (existsSync41(parent) && lstatSync11(parent).isSymbolicLink()) throw new TrimRefusal(`${dirname26(rel)} is a symlink \u2014 refusing to write through it`);
149386
150127
  mkdirSync21(parent, { recursive: true });
149387
- if (existsSync40(p2) && lstatSync11(p2).isSymbolicLink()) throw new TrimRefusal(`${rel} is a symlink \u2014 refusing to write through it`);
150128
+ if (existsSync41(p2) && lstatSync11(p2).isSymbolicLink()) throw new TrimRefusal(`${rel} is a symlink \u2014 refusing to write through it`);
149388
150129
  const tmp = `${p2}.${process.pid}.${Date.now()}.tmp`;
149389
150130
  writeFileSync16(tmp, body, { flag: "wx" });
149390
150131
  renameSync9(tmp, p2);
@@ -149393,7 +150134,7 @@ function writeInventory(dir, inv, opts = {}) {
149393
150134
  const written = [];
149394
150135
  const keep = opts.companions === "if-missing";
149395
150136
  const put = (rel, body, companion) => {
149396
- if (companion && keep && existsSync40(join35(dir, rel))) return;
150137
+ if (companion && keep && existsSync41(join35(dir, rel))) return;
149397
150138
  writeNoFollow(dir, rel, body);
149398
150139
  written.push(rel);
149399
150140
  };
@@ -149499,7 +150240,7 @@ function addScreen(dir, id, entry, opts = {}) {
149499
150240
  }
149500
150241
  for (const rel of ["dev", "dev/index.ts", ...config !== src.config ? ["config.ts"] : [], ...contentWithView !== void 0 ? ["himalaya.content.json"] : []]) {
149501
150242
  const p2 = join35(dir, rel);
149502
- if (existsSync40(p2) && lstatSync11(p2).isSymbolicLink()) throw new TrimRefusal(`${rel} is a symlink \u2014 refusing to write through it (nothing written)`);
150243
+ if (existsSync41(p2) && lstatSync11(p2).isSymbolicLink()) throw new TrimRefusal(`${rel} is a symlink \u2014 refusing to write through it (nothing written)`);
149503
150244
  }
149504
150245
  writeNoFollow(dir, "dev/index.ts", dev);
149505
150246
  if (config !== src.config) writeNoFollow(dir, "config.ts", config);
@@ -149522,7 +150263,7 @@ function specScreens(spec) {
149522
150263
  return [...new Set(out2)];
149523
150264
  }
149524
150265
  function keepFromSpec(dir, specPath) {
149525
- if (!existsSync40(specPath)) throw new TrimRefusal(`no ${specPath} \u2014 --from-spec reads the approved plan's \`## Screen catalogue\``);
150266
+ if (!existsSync41(specPath)) throw new TrimRefusal(`no ${specPath} \u2014 --from-spec reads the approved plan's \`## Screen catalogue\``);
149526
150267
  const ids = specScreens(readFileSync46(specPath, "utf8"));
149527
150268
  if (!ids.length) {
149528
150269
  throw new TrimRefusal("SPEC.md's `## Screen catalogue` names no screen ids \u2014 put each screen's id (`himi template screens` lists them) in the first column, in backticks");
@@ -150275,7 +151016,7 @@ __export(pack_exports, {
150275
151016
  });
150276
151017
  import { createHash as createHash24 } from "node:crypto";
150277
151018
  import { deflateRawSync, inflateRawSync } from "node:zlib";
150278
- import { existsSync as existsSync41, mkdirSync as mkdirSync22, readFileSync as readFileSync48, readdirSync as readdirSync23, rmSync as rmSync12, statSync as statSync13, writeFileSync as writeFileSync17 } from "node:fs";
151019
+ import { existsSync as existsSync42, mkdirSync as mkdirSync22, readFileSync as readFileSync48, readdirSync as readdirSync23, rmSync as rmSync12, statSync as statSync13, writeFileSync as writeFileSync17 } from "node:fs";
150279
151020
  import { dirname as dirname27, join as join37, resolve as resolve39 } from "node:path";
150280
151021
  function writeZip(entries) {
150281
151022
  const sorted2 = entries.slice().sort((a2, b2) => a2.path < b2.path ? -1 : a2.path > b2.path ? 1 : 0);
@@ -150370,10 +151111,10 @@ function inflateEntry(buf, entry) {
150370
151111
  return bytes2;
150371
151112
  }
150372
151113
  function readIf(path2) {
150373
- return existsSync41(path2) && statSync13(path2).isFile() ? readFileSync48(path2) : null;
151114
+ return existsSync42(path2) && statSync13(path2).isFile() ? readFileSync48(path2) : null;
150374
151115
  }
150375
151116
  function listDir(dir) {
150376
- return existsSync41(dir) ? readdirSync23(dir).filter((f2) => statSync13(join37(dir, f2)).isFile()) : [];
151117
+ return existsSync42(dir) ? readdirSync23(dir).filter((f2) => statSync13(join37(dir, f2)).isFile()) : [];
150377
151118
  }
150378
151119
  function gatherReleaseEntries(appDir3) {
150379
151120
  const manifestPath = join37(appDir3, HIMI_PACKAGE_MANIFEST_PATH);
@@ -150452,7 +151193,7 @@ function packRelease(releaseRoot, app, out2, opts = {}) {
150452
151193
  const appDir3 = join37(resolve39(releaseRoot), app);
150453
151194
  const { all, header, skipped } = buildEntries(appDir3, app, opts);
150454
151195
  const buf = writeZip(all);
150455
- const isDir2 = existsSync41(out2) && statSync13(out2).isDirectory();
151196
+ const isDir2 = existsSync42(out2) && statSync13(out2).isDirectory();
150456
151197
  const outFile = isDir2 ? join37(resolve39(out2), packageFileName(app, header.releaseId)) : resolve39(out2);
150457
151198
  mkdirSync22(dirname27(outFile), { recursive: true });
150458
151199
  writeFileSync17(outFile, buf);
@@ -150469,11 +151210,11 @@ function resolvePackageDirDest(outDir, app, releaseId) {
150469
151210
  }
150470
151211
  };
150471
151212
  const replaceable = (dir) => {
150472
- if (!existsSync41(dir)) return true;
151213
+ if (!existsSync42(dir)) return true;
150473
151214
  if (!statSync13(dir).isDirectory()) return false;
150474
151215
  return readdirSync23(dir).length === 0 || packagedApp(dir) === app;
150475
151216
  };
150476
- if (existsSync41(outDir) && !statSync13(outDir).isDirectory()) {
151217
+ if (existsSync42(outDir) && !statSync13(outDir).isDirectory()) {
150477
151218
  throw new Error(`refusing to write a package tree over ${outDir} \u2014 it is a file, not a directory`);
150478
151219
  }
150479
151220
  if (replaceable(outDir)) return outDir;
@@ -150534,7 +151275,7 @@ function openPackageDir(dir) {
150534
151275
  else if (isSafeEntryName(childRel)) entries.set(childRel, readFileSync48(childAbs));
150535
151276
  }
150536
151277
  };
150537
- if (!existsSync41(root)) throw new Error(`no such package directory: ${root}`);
151278
+ if (!existsSync42(root)) throw new Error(`no such package directory: ${root}`);
150538
151279
  walk2("");
150539
151280
  const manifestBytes = entries.get(HIMI_PACKAGE_MANIFEST_PATH);
150540
151281
  if (manifestBytes) {
@@ -150619,7 +151360,7 @@ __export(app_source_exports, {
150619
151360
  zipAppSource: () => zipAppSource
150620
151361
  });
150621
151362
  import { createHash as createHash25 } from "node:crypto";
150622
- import { readdirSync as readdirSync24, lstatSync as lstatSync13, readFileSync as readFileSync49, mkdirSync as mkdirSync23, writeFileSync as writeFileSync18, existsSync as existsSync42, rmSync as rmSync13, rmdirSync as rmdirSync2, unlinkSync as unlinkSync3 } from "node:fs";
151363
+ import { readdirSync as readdirSync24, lstatSync as lstatSync13, readFileSync as readFileSync49, mkdirSync as mkdirSync23, writeFileSync as writeFileSync18, existsSync as existsSync43, rmSync as rmSync13, rmdirSync as rmdirSync2, unlinkSync as unlinkSync3 } from "node:fs";
150623
151364
  import { join as join38, resolve as resolve40, sep as sep13 } from "node:path";
150624
151365
  import { createRequire as createRequire3 } from "node:module";
150625
151366
  import { deflateRawSync as deflateRawSync2 } from "node:zlib";
@@ -150635,7 +151376,7 @@ function walkSourceTree(dir, file2, skip, enter = () => {
150635
151376
  continue;
150636
151377
  }
150637
151378
  if (st2.isDirectory()) {
150638
- if (isDeniedSourceDir(name, relDir) || existsSync42(join38(dir, rel, PACKAGE_DIR_MARKER))) skip(rel);
151379
+ if (isDeniedSourceDir(name, relDir) || existsSync43(join38(dir, rel, PACKAGE_DIR_MARKER))) skip(rel);
150639
151380
  else walk2(rel);
150640
151381
  continue;
150641
151382
  }
@@ -150803,7 +151544,7 @@ function writeAppSource(entries, destDir) {
150803
151544
  return written;
150804
151545
  }
150805
151546
  function staleSourcePaths(entries, destDir) {
150806
- if (!existsSync42(destDir)) return [];
151547
+ if (!existsSync43(destDir)) return [];
150807
151548
  const archived = new Set(entries.map((e2) => e2.path));
150808
151549
  const stale = [];
150809
151550
  walkSourceTree(destDir, (archivePath) => {
@@ -150859,7 +151600,7 @@ function removeStaleSource(entries, destDir) {
150859
151600
  const segments = entry.path.split("/");
150860
151601
  for (let i2 = 1; i2 < segments.length; i2++) needed.add(segments.slice(0, i2).join("/"));
150861
151602
  }
150862
- if (existsSync42(root)) pruneEmptyDirs(root, "", needed, removed);
151603
+ if (existsSync43(root)) pruneEmptyDirs(root, "", needed, removed);
150863
151604
  return removed.sort();
150864
151605
  }
150865
151606
  function pruneEmptyDirs(root, rel, needed, removed) {
@@ -150948,7 +151689,7 @@ __export(run_watch_exports, {
150948
151689
  watchedContentDir: () => watchedContentDir,
150949
151690
  writeRunRecord: () => writeRunRecord
150950
151691
  });
150951
- import { closeSync as closeSync4, constants as constants3, existsSync as existsSync43, fstatSync, lstatSync as lstatSync14, statSync as statSync14, readdirSync as readdirSync25, mkdirSync as mkdirSync24, openSync as openSync4, readFileSync as readFileSync50, realpathSync as realpathSync8, renameSync as renameSync10, rmSync as rmSync14, writeFileSync as writeFileSync19, watch as fsWatch } from "node:fs";
151692
+ import { closeSync as closeSync4, constants as constants3, existsSync as existsSync44, fstatSync, lstatSync as lstatSync14, statSync as statSync14, readdirSync as readdirSync25, mkdirSync as mkdirSync24, openSync as openSync4, readFileSync as readFileSync50, realpathSync as realpathSync8, renameSync as renameSync10, rmSync as rmSync14, writeFileSync as writeFileSync19, watch as fsWatch } from "node:fs";
150952
151693
  import { randomUUID as randomUUID7 } from "node:crypto";
150953
151694
  import { extname as extname4, join as join39, relative as relative8, resolve as resolve41, sep as sep14 } from "node:path";
150954
151695
  function diffReleases(prev, next) {
@@ -151016,7 +151757,7 @@ function watchContent(dir, onChange, opts = {}) {
151016
151757
  }, debounceMs);
151017
151758
  };
151018
151759
  let watcher2, polling;
151019
- const snapshot2 = () => {
151760
+ const snapshot3 = () => {
151020
151761
  const files = /* @__PURE__ */ new Map();
151021
151762
  const visit = (directory, prefix = "") => {
151022
151763
  let entries;
@@ -151039,12 +151780,12 @@ function watchContent(dir, onChange, opts = {}) {
151039
151780
  visit(dir);
151040
151781
  return files;
151041
151782
  };
151042
- let before = snapshot2();
151783
+ let before = snapshot3();
151043
151784
  const fallback = () => {
151044
151785
  if (polling) return;
151045
151786
  watcher2?.close();
151046
151787
  polling = setInterval(() => {
151047
- const after = snapshot2();
151788
+ const after = snapshot3();
151048
151789
  for (const path2 of /* @__PURE__ */ new Set([...before.keys(), ...after.keys()])) if (before.get(path2) !== after.get(path2)) changed("change", path2);
151049
151790
  before = after;
151050
151791
  }, opts.pollMs ?? 500);
@@ -151067,7 +151808,7 @@ function watchedContentDir(source) {
151067
151808
  if (!source || /^https?:\/\//i.test(source)) return null;
151068
151809
  const dir = resolve41(source);
151069
151810
  try {
151070
- return statSync14(dir).isDirectory() && existsSync43(join39(dir, "himalaya.content.json")) ? dir : null;
151811
+ return statSync14(dir).isDirectory() && existsSync44(join39(dir, "himalaya.content.json")) ? dir : null;
151071
151812
  } catch {
151072
151813
  return null;
151073
151814
  }
@@ -151723,7 +152464,7 @@ __export(milestones_exports, {
151723
152464
  });
151724
152465
  import { createHash as createHash28, randomUUID as randomUUID8 } from "node:crypto";
151725
152466
  import { spawn as spawn4 } from "node:child_process";
151726
- import { closeSync as closeSync5, existsSync as existsSync44, lstatSync as lstatSync17, readFileSync as readFileSync54, statSync as statSync15 } from "node:fs";
152467
+ import { closeSync as closeSync5, existsSync as existsSync45, lstatSync as lstatSync17, readFileSync as readFileSync54, statSync as statSync15 } from "node:fs";
151727
152468
  import { createServer as createServer3 } from "node:net";
151728
152469
  import { basename as basename14, dirname as dirname28, isAbsolute as isAbsolute4, join as join43, relative as relative9, resolve as resolve42, sep as sep15 } from "node:path";
151729
152470
  function homeShotPath(dir, home) {
@@ -151836,7 +152577,7 @@ function autoPictureGate(dir) {
151836
152577
  }
151837
152578
  async function homePictureAtValidate(dir, opts) {
151838
152579
  if (!opts.ok) return { skipped: "validate found errors, so the picture was left as it is" };
151839
- if (!existsSync44(join43(dir, "himalaya.content.json"))) return { skipped: "not a content package" };
152580
+ if (!existsSync45(join43(dir, "himalaya.content.json"))) return { skipped: "not a content package" };
151840
152581
  const env = opts.env ?? process.env;
151841
152582
  if (ciSet(env)) return { skipped: "the CI environment variable is set" };
151842
152583
  if (env.NODE_TEST_CONTEXT) return { skipped: "running under `node --test`" };
@@ -151906,7 +152647,7 @@ function stillBuilding(dir, image, now) {
151906
152647
  }
151907
152648
  }
151908
152649
  function firstLookBeforeOwnPostcard(dir, image, now) {
151909
- if (!image || !existsSync44(image) || initDivergence(dir).state !== "diverged") return void 0;
152650
+ if (!image || !existsSync45(image) || initDivergence(dir).state !== "diverged") return void 0;
151910
152651
  return journal(dir, "first-look", withHomeCaveat(yourFirstLookMessage(dir), homeCaveat(dir, image)), { image, ...now ? { now } : {} });
151911
152652
  }
151912
152653
  function afterRenderPng(dir, input) {
@@ -151971,13 +152712,13 @@ function testChangeNote(headline2, change) {
151971
152712
  }
151972
152713
  function afterTestRun(dir, input) {
151973
152714
  const firstLook = firstLookBeforeOwnPostcard(dir, input.homeShot, input.now);
151974
- const shot = input.homeShot && existsSync44(input.homeShot) ? input.homeShot : void 0;
152715
+ const shot = input.homeShot && existsSync45(input.homeShot) ? input.homeShot : void 0;
151975
152716
  const caveat = shot ? homeCaveat(dir, shot) : void 0;
151976
152717
  const counts = testPostcardMessage(input);
151977
152718
  const headline2 = caveat ? `${counts} But ${caveat}.` : counts;
151978
152719
  const postcard = journal(dir, "test", headline2, {
151979
152720
  ref: input.runId,
151980
- ...input.homeShot && existsSync44(input.homeShot) ? { image: input.homeShot } : {},
152721
+ ...input.homeShot && existsSync45(input.homeShot) ? { image: input.homeShot } : {},
151981
152722
  ...input.now ? { now: input.now } : {},
151982
152723
  unlessUnchanged: true,
151983
152724
  changeNote: (change) => testChangeNote(headline2, change)
@@ -152020,7 +152761,7 @@ function draftPictureGap(input) {
152020
152761
  if (!input.home) return { reason: "the app's dev/index.ts names no literal homeScreenId, so there is no home screen to picture" };
152021
152762
  if (!input.homeShot) return { reason: "the homeScreenId does not name a file under .himi/shots" };
152022
152763
  const render = `himi render ${shellQuote(input.home)} --png${contentArg(input.content)}`;
152023
- if (!existsSync44(input.homeShot)) return { reason: "there is no home shot yet", render };
152764
+ if (!existsSync45(input.homeShot)) return { reason: "there is no home shot yet", render };
152024
152765
  if (input.sourceChangedAtMs === void 0) return { reason: "the source's last change could not be read, so the home shot cannot be shown to be current", render };
152025
152766
  if (!shotIsCurrent(input.homeShot, input.sourceChangedAtMs)) return { reason: "the home shot is older than the last source edit, so it is not a picture of this draft", render };
152026
152767
  return null;
@@ -152098,7 +152839,7 @@ function draftChangeNote(dir, input) {
152098
152839
  if (!previous) return void 0;
152099
152840
  const shaOf = (i2) => i2 && typeof i2 === "object" && typeof i2.sha256 === "string" ? i2.sha256 : void 0;
152100
152841
  const had = Array.isArray(previous.images) ? previous.images.map(shaOf).find(Boolean) : void 0;
152101
- const has = input.picture && existsSync44(input.picture) ? sha256Of2(input.picture) : void 0;
152842
+ const has = input.picture && existsSync45(input.picture) ? sha256Of2(input.picture) : void 0;
152102
152843
  if (had && has) parts.push(had === has ? "the home screen looks the same" : "the home screen changed");
152103
152844
  else if (has) parts.push("a home picture this time");
152104
152845
  else return void 0;
@@ -152164,7 +152905,7 @@ function homeShotForPostcard(dir, opts = {}) {
152164
152905
  const shot = homeShotPath(dir, home);
152165
152906
  if (!shot) return { skipped: "the homeScreenId does not name a file under .himi/shots" };
152166
152907
  const render = `\`himi render ${shellQuote(home)} --png\``;
152167
- if (!existsSync44(shot)) return { skipped: `no home shot yet \u2014 ${render} makes one, and the next postcard carries it` };
152908
+ if (!existsSync45(shot)) return { skipped: `no home shot yet \u2014 ${render} makes one, and the next postcard carries it` };
152168
152909
  let changed;
152169
152910
  try {
152170
152911
  changed = newestSourceChangeMs(dir);
@@ -152244,7 +152985,7 @@ function liveWatchRunning(dir, isAlive = pidAlive, now) {
152244
152985
  }
152245
152986
  function watchReminder(dir, opts = {}) {
152246
152987
  try {
152247
- if (!existsSync44(join43(dir, "himalaya.content.json"))) return void 0;
152988
+ if (!existsSync45(join43(dir, "himalaya.content.json"))) return void 0;
152248
152989
  const nowDate = opts.now ?? /* @__PURE__ */ new Date();
152249
152990
  const live3 = liveWatch(dir, opts.isAlive, nowDate);
152250
152991
  const now = nowDate.getTime();
@@ -152919,12 +153660,12 @@ var init_brand_color_math = __esm({
152919
153660
  });
152920
153661
 
152921
153662
  // src/token-lint.ts
152922
- import { existsSync as existsSync47, readFileSync as readFileSync56 } from "node:fs";
153663
+ import { existsSync as existsSync48, readFileSync as readFileSync56 } from "node:fs";
152923
153664
  import { join as join46 } from "node:path";
152924
153665
  function configuredTokensPath(dir) {
152925
153666
  for (const name of ["config.ts", "config.js", "himi.config.ts"]) {
152926
153667
  const f2 = join46(dir, name);
152927
- if (!existsSync47(f2)) continue;
153668
+ if (!existsSync48(f2)) continue;
152928
153669
  const src = readFileSync56(f2, "utf8");
152929
153670
  const m2 = /designTokensPath\s*:\s*["'`]([^"'`]+)["'`]/.exec(src);
152930
153671
  if (m2) return { path: m2[1].replace(/^\.\//, "") };
@@ -153002,7 +153743,7 @@ function tokenColorIssues(dir, tokensPathOverride) {
153002
153743
  }
153003
153744
  const tokensPath = configured.path ?? "tokens.json";
153004
153745
  const p2 = join46(dir, tokensPath);
153005
- if (!existsSync47(p2)) {
153746
+ if (!existsSync48(p2)) {
153006
153747
  if (tokensPath !== "tokens.json") {
153007
153748
  warn3(`config designTokensPath points at ${tokensPath}, which does not exist -- colour tokens were not checked`);
153008
153749
  }
@@ -153324,7 +154065,7 @@ __export(fonts_exports, {
153324
154065
  listReport: () => listReport,
153325
154066
  resolveFamilyName: () => resolveFamilyName
153326
154067
  });
153327
- import { existsSync as existsSync48, readFileSync as readFileSync57 } from "node:fs";
154068
+ import { existsSync as existsSync49, readFileSync as readFileSync57 } from "node:fs";
153328
154069
  import { join as join47 } from "node:path";
153329
154070
  function readJson6(path2, fallback) {
153330
154071
  try {
@@ -153358,7 +154099,7 @@ function listReport(opts = {}) {
153358
154099
  }
153359
154100
  async function fontFindings(appDir3, opts = {}) {
153360
154101
  const tokensPath = join47(appDir3, configuredTokensPath(appDir3).path ?? "tokens.json");
153361
- if (!existsSync48(tokensPath)) return null;
154102
+ if (!existsSync49(tokensPath)) return null;
153362
154103
  const catalog4 = loadCatalog2();
153363
154104
  const tokens2 = readJson6(tokensPath, {});
153364
154105
  const policy = readJson6(join47(appDir3, "fonts.json"), {});
@@ -153866,17 +154607,17 @@ __export(template_recommend_exports, {
153866
154607
  recommendTemplates: () => recommendTemplates,
153867
154608
  verticalsFromBook: () => verticalsFromBook
153868
154609
  });
153869
- import { existsSync as existsSync50, readFileSync as readFileSync60 } from "node:fs";
154610
+ import { existsSync as existsSync51, readFileSync as readFileSync60 } from "node:fs";
153870
154611
  import { join as join50 } from "node:path";
153871
154612
  function verticalsFromBook(path2) {
153872
- const dir = existsSync50(join50(path2, "book.json")) || existsSync50(join50(path2, "provisioning.overlay.json")) ? path2 : join50(path2, ".himi", "business-book");
154613
+ const dir = existsSync51(join50(path2, "book.json")) || existsSync51(join50(path2, "provisioning.overlay.json")) ? path2 : join50(path2, ".himi", "business-book");
153873
154614
  const overlay = join50(dir, "provisioning.overlay.json");
153874
- if (existsSync50(overlay)) {
154615
+ if (existsSync51(overlay)) {
153875
154616
  const v2 = JSON.parse(readFileSync60(overlay, "utf8")).installedVerticals;
153876
154617
  if (Array.isArray(v2) && v2.length) return v2.filter((x2) => typeof x2 === "string");
153877
154618
  }
153878
154619
  const book = join50(dir, "book.json");
153879
- if (existsSync50(book)) {
154620
+ if (existsSync51(book)) {
153880
154621
  const probes = JSON.parse(readFileSync60(book, "utf8")).probes;
153881
154622
  if (Array.isArray(probes)) return installedFromProbes(probes);
153882
154623
  }
@@ -154491,7 +155232,7 @@ var init_glyphs = __esm({
154491
155232
  });
154492
155233
 
154493
155234
  // ../app-icons/plan.ts
154494
- import { existsSync as existsSync51, readFileSync as readFileSync61, readdirSync as readdirSync27 } from "node:fs";
155235
+ import { existsSync as existsSync52, readFileSync as readFileSync61, readdirSync as readdirSync27 } from "node:fs";
154495
155236
  import { createHash as createHash29 } from "node:crypto";
154496
155237
  import { dirname as dirname29, join as join51, resolve as resolve44 } from "node:path";
154497
155238
  function stripComments(src) {
@@ -154627,7 +155368,7 @@ function resolveTokensPath(app, configTs) {
154627
155368
  }
154628
155369
  function resolveToken(app, token, tokensPathOverride) {
154629
155370
  const tokensPath = tokensPathOverride ?? join51(appDir(app), "tokens.json");
154630
- if (!existsSync51(tokensPath)) {
155371
+ if (!existsSync52(tokensPath)) {
154631
155372
  throw new Error(`app-icons: ${app} has no tokens.json at ${tokensPath} (needed to resolve "${token}").`);
154632
155373
  }
154633
155374
  const tokens2 = JSON.parse(readFileSync61(tokensPath, "utf8"));
@@ -154672,7 +155413,7 @@ function iconSpec(app, configTs, id, tokensPathOverride) {
154672
155413
  const tokens2 = tokensPathOverride ?? resolveTokensPath(app, configTs).path;
154673
155414
  if (cfg.source) {
154674
155415
  const abs = resolve44(appDir(app), cfg.source);
154675
- if (!existsSync51(abs)) {
155416
+ if (!existsSync52(abs)) {
154676
155417
  throw new Error(`app-icons: ${app} declares icon.source "${cfg.source}" but ${abs} does not exist.`);
154677
155418
  }
154678
155419
  return {
@@ -154712,9 +155453,9 @@ function iosAssetCatalog2(app) {
154712
155453
  return assetCatalogIn(join51(appDir(app), "ios"));
154713
155454
  }
154714
155455
  function assetCatalogIn(platformDir) {
154715
- if (!existsSync51(platformDir)) return void 0;
155456
+ if (!existsSync52(platformDir)) return void 0;
154716
155457
  const children = readdirSync27(platformDir).filter((c2) => !c2.startsWith("build")).sort();
154717
- const catalogs = children.map((c2) => join51(platformDir, c2, "Assets.xcassets")).filter(existsSync51);
155458
+ const catalogs = children.map((c2) => join51(platformDir, c2, "Assets.xcassets")).filter(existsSync52);
154718
155459
  if (catalogs.length === 1) return catalogs[0];
154719
155460
  if (catalogs.length > 1) return void 0;
154720
155461
  const targets = [];
@@ -154737,14 +155478,14 @@ function androidResDir2(manifestPath) {
154737
155478
  }
154738
155479
  function androidManifestPath(app) {
154739
155480
  const androidDir = join51(appDir(app), "android");
154740
- if (!existsSync51(androidDir)) return void 0;
155481
+ if (!existsSync52(androidDir)) return void 0;
154741
155482
  const preferred = join51(androidDir, `${app}-app`, "src", "main", "AndroidManifest.xml");
154742
- if (existsSync51(preferred)) return preferred;
154743
- const candidates = readdirSync27(androidDir, { withFileTypes: true }).filter((d2) => d2.isDirectory() && d2.name.endsWith("-app")).map((d2) => join51(androidDir, d2.name, "src", "main", "AndroidManifest.xml")).filter(existsSync51);
155483
+ if (existsSync52(preferred)) return preferred;
155484
+ const candidates = readdirSync27(androidDir, { withFileTypes: true }).filter((d2) => d2.isDirectory() && d2.name.endsWith("-app")).map((d2) => join51(androidDir, d2.name, "src", "main", "AndroidManifest.xml")).filter(existsSync52);
154744
155485
  return candidates.length === 1 ? candidates[0] : void 0;
154745
155486
  }
154746
155487
  function androidOptedIn2(manifestPath) {
154747
- if (!manifestPath || !existsSync51(manifestPath)) return false;
155488
+ if (!manifestPath || !existsSync52(manifestPath)) return false;
154748
155489
  return readFileSync61(manifestPath, "utf8").includes("@mipmap/ic_launcher");
154749
155490
  }
154750
155491
  function templateIconSha256() {
@@ -154769,7 +155510,7 @@ function generationAllowed(app, configTs, opts = {}) {
154769
155510
  }
154770
155511
  const iosCat = iosAssetCatalog2(app);
154771
155512
  const iosIcon = iosCat ? join51(iosCat, "AppIcon.appiconset", "icon_1024.png") : void 0;
154772
- if (!iosIcon || !existsSync51(iosIcon)) return { allowed: true, reason: "no icon yet" };
155513
+ if (!iosIcon || !existsSync52(iosIcon)) return { allowed: true, reason: "no icon yet" };
154773
155514
  const hash2 = fileSha256(iosIcon);
154774
155515
  const placeholders = opts.placeholderHashes ?? placeholderHashes();
154775
155516
  if (app === "_template") return { allowed: true, reason: "the template itself" };
@@ -154793,7 +155534,7 @@ var init_plan2 = __esm({
154793
155534
  });
154794
155535
 
154795
155536
  // ../native-config/icon.ts
154796
- import { existsSync as existsSync52, readFileSync as readFileSync62 } from "node:fs";
155537
+ import { existsSync as existsSync53, readFileSync as readFileSync62 } from "node:fs";
154797
155538
  import { join as join52 } from "node:path";
154798
155539
  function androidAdaptiveIconXml() {
154799
155540
  return [
@@ -154822,7 +155563,7 @@ function androidIconArtifacts(app, configTs) {
154822
155563
  if (!generationAllowed(app, configTs).allowed) return [];
154823
155564
  const res = androidResDir2(manifest2);
154824
155565
  const foreground = join52(res, "mipmap-mdpi", "ic_launcher_foreground.png");
154825
- if (!existsSync52(foreground)) {
155566
+ if (!existsSync53(foreground)) {
154826
155567
  throw new Error(
154827
155568
  `native-config icon: ${app} opts into @mipmap/ic_launcher but has no mipmap-*/ic_launcher_foreground.png. Run \`npm run app-icons -- ${app}\` first \u2014 the XML emitted here points at those rasters.`
154828
155569
  );
@@ -155124,7 +155865,7 @@ var init_localweb = __esm({
155124
155865
  });
155125
155866
 
155126
155867
  // ../native-config/capability-registrations.ts
155127
- import { existsSync as existsSync53, readdirSync as readdirSync28, readFileSync as readFileSync63, statSync as statSync16 } from "node:fs";
155868
+ import { existsSync as existsSync54, readdirSync as readdirSync28, readFileSync as readFileSync63, statSync as statSync16 } from "node:fs";
155128
155869
  import { dirname as dirname30, join as join53, resolve as resolve45 } from "node:path";
155129
155870
  import { fileURLToPath as fileURLToPath22 } from "node:url";
155130
155871
  function registrarClasses(path2, re2) {
@@ -155168,7 +155909,7 @@ function renderKotlinRegistrations(ids, appIdExpr = "APP_NAME", classes = androi
155168
155909
  ];
155169
155910
  }
155170
155911
  function filesWithRegisterMarkers(root, ext) {
155171
- if (!existsSync53(root)) return [];
155912
+ if (!existsSync54(root)) return [];
155172
155913
  const out2 = [];
155173
155914
  const stack = [[root, 0, ext === ".kt" ? "project" : "main"]];
155174
155915
  while (stack.length) {
@@ -155360,7 +156101,7 @@ __export(gen_native_config_exports, {
155360
156101
  xmlAttr: () => xmlAttr,
155361
156102
  yamlScalar: () => yamlScalar
155362
156103
  });
155363
- import { existsSync as existsSync54, mkdirSync as mkdirSync25, readFileSync as readFileSync64, readdirSync as readdirSync29, rmSync as rmSync15, statSync as statSync17, writeFileSync as writeFileSync21 } from "node:fs";
156104
+ import { existsSync as existsSync55, mkdirSync as mkdirSync25, readFileSync as readFileSync64, readdirSync as readdirSync29, rmSync as rmSync15, statSync as statSync17, writeFileSync as writeFileSync21 } from "node:fs";
155364
156105
  import { dirname as dirname31, join as join54 } from "node:path";
155365
156106
  import { fileURLToPath as fileURLToPath23 } from "node:url";
155366
156107
  function parseStringArray(configTs, field) {
@@ -155438,7 +156179,7 @@ function buildSet(capabilities, envelope = []) {
155438
156179
  }
155439
156180
  function loadOverrides(app) {
155440
156181
  const p2 = join54(appDir(app), "native-config.overrides.json");
155441
- if (!existsSync54(p2)) return {};
156182
+ if (!existsSync55(p2)) return {};
155442
156183
  return JSON.parse(readFileSync64(p2, "utf8"));
155443
156184
  }
155444
156185
  function needsQuote(s2) {
@@ -155665,7 +156406,7 @@ function genCoreModuleInstallers(check) {
155665
156406
  }
155666
156407
  function swiftFilesWithModuleMarkers(app) {
155667
156408
  const root = join54(appDir(app), "ios");
155668
- if (!existsSync54(root)) return [];
156409
+ if (!existsSync55(root)) return [];
155669
156410
  const out2 = [];
155670
156411
  const stack = [root];
155671
156412
  while (stack.length) {
@@ -155687,7 +156428,7 @@ function kotlinFilesWithModuleInstall(app) {
155687
156428
  return kotlinBootSourcesUnder(join54(appDir(app), "android"));
155688
156429
  }
155689
156430
  function kotlinBootSourcesUnder(root) {
155690
- if (!existsSync54(root)) return [];
156431
+ if (!existsSync55(root)) return [];
155691
156432
  const out2 = [];
155692
156433
  const stack = [[root, 0, "project"]];
155693
156434
  while (stack.length) {
@@ -155758,7 +156499,7 @@ function endText(kind, label3, indent) {
155758
156499
  }
155759
156500
  function hostAppliesDeferredWidgetActions(app) {
155760
156501
  const root = join54(appDir(app), "ios");
155761
- if (!existsSync54(root)) return false;
156502
+ if (!existsSync55(root)) return false;
155762
156503
  const stack = [root];
155763
156504
  while (stack.length) {
155764
156505
  const dir = stack.pop();
@@ -155816,15 +156557,15 @@ function androidAppGradle(app) {
155816
156557
  function androidManifestPath2(app) {
155817
156558
  const androidDir = join54(appDir(app), "android");
155818
156559
  const preferred = join54(androidDir, `${app}-app`, "src", "main", "AndroidManifest.xml");
155819
- if (existsSync54(preferred)) return preferred;
155820
- const candidates = existsSync54(androidDir) ? readdirSync29(androidDir, { withFileTypes: true }).filter((d2) => d2.isDirectory() && d2.name.endsWith("-app")).map((d2) => join54(androidDir, d2.name, "src", "main", "AndroidManifest.xml")).filter(existsSync54) : [];
156560
+ if (existsSync55(preferred)) return preferred;
156561
+ const candidates = existsSync55(androidDir) ? readdirSync29(androidDir, { withFileTypes: true }).filter((d2) => d2.isDirectory() && d2.name.endsWith("-app")).map((d2) => join54(androidDir, d2.name, "src", "main", "AndroidManifest.xml")).filter(existsSync55) : [];
155821
156562
  return candidates.length === 1 ? candidates[0] : preferred;
155822
156563
  }
155823
156564
  function automotiveAppDescPath(app) {
155824
156565
  return join54(dirname31(androidManifestPath2(app)), "res", "xml", "automotive_app_desc.xml");
155825
156566
  }
155826
156567
  function applyToFile(path2, kind, label3, render, check) {
155827
- if (!existsSync54(path2)) return { path: path2, outcome: "skipped" };
156568
+ if (!existsSync55(path2)) return { path: path2, outcome: "skipped" };
155828
156569
  const before = readFileSync64(path2, "utf8");
155829
156570
  assertSingleMarkerPair(before, kind, label3, path2);
155830
156571
  if (!hasMarkers(before, kind, label3)) return { path: path2, outcome: "skipped" };
@@ -155836,7 +156577,7 @@ function applyToFile(path2, kind, label3, render, check) {
155836
156577
  }
155837
156578
  function assertModuleFlagsMarkers(paths2) {
155838
156579
  for (const path2 of paths2) {
155839
- if (!existsSync54(path2)) continue;
156580
+ if (!existsSync55(path2)) continue;
155840
156581
  const text11 = readFileSync64(path2, "utf8");
155841
156582
  if (hasMarkers(text11, "yaml", LABEL_MODULES_IOS_LINK) && !hasMarkers(text11, "yaml", LABEL_MODULES_IOS_FLAGS)) {
155842
156583
  throw new Error(`${path2} links modules (${LABEL_MODULES_IOS_LINK}) but has no ${LABEL_MODULES_IOS_FLAGS} block under its project-level settings:, so no module would install. Add the markers (see apps/_template).`);
@@ -155848,7 +156589,7 @@ function applyModuleFlags(path2, products, check) {
155848
156589
  return applyToFile(path2, "yaml", LABEL_MODULES_IOS_FLAGS, (i2) => renderModulesIosFlags(products, i2), check);
155849
156590
  }
155850
156591
  function applyWholeFile(path2, content, check) {
155851
- const current = existsSync54(path2) ? readFileSync64(path2, "utf8") : null;
156592
+ const current = existsSync55(path2) ? readFileSync64(path2, "utf8") : null;
155852
156593
  if (current === content) return { path: path2, outcome: "unchanged" };
155853
156594
  if (check) return { path: path2, outcome: "drift" };
155854
156595
  mkdirSync25(dirname31(path2), { recursive: true });
@@ -155856,7 +156597,7 @@ function applyWholeFile(path2, content, check) {
155856
156597
  return { path: path2, outcome: "written" };
155857
156598
  }
155858
156599
  function removeWholeFile(path2, check) {
155859
- if (!existsSync54(path2)) return { path: path2, outcome: "skipped" };
156600
+ if (!existsSync55(path2)) return { path: path2, outcome: "skipped" };
155860
156601
  if (check) return { path: path2, outcome: "drift" };
155861
156602
  rmSync15(path2);
155862
156603
  return { path: path2, outcome: "removed" };
@@ -155895,7 +156636,7 @@ function genCapabilityRegistrations(root, declared, check) {
155895
156636
  }
155896
156637
  function buildSetOfAppDir(root) {
155897
156638
  const configPath = join54(root, "config.ts");
155898
- const configTs = existsSync54(configPath) ? readFileSync64(configPath, "utf8") : "";
156639
+ const configTs = existsSync55(configPath) ? readFileSync64(configPath, "utf8") : "";
155899
156640
  return buildSet(parseStringArray(configTs, "capabilities"), parseStringArray(configTs, "capabilityEnvelope"));
155900
156641
  }
155901
156642
  function genNativeConfig(app, opts = {}) {
@@ -155904,7 +156645,7 @@ function genNativeConfig(app, opts = {}) {
155904
156645
  assertSingleModuleInstall(app, kotlinFilesWithModuleInstall(app));
155905
156646
  assertModuleFlagsMarkers([iosProjectYml(app), macosProjectYml(app)]);
155906
156647
  const configPath = appConfigTs(app);
155907
- const configTs = existsSync54(configPath) ? readFileSync64(configPath, "utf8") : "";
156648
+ const configTs = existsSync55(configPath) ? readFileSync64(configPath, "utf8") : "";
155908
156649
  const capabilities = parseStringArray(configTs, "capabilities");
155909
156650
  const envelope = parseStringArray(configTs, "capabilityEnvelope");
155910
156651
  const ownIds = buildSet(capabilities, envelope);
@@ -155913,7 +156654,7 @@ function genNativeConfig(app, opts = {}) {
155913
156654
  const ids = dist ? dist.build : ownIds;
155914
156655
  const healthLinked = ids.includes("health");
155915
156656
  const distJsonPath = join54(appDir(app), "distribution.json");
155916
- const distJsonText = existsSync54(distJsonPath) ? readFileSync64(distJsonPath, "utf8") : void 0;
156657
+ const distJsonText = existsSync55(distJsonPath) ? readFileSync64(distJsonPath, "utf8") : void 0;
155917
156658
  const optIns = distributionOptIns(distJsonText);
155918
156659
  const binaryCore = isBinaryCore(configTs, distJsonText);
155919
156660
  const modules = modulesFor(ids, optIns);
@@ -155929,7 +156670,7 @@ function genNativeConfig(app, opts = {}) {
155929
156670
  if (!v2) throw new Error(`${app}: a binary-core app that links native modules (${modules.gradle.join(", ")}) needs distribution.json coreVersion`);
155930
156671
  return v2;
155931
156672
  },
155932
- corePackage: () => existsSync54(iosProjectYml(app)) ? binaryCorePackage(readFileSync64(iosProjectYml(app), "utf8")) : void 0
156673
+ corePackage: () => existsSync55(iosProjectYml(app)) ? binaryCorePackage(readFileSync64(iosProjectYml(app), "utf8")) : void 0
155933
156674
  } : void 0
155934
156675
  );
155935
156676
  if (binaryCore) {
@@ -155948,9 +156689,9 @@ function genNativeConfig(app, opts = {}) {
155948
156689
  const iosBundleId = watchConfig.iosBundleId ?? parseIosBundleId(configTs);
155949
156690
  const watch2 = watchInfoPlan(watchConfig, iosBundleId);
155950
156691
  const watchYml = watchosProjectYml(app);
155951
- const watchYmlText = existsSync54(watchYml) ? readFileSync64(watchYml, "utf8") : "";
156692
+ const watchYmlText = existsSync55(watchYml) ? readFileSync64(watchYml, "utf8") : "";
155952
156693
  const watchSettings = watchSettingsPlan(watchMode(watchConfig.mode), iosBundleId, watchTargetBundleId(watchYmlText));
155953
- const watchName = existsSync54(watchYml) ? watchProjectName(readFileSync64(watchYml, "utf8")) : void 0;
156694
+ const watchName = existsSync55(watchYml) ? watchProjectName(readFileSync64(watchYml, "utf8")) : void 0;
155954
156695
  const watchEmbedFor = (lines) => (indent) => {
155955
156696
  const mode = watchMode(watchConfig.mode);
155956
156697
  if (mode === "standalone") return [];
@@ -155964,7 +156705,7 @@ function genNativeConfig(app, opts = {}) {
155964
156705
  const carBlock = applyToFile(carManifestPath, "xml", LABEL_CAR, (i2) => renderCarManifestXml(carCategory, i2), check);
155965
156706
  assertCarBlockLanded(app, carCategory, carManifestPath, carBlock.outcome, LABEL_CAR);
155966
156707
  const iosYml = iosProjectYml(app);
155967
- const project = existsSync54(iosYml) ? readFileSync64(iosYml, "utf8") : "";
156708
+ const project = existsSync55(iosYml) ? readFileSync64(iosYml, "utf8") : "";
155968
156709
  const targetManaged = hasMarkers(project, "yaml", LABEL_LIVE_TARGET);
155969
156710
  const embedManaged = hasMarkers(project, "yaml", LABEL_LIVE_EMBED);
155970
156711
  if (targetManaged !== embedManaged) throw new Error(`${app}: Live Activity target and embedding markers must be installed together`);
@@ -156048,7 +156789,7 @@ function genNativeConfig(app, opts = {}) {
156048
156789
  ];
156049
156790
  if (dist) {
156050
156791
  const manifestPath = androidManifestPath2(app);
156051
- const marked = (path2, kind, label3) => !existsSync54(path2) || hasMarkers(readFileSync64(path2, "utf8"), kind, label3);
156792
+ const marked = (path2, kind, label3) => !existsSync55(path2) || hasMarkers(readFileSync64(path2, "utf8"), kind, label3);
156052
156793
  if (!marked(iosYml, "yaml", LABEL_IOS_INFO)) throw new Error(`${app}: dist capabilities need the ${LABEL_IOS_INFO} markers in ${iosYml}`);
156053
156794
  if (!marked(manifestPath, "xml", LABEL_ANDROID_SERVICES)) {
156054
156795
  throw new Error(`${app}: dist capabilities need the ${LABEL_ANDROID_SERVICES} markers inside <application> in ${manifestPath}`);
@@ -156059,7 +156800,7 @@ function genNativeConfig(app, opts = {}) {
156059
156800
  const addsGradle = added.gradle.some((p2) => !ownModules.gradle.includes(p2));
156060
156801
  if (addsSpm || addsGradle) {
156061
156802
  const requireMarkers = (path2, kind, label3) => {
156062
- if (!existsSync54(path2) || !hasMarkers(readFileSync64(path2, "utf8"), kind, label3)) {
156803
+ if (!existsSync55(path2) || !hasMarkers(readFileSync64(path2, "utf8"), kind, label3)) {
156063
156804
  throw new Error(`${app}: dist added ${dist.added.join(", ")} but ${path2} has no ${label3} markers \u2014 the module would stay unlinked and every verb would answer module_not_linked`);
156064
156805
  }
156065
156806
  };
@@ -156084,9 +156825,9 @@ function genNativeConfig(app, opts = {}) {
156084
156825
  files.push(...genCapabilityRegistrations(appDir(app), ids, check));
156085
156826
  const rce = declaresRichContentEditor(configTs);
156086
156827
  for (const yml of [iosYml, macosProjectYml(app)]) {
156087
- const text11 = existsSync54(yml) ? readFileSync64(yml, "utf8") : "";
156828
+ const text11 = existsSync55(yml) ? readFileSync64(yml, "utf8") : "";
156088
156829
  const r3 = applyToFile(yml, "yaml", LABEL_LOCALWEB, renderLocalWebYaml(resourcesDirOf(text11), rce), check);
156089
- if (existsSync54(yml)) assertLocalWebBlockLanded(app, rce, yml, r3.outcome);
156830
+ if (existsSync55(yml)) assertLocalWebBlockLanded(app, rce, yml, r3.outcome);
156090
156831
  files.push(r3);
156091
156832
  }
156092
156833
  if (targetManaged) {
@@ -156098,7 +156839,7 @@ function genNativeConfig(app, opts = {}) {
156098
156839
  const entitlements = join54(dirname31(iosYml), LIVE_ENTITLEMENTS_PATH);
156099
156840
  files.push(plan.entitlements ? applyWholeFile(entitlements, plan.entitlements, check) : removeWholeFile(entitlements, check));
156100
156841
  }
156101
- const iosSplashManaged = existsSync54(iosYml) && hasMarkers(readFileSync64(iosYml, "utf8"), "yaml", LABEL_IOS_SPLASH);
156842
+ const iosSplashManaged = existsSync55(iosYml) && hasMarkers(readFileSync64(iosYml, "utf8"), "yaml", LABEL_IOS_SPLASH);
156102
156843
  const manifest2 = androidManifestPath2(app);
156103
156844
  const splash = splashPlan(app, configTs, manifest2, iosSplashManaged);
156104
156845
  for (const artifact of splash.artifacts) files.push(applyWholeFile(artifact.path, artifact.content, check));
@@ -156191,7 +156932,7 @@ __export(capabilities_exports, {
156191
156932
  shellSupport: () => shellSupport,
156192
156933
  writeLastDist: () => writeLastDist
156193
156934
  });
156194
- import { existsSync as existsSync55, lstatSync as lstatSync18, readFileSync as readFileSync65 } from "node:fs";
156935
+ import { existsSync as existsSync56, lstatSync as lstatSync18, readFileSync as readFileSync65 } from "node:fs";
156195
156936
  import { join as join55 } from "node:path";
156196
156937
  function declareHintFor(id) {
156197
156938
  return catalogKey(id) === "app_services" ? "each calling screen's `logicBundle.declaredCapabilities` (the runtime gate) \u2014 an app need not list app_services in config.ts `capabilities`, which only a shell that hosts app services must (an HHP app declares it there, since HHP copies that list onto every screen)" : DECLARE_HINT;
@@ -156273,7 +157014,7 @@ function allCapabilities(sdkRef = []) {
156273
157014
  function contentShell(dir, flag) {
156274
157015
  if (flag) return flag;
156275
157016
  const path2 = join55(dir, "himalaya.content.json");
156276
- if (!existsSync55(path2)) return null;
157017
+ if (!existsSync56(path2)) return null;
156277
157018
  try {
156278
157019
  const shell = JSON.parse(readFileSync65(path2, "utf8")).shell;
156279
157020
  return typeof shell === "string" && shell ? shell : null;
@@ -156571,7 +157312,7 @@ function envelopeSubsetIssues(app, envelope) {
156571
157312
  function capabilityConfigFindings(sourceDir, builtDir) {
156572
157313
  const out2 = [];
156573
157314
  const configPath = join55(sourceDir, "config.ts");
156574
- if (existsSync55(configPath)) {
157315
+ if (existsSync56(configPath)) {
156575
157316
  const configSrc = readFileSync65(configPath, "utf8");
156576
157317
  const declared = parseStringArray(configSrc, "capabilities");
156577
157318
  for (const id of new Set(declared)) {
@@ -156740,6 +157481,9 @@ async function navIssues(dir, strict) {
156740
157481
  pushScreenMapIssues(cfg.push, provisioning, warn3);
156741
157482
  pushAuthIssues(cfg.push, cfg.auth, provisioning, warn3);
156742
157483
  pushFamilyIssues(cfg.push, warn3);
157484
+ const captcha = provisioning.siteId && !placeholderLogin(cfg.auth) ? captchaAuthFinding(cfg.auth, provisioning.siteId) : void 0;
157485
+ if (captcha && captcha.code !== "captcha_auth_site_case" && !issues.some((i2) => i2.ruleCode === "push-auth-site"))
157486
+ push("warning", "auth-captcha-site", captcha.message);
156743
157487
  if (nav === void 0 || nav === null) return issues;
156744
157488
  if (!isPlainObject2(nav)) {
156745
157489
  error("nav-not-an-object", `navigation must be an object (got ${Array.isArray(nav) ? "array" : typeof nav}).`);
@@ -156877,6 +157621,9 @@ function pushAuthIssues(push, auth, provisioning, warn3) {
156877
157621
  `push.registrar is "wix-ping", which registers a signed-in member's device with Wix Ping, but ${problem}. Use auth: WixConsumerAuthProvider({ siteId: "${provisioning.siteId ?? "<metaSiteId>"}", \u2026 }).`
156878
157622
  );
156879
157623
  }
157624
+ function placeholderLogin(auth) {
157625
+ return isPlainObject2(auth) && isPlainObject2(auth.config) && auth.config.clientId === PLACEHOLDER_CLIENT_ID;
157626
+ }
156880
157627
  function pushFamilyIssues(push, warn3) {
156881
157628
  if (!isPlainObject2(push) || push.registrar !== "wix-ping" || typeof push.pingAppName !== "string") return;
156882
157629
  const replacement = replacementPingFamily(push.pingAppName);
@@ -156939,6 +157686,8 @@ var init_nav_lint = __esm({
156939
157686
  init_nav_slots();
156940
157687
  init_home_screen_id();
156941
157688
  init_wix_push_links();
157689
+ init_captcha_auth();
157690
+ init_wix_placeholders();
156942
157691
  NAVIGATION_KEYS = /* @__PURE__ */ new Set([
156943
157692
  "tabBar",
156944
157693
  "drawer",
@@ -157019,7 +157768,7 @@ __export(base44_types_exports, {
157019
157768
  renderBase44Types: () => renderBase44Types,
157020
157769
  writeBase44Types: () => writeBase44Types
157021
157770
  });
157022
- import { existsSync as existsSync56, mkdirSync as mkdirSync26, readFileSync as readFileSync66, writeFileSync as writeFileSync22 } from "node:fs";
157771
+ import { existsSync as existsSync57, mkdirSync as mkdirSync26, readFileSync as readFileSync66, writeFileSync as writeFileSync22 } from "node:fs";
157023
157772
  import { dirname as dirname32, join as join56 } from "node:path";
157024
157773
  function logicalName(spec) {
157025
157774
  return (isAdoptedEntity(spec) ? spec.base44Name : spec.name) ?? "";
@@ -157099,7 +157848,7 @@ async function writeBase44Types(dir, app) {
157099
157848
  if (!list2?.length) throw new Base44TypesError("no_base44_entities", "config.ts declares no base44.entities \u2014 nothing to type. Declare them (or run `himi base44 adopt`) first.");
157100
157849
  const text11 = renderBase44Types(list2, app);
157101
157850
  const path2 = join56(dir, BASE44_TYPES_PATH);
157102
- const changed = !existsSync56(path2) || readFileSync66(path2, "utf8") !== text11;
157851
+ const changed = !existsSync57(path2) || readFileSync66(path2, "utf8") !== text11;
157103
157852
  if (changed) {
157104
157853
  mkdirSync26(dirname32(path2), { recursive: true });
157105
157854
  writeFileSync22(path2, text11);
@@ -157108,7 +157857,7 @@ async function writeBase44Types(dir, app) {
157108
157857
  }
157109
157858
  async function base44TypesIssues(dir, app, strict) {
157110
157859
  const path2 = join56(dir, BASE44_TYPES_PATH);
157111
- if (!existsSync56(path2)) return [];
157860
+ if (!existsSync57(path2)) return [];
157112
157861
  let list2;
157113
157862
  try {
157114
157863
  list2 = await declaredEntities(dir);
@@ -157251,13 +158000,13 @@ __export(eject_exports, {
157251
158000
  EJECTABLE: () => EJECTABLE,
157252
158001
  ejectModule: () => ejectModule
157253
158002
  });
157254
- import { existsSync as existsSync58, mkdirSync as mkdirSync27, readFileSync as readFileSync68, writeFileSync as writeFileSync23 } from "node:fs";
158003
+ import { existsSync as existsSync59, mkdirSync as mkdirSync27, readFileSync as readFileSync68, writeFileSync as writeFileSync23 } from "node:fs";
157255
158004
  import { dirname as dirname33, join as join58, relative as relative10, resolve as resolve47, sep as sep16 } from "node:path";
157256
158005
  function locate(repoRootOrCwd, mod) {
157257
158006
  const inRepo = resolve47(repoRootOrCwd, `stdlib/flows/${mod}/src/index.ts`);
157258
- if (existsSync58(inRepo)) return { path: inRepo, form: "source" };
158007
+ if (existsSync59(inRepo)) return { path: inRepo, form: "source" };
157259
158008
  const dist = resolve47(repoRootOrCwd, `node_modules/@wix/himalaya/dist/${mod}.mjs`);
157260
- if (existsSync58(dist)) return { path: dist, form: "bundle" };
158009
+ if (existsSync59(dist)) return { path: dist, form: "bundle" };
157261
158010
  return null;
157262
158011
  }
157263
158012
  function specifiersFor(mod) {
@@ -157302,7 +158051,7 @@ function ejectModule(opts) {
157302
158051
  writeFileSync23(target, banner + normalized);
157303
158052
  const rewired = [];
157304
158053
  for (const f2 of files) {
157305
- if (!existsSync58(f2)) continue;
158054
+ if (!existsSync59(f2)) continue;
157306
158055
  const before = readFileSync68(f2, "utf8");
157307
158056
  let after = before;
157308
158057
  let rel = relative10(dirname33(f2), target).split(sep16).join("/").replace(/\.tsx?$/, ".js");
@@ -157481,7 +158230,7 @@ __export(icon_exports, {
157481
158230
  summarize: () => summarize3
157482
158231
  });
157483
158232
  import { createHash as createHash31 } from "node:crypto";
157484
- import { existsSync as existsSync59, mkdirSync as mkdirSync28, readFileSync as readFileSync69, statSync as statSync18, writeFileSync as writeFileSync24 } from "node:fs";
158233
+ import { existsSync as existsSync60, mkdirSync as mkdirSync28, readFileSync as readFileSync69, statSync as statSync18, writeFileSync as writeFileSync24 } from "node:fs";
157485
158234
  import { basename as basename16, dirname as dirname34, join as join59, resolve as resolve48, sep as sep17 } from "node:path";
157486
158235
  function readManifest(dir) {
157487
158236
  try {
@@ -157520,7 +158269,7 @@ function templateIconMatch(png) {
157520
158269
  }
157521
158270
  function playState(dir) {
157522
158271
  const p2 = join59(resolve48(dir), PLAY_LISTING_ICON);
157523
- if (!existsSync59(p2)) return null;
158272
+ if (!existsSync60(p2)) return null;
157524
158273
  try {
157525
158274
  if (!statSync18(p2).isFile()) return { path: p2, issues: ["is a directory, not a PNG file"] };
157526
158275
  return { path: p2, issues: playListingIconIssues(readFileSync69(p2)) };
@@ -157546,7 +158295,7 @@ async function iconStatus(dir) {
157546
158295
  verdict: "missing",
157547
158296
  policyChecklist: POLICY_CHECKLIST
157548
158297
  };
157549
- if (!path2 || !existsSync59(path2)) return base;
158298
+ if (!path2 || !existsSync60(path2)) return base;
157550
158299
  let png;
157551
158300
  try {
157552
158301
  if (!statSync18(path2).isFile()) {
@@ -157636,7 +158385,7 @@ function backdropFromTokens(dir, fallback = "#1F2933") {
157636
158385
  }
157637
158386
  async function installIcon(dir, sourcePath, opts = {}) {
157638
158387
  const src = resolve48(sourcePath);
157639
- if (!existsSync59(src)) throw new Error(`himi icon: no such file: ${src}`);
158388
+ if (!existsSync60(src)) throw new Error(`himi icon: no such file: ${src}`);
157640
158389
  const name = declaredIconName(dir) ?? DEFAULT_CONTENT_ICON;
157641
158390
  const dest = iconDest(dir, name);
157642
158391
  const wrote = [];
@@ -157690,11 +158439,11 @@ function declareIcon(dir, name) {
157690
158439
  }
157691
158440
  function siteBookIcon(bookDir) {
157692
158441
  const p2 = join59(resolve48(bookDir), SITE_BOOK_ICON_REL);
157693
- return existsSync59(p2) ? p2 : null;
158442
+ return existsSync60(p2) ? p2 : null;
157694
158443
  }
157695
158444
  function siteLogoAbsence(bookDir) {
157696
158445
  const bookJson = join59(resolve48(bookDir), "book.json");
157697
- if (!existsSync59(bookJson)) {
158446
+ if (!existsSync60(bookJson)) {
157698
158447
  return { reason: "no-book", hint: `no business book at ${bookDir} \u2014 run \`himi site analyze --out <dir>\` first, or pass --book <dir>` };
157699
158448
  }
157700
158449
  let logoUrl;
@@ -157978,7 +158727,7 @@ var init_crawl_layers = __esm({
157978
158727
  });
157979
158728
 
157980
158729
  // src/wix-writes.ts
157981
- import { existsSync as existsSync61, readFileSync as readFileSync71 } from "node:fs";
158730
+ import { existsSync as existsSync62, readFileSync as readFileSync71 } from "node:fs";
157982
158731
  import { join as join62 } from "node:path";
157983
158732
  function isProvenRead(method, path2) {
157984
158733
  if (/[#\x00-\x1F\x7F]/.test(path2)) return false;
@@ -158098,7 +158847,7 @@ function parseDataAccess(text11, from) {
158098
158847
  function readDataAccess(dir) {
158099
158848
  for (const name of ["SPEC.md", "MOBILE-UX.md"]) {
158100
158849
  const p2 = join62(dir, name);
158101
- if (!existsSync61(p2)) continue;
158850
+ if (!existsSync62(p2)) continue;
158102
158851
  let text11;
158103
158852
  try {
158104
158853
  text11 = readFileSync71(p2, "utf8");
@@ -158217,11 +158966,11 @@ __export(test_exports, {
158217
158966
  scopeDescriptors: () => scopeDescriptors,
158218
158967
  writeRecordedMocks: () => writeRecordedMocks
158219
158968
  });
158220
- import { existsSync as existsSync62, mkdirSync as mkdirSync29, readFileSync as readFileSync72, writeFileSync as writeFileSync25 } from "node:fs";
158969
+ import { existsSync as existsSync63, mkdirSync as mkdirSync29, readFileSync as readFileSync72, writeFileSync as writeFileSync25 } from "node:fs";
158221
158970
  import { join as join63, resolve as resolve49 } from "node:path";
158222
158971
  function readTestConfig(dir) {
158223
158972
  const p2 = resolve49(dir, TEST_CONFIG_FILE);
158224
- if (!existsSync62(p2)) return {};
158973
+ if (!existsSync63(p2)) return {};
158225
158974
  let parsed;
158226
158975
  try {
158227
158976
  parsed = JSON.parse(readFileSync72(p2, "utf8"));
@@ -158292,7 +159041,7 @@ function readNetRules(path2) {
158292
159041
  function defaultNetRules(dir) {
158293
159042
  for (const rel of ["dev/net-mocks.json", "tests/net-mocks.json"]) {
158294
159043
  const p2 = resolve49(dir, rel);
158295
- if (existsSync62(p2)) {
159044
+ if (existsSync63(p2)) {
158296
159045
  const rules = readNetRules(p2);
158297
159046
  if (rules.length) return { rules, from: rel };
158298
159047
  }
@@ -159384,7 +160133,7 @@ var init_release_payload_hash = __esm({
159384
160133
  import { execFileSync as execFileSync5 } from "node:child_process";
159385
160134
  import { createHash as createHash35, randomBytes as randomBytes2 } from "node:crypto";
159386
160135
  import {
159387
- existsSync as existsSync63,
160136
+ existsSync as existsSync64,
159388
160137
  lstatSync as lstatSync20,
159389
160138
  mkdirSync as mkdirSync31,
159390
160139
  realpathSync as realpathSync9,
@@ -159514,7 +160263,7 @@ function readLatestAttestation(contentDir2) {
159514
160263
  }
159515
160264
  function readRetainedAttestations(contentDir2) {
159516
160265
  const dir = join66(resolve53(contentDir2), ".himi", "attestations");
159517
- if (!existsSync63(dir)) return { runs: [], errors: [] };
160266
+ if (!existsSync64(dir)) return { runs: [], errors: [] };
159518
160267
  try {
159519
160268
  const names2 = readdirSync30(dir).filter((name) => name.endsWith(".json") && name !== "latest.json");
159520
160269
  const parsedRuns = [];
@@ -159531,7 +160280,7 @@ function readRetainedAttestations(contentDir2) {
159531
160280
  } else errors.push(`attestation history contains malformed retained run ${name}`);
159532
160281
  }
159533
160282
  const latest = readLatestAttestation(contentDir2);
159534
- if (existsSync63(join66(dir, "latest.json")) && !latest) errors.push("attestation history has no valid latest.json");
160283
+ if (existsSync64(join66(dir, "latest.json")) && !latest) errors.push("attestation history has no valid latest.json");
159535
160284
  else if (names2.length > 0 && !latest) errors.push("attestation history has no latest.json");
159536
160285
  const byHash = new Map(parsedRuns.map((run2) => [run2.selfHash, run2]));
159537
160286
  if (byHash.size !== parsedRuns.length) errors.push("attestation history contains duplicate self hashes");
@@ -159539,7 +160288,7 @@ function readRetainedAttestations(contentDir2) {
159539
160288
  if (selfHashFor(run2) !== run2.selfHash) errors.push(`selfHash does not match retained run ${run2.runId}`);
159540
160289
  for (const expected of Object.values(run2.screenshots)) {
159541
160290
  const path2 = screenshotArtifactPath(contentDir2, expected);
159542
- if (!existsSync63(path2)) errors.push(`missing screenshot for retained run ${run2.runId}: ${basename18(path2)}`);
160291
+ if (!existsSync64(path2)) errors.push(`missing screenshot for retained run ${run2.runId}: ${basename18(path2)}`);
159543
160292
  else if (sha2565(readFileSync74(path2)) !== expected) errors.push(`screenshot hash does not match retained run ${run2.runId}: ${basename18(path2)}`);
159544
160293
  }
159545
160294
  }
@@ -159610,7 +160359,7 @@ function writeAttestation(input, opts = {}) {
159610
160359
  const descriptorHashes = Object.fromEntries(
159611
160360
  Object.entries(input.descriptors).sort(([a2], [b2]) => a2.localeCompare(b2)).map(([screen, bytes2]) => [screen, sha2565(bytes2)])
159612
160361
  );
159613
- const screenshotEntries = Object.entries(input.screenshots ?? {}).sort(([a2], [b2]) => a2.localeCompare(b2)).filter(([, path2]) => existsSync63(path2)).map(([screen, path2]) => {
160362
+ const screenshotEntries = Object.entries(input.screenshots ?? {}).sort(([a2], [b2]) => a2.localeCompare(b2)).filter(([, path2]) => existsSync64(path2)).map(([screen, path2]) => {
159614
160363
  const bytes2 = readFileSync74(path2);
159615
160364
  return { screen, bytes: bytes2, hash: sha2565(bytes2) };
159616
160365
  });
@@ -159618,7 +160367,7 @@ function writeAttestation(input, opts = {}) {
159618
160367
  for (const { bytes: bytes2, hash: hash2 } of screenshotEntries) {
159619
160368
  const artifact = screenshotArtifactPath(contentDir2, hash2);
159620
160369
  mkdirSync31(join66(dir, "artifacts"), { recursive: true });
159621
- if (!existsSync63(artifact)) writeFileSync27(artifact, bytes2);
160370
+ if (!existsSync64(artifact)) writeFileSync27(artifact, bytes2);
159622
160371
  }
159623
160372
  const unsigned = {
159624
160373
  attestation: 2,
@@ -159663,7 +160412,7 @@ function writeAttestation(input, opts = {}) {
159663
160412
  retainedRuns.flatMap((run2) => Object.values(run2.screenshots))
159664
160413
  );
159665
160414
  const artifactDir = join66(dir, "artifacts");
159666
- if (existsSync63(artifactDir)) {
160415
+ if (existsSync64(artifactDir)) {
159667
160416
  for (const name of readdirSync30(artifactDir).filter((candidate) => candidate.endsWith(".png"))) {
159668
160417
  if (!retainedScreenshotHashes.has(name.slice(0, -4))) unlinkSync4(join66(artifactDir, name));
159669
160418
  }
@@ -159739,7 +160488,7 @@ function verifyAttestation(attestation, contentDir2, descriptors, expectedApp, r
159739
160488
  }
159740
160489
  for (const [screen, expected] of Object.entries(attestation.screenshots)) {
159741
160490
  const path2 = screenshotArtifactPath(contentDir2, expected);
159742
- if (!existsSync63(path2)) {
160491
+ if (!existsSync64(path2)) {
159743
160492
  errors.push(`missing screenshot for ${screen}: ${basename18(path2)}`);
159744
160493
  continue;
159745
160494
  }
@@ -159763,7 +160512,7 @@ var init_attestation = __esm({
159763
160512
  });
159764
160513
 
159765
160514
  // src/ux-evidence.ts
159766
- import { existsSync as existsSync64, mkdirSync as mkdirSync32, readFileSync as readFileSync75, writeFileSync as writeFileSync28 } from "node:fs";
160515
+ import { existsSync as existsSync65, mkdirSync as mkdirSync32, readFileSync as readFileSync75, writeFileSync as writeFileSync28 } from "node:fs";
159767
160516
  import { dirname as dirname38, isAbsolute as isAbsolute6, join as join67, relative as relative12, resolve as resolve54 } from "node:path";
159768
160517
  function isNativePlatform(value2) {
159769
160518
  return typeof value2 === "string" && NATIVE_PLATFORMS.includes(value2);
@@ -159773,7 +160522,7 @@ function isNativeAuditStatus(value2) {
159773
160522
  }
159774
160523
  function readText(path2) {
159775
160524
  try {
159776
- return existsSync64(path2) ? readFileSync75(path2, "utf8") : null;
160525
+ return existsSync65(path2) ? readFileSync75(path2, "utf8") : null;
159777
160526
  } catch {
159778
160527
  return null;
159779
160528
  }
@@ -159875,7 +160624,7 @@ function uxEvidenceForRelease(content, release2) {
159875
160624
  inheritedScreens: [],
159876
160625
  malformed: []
159877
160626
  };
159878
- if (!existsSync64(path2)) return { ...base, state: "absent" };
160627
+ if (!existsSync65(path2)) return { ...base, state: "absent" };
159879
160628
  const parsed = parseEvidence(path2);
159880
160629
  if (parsed.error) return { ...base, state: "unreadable", error: parsed.error };
159881
160630
  if (!parsed.evidence) return { ...base, state: "absent" };
@@ -159946,11 +160695,11 @@ var mobile_ux_lint_exports = {};
159946
160695
  __export(mobile_ux_lint_exports, {
159947
160696
  mobileUxIssues: () => mobileUxIssues
159948
160697
  });
159949
- import { existsSync as existsSync65, readFileSync as readFileSync76 } from "node:fs";
160698
+ import { existsSync as existsSync66, readFileSync as readFileSync76 } from "node:fs";
159950
160699
  import { join as join68 } from "node:path";
159951
160700
  function mobileUxIssues(dir, strict) {
159952
160701
  const file2 = join68(dir, "MOBILE-UX.md");
159953
- if (!existsSync65(file2)) return [];
160702
+ if (!existsSync66(file2)) return [];
159954
160703
  let text11;
159955
160704
  try {
159956
160705
  text11 = readFileSync76(file2, "utf8");
@@ -161634,7 +162383,7 @@ __export(functions_exports, {
161634
162383
  resolveFunctionsTarget: () => resolveFunctionsTarget,
161635
162384
  runRemoteFunctionOperation: () => runRemoteFunctionOperation
161636
162385
  });
161637
- import { readFileSync as readFileSync79, existsSync as existsSync68 } from "node:fs";
162386
+ import { readFileSync as readFileSync79, existsSync as existsSync69 } from "node:fs";
161638
162387
  import { join as join71, resolve as resolve55 } from "node:path";
161639
162388
  function resolveFunctionsTarget(input) {
161640
162389
  const explicitUrl = input.functionsUrl?.trim();
@@ -161654,7 +162403,7 @@ async function loadFunctionsApp(dir) {
161654
162403
  }
161655
162404
  const sources = {};
161656
162405
  for (const definition of config.functions.functions) {
161657
- const source = [".ts", ".js", ".mts", ".mjs"].map((extension) => join71(loaded.dir, "functions", `${definition.name}${extension}`)).find(existsSync68);
162406
+ const source = [".ts", ".js", ".mts", ".mjs"].map((extension) => join71(loaded.dir, "functions", `${definition.name}${extension}`)).find(existsSync69);
161658
162407
  if (!source) throw new Error(`missing source for function ${definition.name}; expected functions/${definition.name}.ts`);
161659
162408
  sources[definition.name] = readFileSync79(source, "utf8");
161660
162409
  }
@@ -161844,7 +162593,7 @@ var init_cli_bridge = __esm({
161844
162593
  });
161845
162594
 
161846
162595
  // src/mcp/file-tools.ts
161847
- import { closeSync as closeSync6, constants as constants4, lstatSync as lstatSync21, mkdirSync as mkdirSync33, openSync as openSync5, readdirSync as readdirSync31, readFileSync as readFileSync81, realpathSync as realpathSync10, renameSync as renameSync11, rmSync as rmSync18, statSync as statSync19, writeSync, existsSync as existsSync69 } from "node:fs";
162596
+ import { closeSync as closeSync6, constants as constants4, lstatSync as lstatSync21, mkdirSync as mkdirSync33, openSync as openSync5, readdirSync as readdirSync31, readFileSync as readFileSync81, realpathSync as realpathSync10, renameSync as renameSync11, rmSync as rmSync18, statSync as statSync19, writeSync, existsSync as existsSync70 } from "node:fs";
161848
162597
  import { randomBytes as randomBytes3 } from "node:crypto";
161849
162598
  import { dirname as dirname39, isAbsolute as isAbsolute7, join as join72, relative as relative13, resolve as resolve56, sep as sep18 } from "node:path";
161850
162599
  import * as z2 from "zod";
@@ -161854,7 +162603,7 @@ function within(root, p2) {
161854
162603
  function realish(p2) {
161855
162604
  let cur = p2;
161856
162605
  const tail = [];
161857
- while (!existsSync69(cur)) {
162606
+ while (!existsSync70(cur)) {
161858
162607
  const up = dirname39(cur);
161859
162608
  if (up === cur) break;
161860
162609
  tail.unshift(cur.slice(up.length + (up.endsWith(sep18) ? 0 : 1)));
@@ -161877,7 +162626,7 @@ function symlinkComponent(base, abs) {
161877
162626
  function workspaceRefusal(root, target) {
161878
162627
  const r3 = resolve56(root);
161879
162628
  const t2 = resolve56(r3, target);
161880
- if (!existsSync69(r3)) return `the workspace folder ${r3} does not exist`;
162629
+ if (!existsSync70(r3)) return `the workspace folder ${r3} does not exist`;
161881
162630
  if (!within(r3, t2) || !within(realpathSync10(r3), realish(t2))) return `"${target}" is outside the workspace folder ${r3}`;
161882
162631
  const link = symlinkComponent(r3, t2);
161883
162632
  if (link) return `"${link}" is a symlink \u2014 paths must stay in real folders inside the workspace`;
@@ -161886,13 +162635,13 @@ function workspaceRefusal(root, target) {
161886
162635
  async function confinedAppDir(args, deps) {
161887
162636
  const root = resolve56(await deps.defaultDir());
161888
162637
  const dir = typeof args.dir === "string" && args.dir ? resolve56(root, args.dir) : root;
161889
- if (!existsSync69(root)) return refuse5("no_workspace", `the workspace folder ${root} does not exist`);
162638
+ if (!existsSync70(root)) return refuse5("no_workspace", `the workspace folder ${root} does not exist`);
161890
162639
  if (!within(root, dir) || !within(realpathSync10(root), realish(dir))) return refuse5("outside_workspace", `"${String(args.dir)}" is outside the workspace folder`);
161891
162640
  const link = symlinkComponent(root, dir);
161892
162641
  if (link) return refuse5("outside_workspace", `"${link}" is a symlink \u2014 the app folder must be a real folder in the workspace`);
161893
162642
  const rel = relative13(root, dir);
161894
162643
  if (rel && (isDeniedSourcePath(`${rel}/x`) || isDeniedSourcePath(`${rel.toLowerCase()}/x`))) return refuse5("denied", `"${rel}" is a folder this tool does not touch`);
161895
- if (!existsSync69(join72(dir, CONTENT_MARKER))) {
162644
+ if (!existsSync70(join72(dir, CONTENT_MARKER))) {
161896
162645
  return refuse5("not_an_app", `"${rel || "."}" is not an app folder (no ${CONTENT_MARKER}) \u2014 see himi_list_apps, or create one with himi_init`);
161897
162646
  }
161898
162647
  return dir;
@@ -161900,7 +162649,7 @@ async function confinedAppDir(args, deps) {
161900
162649
  function onDiskSpelling(abs) {
161901
162650
  let cur = abs;
161902
162651
  const tail = [];
161903
- while (!existsSync69(cur)) {
162652
+ while (!existsSync70(cur)) {
161904
162653
  const up = dirname39(cur);
161905
162654
  if (up === cur) break;
161906
162655
  tail.unshift(cur.slice(up.length + (up.endsWith(sep18) ? 0 : 1)));
@@ -161924,7 +162673,7 @@ function confinedPath(appDir3, rel) {
161924
162673
  const abs = resolve56(appDir3, rel);
161925
162674
  if (!within(appDir3, abs) || abs === appDir3) return { error: `"${rel}" is outside the app folder` };
161926
162675
  const real = realish(abs);
161927
- const base = existsSync69(appDir3) ? realpathSync10(appDir3) : realish(appDir3);
162676
+ const base = existsSync70(appDir3) ? realpathSync10(appDir3) : realish(appDir3);
161928
162677
  if (!within(base, real) || real === base) return { error: `"${rel}" is outside the app folder` };
161929
162678
  const link = symlinkComponent(appDir3, abs);
161930
162679
  if (link) return { error: `"${link}" is a symlink, which this tool does not follow` };
@@ -161981,11 +162730,11 @@ function fileTools() {
161981
162730
  inputSchema: z2.object({}),
161982
162731
  handler: async (_a3, d2) => {
161983
162732
  const root = resolve56(await d2.defaultDir());
161984
- if (!existsSync69(root)) return ok({ ok: true, workspace: root, apps: [] });
162733
+ if (!existsSync70(root)) return ok({ ok: true, workspace: root, apps: [] });
161985
162734
  const apps = [];
161986
- if (existsSync69(join72(root, CONTENT_MARKER))) apps.push(".");
162735
+ if (existsSync70(join72(root, CONTENT_MARKER))) apps.push(".");
161987
162736
  for (const e2 of readdirSync31(root, { withFileTypes: true })) {
161988
- if (e2.isDirectory() && !e2.name.startsWith(".") && existsSync69(join72(root, e2.name, CONTENT_MARKER))) apps.push(e2.name);
162737
+ if (e2.isDirectory() && !e2.name.startsWith(".") && existsSync70(join72(root, e2.name, CONTENT_MARKER))) apps.push(e2.name);
161989
162738
  }
161990
162739
  return ok({ ok: true, workspace: root, apps: apps.sort() });
161991
162740
  }
@@ -161999,7 +162748,7 @@ function fileTools() {
161999
162748
  handler: async (a2, d2) => {
162000
162749
  const app = await confinedAppDir(a2, d2);
162001
162750
  if (typeof app !== "string") return app;
162002
- if (!existsSync69(app) || !statSync19(app).isDirectory()) return refuse5("no_app", `no folder at ${app}`);
162751
+ if (!existsSync70(app) || !statSync19(app).isDirectory()) return refuse5("no_app", `no folder at ${app}`);
162003
162752
  return ok({ ok: true, dir: app, ...listFiles(app) });
162004
162753
  }
162005
162754
  },
@@ -162014,7 +162763,7 @@ function fileTools() {
162014
162763
  if (typeof app !== "string") return app;
162015
162764
  const p2 = confinedPath(app, a2.path);
162016
162765
  if (typeof p2 !== "string") return refuse5("bad_path", p2.error);
162017
- if (!existsSync69(p2) || !lstatSync21(p2).isFile()) return refuse5("not_found", `no file "${String(a2.path)}"`);
162766
+ if (!existsSync70(p2) || !lstatSync21(p2).isFile()) return refuse5("not_found", `no file "${String(a2.path)}"`);
162018
162767
  const size = statSync19(p2).size;
162019
162768
  if (size > MAX_FILE_BYTES) return refuse5("too_large", `"${String(a2.path)}" is ${size} bytes \u2014 over the ${MAX_FILE_BYTES}-byte read limit`);
162020
162769
  return ok({ ok: true, path: a2.path, bytes: size, content: readFileSync81(p2, "utf8") });
@@ -162041,7 +162790,7 @@ function fileTools() {
162041
162790
  if (typeof p2 !== "string") refused2.push({ path: f2.path, error: p2.error });
162042
162791
  else if (typeof f2.content !== "string") refused2.push({ path: f2.path, error: "content must be text" });
162043
162792
  else if (Buffer.byteLength(f2.content) > MAX_FILE_BYTES) refused2.push({ path: f2.path, error: `over the ${MAX_FILE_BYTES}-byte limit` });
162044
- else if (existsSync69(p2) && !lstatSync21(p2).isFile()) refused2.push({ path: f2.path, error: "not a regular file" });
162793
+ else if (existsSync70(p2) && !lstatSync21(p2).isFile()) refused2.push({ path: f2.path, error: "not a regular file" });
162045
162794
  else if (planned2.some((q2) => q2.abs === p2)) refused2.push({ path: f2.path, error: "the same file twice in one call" });
162046
162795
  else planned2.push({ abs: p2, rel: String(f2.path), content: f2.content });
162047
162796
  }
@@ -162074,7 +162823,7 @@ function fileTools() {
162074
162823
  for (const rel of paths2) {
162075
162824
  const p2 = confinedPath(app, rel);
162076
162825
  if (typeof p2 !== "string") refused2.push({ path: rel, error: p2.error });
162077
- else if (!existsSync69(p2)) refused2.push({ path: rel, error: "no such file" });
162826
+ else if (!existsSync70(p2)) refused2.push({ path: rel, error: "no such file" });
162078
162827
  else if (!lstatSync21(p2).isFile()) refused2.push({ path: rel, error: "not a regular file" });
162079
162828
  else if (!planned2.includes(p2)) {
162080
162829
  planned2.push(p2);
@@ -162869,14 +163618,14 @@ var init_open_url = __esm({
162869
163618
  });
162870
163619
 
162871
163620
  // src/ux-audit.ts
162872
- import { existsSync as existsSync72, readFileSync as readFileSync83, readdirSync as readdirSync32 } from "node:fs";
163621
+ import { existsSync as existsSync73, readFileSync as readFileSync83, readdirSync as readdirSync32 } from "node:fs";
162873
163622
  import { join as join76, relative as relative15, resolve as resolve61 } from "node:path";
162874
163623
  function issue(issues, strict, code, message2, path2) {
162875
163624
  issues.push({ code, message: message2, ...path2 ? { path: path2 } : {}, severity: strict ? "error" : "warning" });
162876
163625
  }
162877
163626
  function readText2(path2) {
162878
163627
  try {
162879
- return existsSync72(path2) ? readFileSync83(path2, "utf8") : null;
163628
+ return existsSync73(path2) ? readFileSync83(path2, "utf8") : null;
162880
163629
  } catch {
162881
163630
  return null;
162882
163631
  }
@@ -162976,7 +163725,7 @@ function auditUx(content, strict = false) {
162976
163725
  }
162977
163726
  if (usesAppNetwork(source)) {
162978
163727
  const mocksPath = join76(dir, "dev", "net-mocks.json");
162979
- if (!existsSync72(mocksPath)) {
163728
+ if (!existsSync73(mocksPath)) {
162980
163729
  issue(issues, strict, "missing-app-mocks", "This package uses a Wix/network client but has no app-specific dev/net-mocks.json. `himi test --record` writes one from the live responses it sees; then add fixtures for dynamic, entitlement, or recovery flows.", "dev/net-mocks.json");
162981
163730
  } else {
162982
163731
  try {
@@ -163024,7 +163773,7 @@ __export(native_decode_exports, {
163024
163773
  runNativeDecode: () => runNativeDecode
163025
163774
  });
163026
163775
  import { execFileSync as execFileSync6, spawnSync as spawnSync4 } from "node:child_process";
163027
- import { existsSync as existsSync73, mkdirSync as mkdirSync37, mkdtempSync as mkdtempSync5, readFileSync as readFileSync84, rmSync as rmSync20, writeFileSync as writeFileSync31 } from "node:fs";
163776
+ import { existsSync as existsSync74, mkdirSync as mkdirSync37, mkdtempSync as mkdtempSync5, readFileSync as readFileSync84, rmSync as rmSync20, writeFileSync as writeFileSync31 } from "node:fs";
163028
163777
  import { homedir as homedir10, tmpdir as tmpdir6 } from "node:os";
163029
163778
  import { join as join78 } from "node:path";
163030
163779
  import { fileURLToPath as fileURLToPath27 } from "node:url";
@@ -163036,8 +163785,8 @@ function nativeDecodeAndroidHarnessDir() {
163036
163785
  }
163037
163786
  function nativeOracleShipped() {
163038
163787
  return {
163039
- ios: existsSync73(join78(nativeDecodePackageDir(), "Package.swift")),
163040
- android: existsSync73(join78(nativeDecodeAndroidHarnessDir(), "gradlew"))
163788
+ ios: existsSync74(join78(nativeDecodePackageDir(), "Package.swift")),
163789
+ android: existsSync74(join78(nativeDecodeAndroidHarnessDir(), "gradlew"))
163041
163790
  };
163042
163791
  }
163043
163792
  function detectNativeDecode(options = {}) {
@@ -163048,7 +163797,7 @@ function detectNativeDecode(options = {}) {
163048
163797
  return { platform: "ios", available: false, reason: `the iOS decoder oracle requires macOS (darwin); this host is ${hostPlatform}` };
163049
163798
  }
163050
163799
  if (!swiftAvailable) return { platform: "ios", available: false, reason: "swift is not on PATH" };
163051
- const packageAvailable = options.packageAvailable ?? existsSync73(join78(packageDir, "Package.swift"));
163800
+ const packageAvailable = options.packageAvailable ?? existsSync74(join78(packageDir, "Package.swift"));
163052
163801
  if (!packageAvailable) {
163053
163802
  return {
163054
163803
  platform: "ios",
@@ -163074,7 +163823,7 @@ function defaultAndroidSdkDir(hostPlatform, home) {
163074
163823
  function detectAndroidNativeDecode(options = {}) {
163075
163824
  const harnessDir = options.harnessDir ?? nativeDecodeAndroidHarnessDir();
163076
163825
  const gradlew = join78(harnessDir, "gradlew");
163077
- const gradlewAvailable = options.gradlewAvailable ?? existsSync73(gradlew);
163826
+ const gradlewAvailable = options.gradlewAvailable ?? existsSync74(gradlew);
163078
163827
  if (!gradlewAvailable) {
163079
163828
  return {
163080
163829
  platform: "android",
@@ -163082,7 +163831,7 @@ function detectAndroidNativeDecode(options = {}) {
163082
163831
  reason: "the in-repo Android Gradle harness is unavailable (off-repo installs do not ship the decoder oracle)"
163083
163832
  };
163084
163833
  }
163085
- const exists = typeof options.sdkAvailable === "function" ? options.sdkAvailable : typeof options.sdkAvailable === "boolean" ? /* @__PURE__ */ ((answer) => () => answer)(options.sdkAvailable) : existsSync73;
163834
+ const exists = typeof options.sdkAvailable === "function" ? options.sdkAvailable : typeof options.sdkAvailable === "boolean" ? /* @__PURE__ */ ((answer) => () => answer)(options.sdkAvailable) : existsSync74;
163086
163835
  const defaultDir = defaultAndroidSdkDir(options.hostPlatform ?? process.platform, options.homeDir ?? homedir10());
163087
163836
  const candidates = [
163088
163837
  options.androidHome ?? process.env.ANDROID_HOME,
@@ -163344,7 +164093,7 @@ __export(browser_authoring_exports, {
163344
164093
  });
163345
164094
  import { createServer as createServer4 } from "node:http";
163346
164095
  import { createHash as createHash38, randomBytes as randomBytes4 } from "node:crypto";
163347
- import { existsSync as existsSync74, readdirSync as readdirSync33, readFileSync as readFileSync85, realpathSync as realpathSync11, statSync as statSync20 } from "node:fs";
164096
+ import { existsSync as existsSync75, readdirSync as readdirSync33, readFileSync as readFileSync85, realpathSync as realpathSync11, statSync as statSync20 } from "node:fs";
163348
164097
  import { join as join79, posix as posix3, relative as relative16, sep as sep19 } from "node:path";
163349
164098
  function humanMs(ms2) {
163350
164099
  return ms2 < 1e3 ? `${ms2}ms` : `${Math.round(ms2 / 1e3)}s`;
@@ -163367,7 +164116,7 @@ function collectWorkerSources(tier5SrcDir, bundleName) {
163367
164116
  }
163368
164117
  }
163369
164118
  };
163370
- if (!existsSync74(root)) return null;
164119
+ if (!existsSync75(root)) return null;
163371
164120
  walk2(root, `/tier5-src/${bundleName}`);
163372
164121
  const entry = [`/tier5-src/${bundleName}/index.ts`, `/tier5-src/${bundleName}/index.js`].find((p2) => p2 in files);
163373
164122
  if (!entry) return null;
@@ -163394,7 +164143,7 @@ function collectRelativeSiblings(files, tier5SrcDir) {
163394
164143
  join79(onDisk, "index.js")
163395
164144
  ];
163396
164145
  for (const abs of candidates) {
163397
- if (!existsSync74(abs) || statSync20(abs).isDirectory()) continue;
164146
+ if (!existsSync75(abs) || statSync20(abs).isDirectory()) continue;
163398
164147
  const key3 = `/tier5-src/${relative16(tier5SrcDir, abs).split(sep19).join(posix3.sep)}`;
163399
164148
  if (key3 in files) break;
163400
164149
  files[key3] = readFileSync85(abs, "utf8");
@@ -163505,7 +164254,7 @@ async function readBody3(req) {
163505
164254
  async function runBrowserAuthoring(opts) {
163506
164255
  const log = opts.log ?? (() => {
163507
164256
  });
163508
- const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
164257
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS3;
163509
164258
  const payload = encodeJob(opts.job);
163510
164259
  const token = mintToken2(payload);
163511
164260
  const unusable = await probeAuthoringPage(opts.authoringBase, opts.fetchImpl, opts.probeTimeoutMs);
@@ -163581,11 +164330,11 @@ async function runBrowserAuthoring(opts) {
163581
164330
  });
163582
164331
  });
163583
164332
  }
163584
- var DEFAULT_TIMEOUT_MS2, PROBE_TIMEOUT_MS, POINT_ELSEWHERE, NO_SUCH_ROUTE, NOT_STAGED, MAX_CALLBACK_BYTES;
164333
+ var DEFAULT_TIMEOUT_MS3, PROBE_TIMEOUT_MS, POINT_ELSEWHERE, NO_SUCH_ROUTE, NOT_STAGED, MAX_CALLBACK_BYTES;
163585
164334
  var init_browser_authoring = __esm({
163586
164335
  "src/browser-authoring.ts"() {
163587
164336
  init_open_url();
163588
- DEFAULT_TIMEOUT_MS2 = 5 * 60 * 1e3;
164337
+ DEFAULT_TIMEOUT_MS3 = 5 * 60 * 1e3;
163589
164338
  PROBE_TIMEOUT_MS = 5e3;
163590
164339
  POINT_ELSEWHERE = "Point --serve-url at a plane that mounts /v1/authoring/* (the local serve stack does NOT: core/serve-authoring is a separate service), or pass --target to select a deployed one.";
163591
164340
  NO_SUCH_ROUTE = /* @__PURE__ */ new Set([404, 410]);
@@ -163604,7 +164353,7 @@ __export(coverage_exports, {
163604
164353
  suppressedNativeKeys: () => suppressedNativeKeys,
163605
164354
  trendAndStore: () => trendAndStore
163606
164355
  });
163607
- import { existsSync as existsSync75, mkdirSync as mkdirSync38, readFileSync as readFileSync86, writeFileSync as writeFileSync32 } from "node:fs";
164356
+ import { existsSync as existsSync76, mkdirSync as mkdirSync38, readFileSync as readFileSync86, writeFileSync as writeFileSync32 } from "node:fs";
163608
164357
  import { dirname as dirname43, join as join80 } from "node:path";
163609
164358
  function suppressedNativeKeys(oracle) {
163610
164359
  return [...oracle.ios ? [] : ["native-decode|ios"], ...oracle.android ? [] : ["native-decode|android"]];
@@ -163788,7 +164537,7 @@ function trendAndStore(dir, entries, suppressed) {
163788
164537
  const p2 = join80(dir, LEDGER_FILE);
163789
164538
  let previous = null;
163790
164539
  try {
163791
- if (existsSync75(p2)) {
164540
+ if (existsSync76(p2)) {
163792
164541
  const parsed = JSON.parse(readFileSync86(p2, "utf8"));
163793
164542
  if (Array.isArray(parsed.keys)) previous = parsed.keys.filter((k2) => typeof k2 === "string");
163794
164543
  }
@@ -163831,7 +164580,7 @@ function diffAndStoreObservations(dir, current) {
163831
164580
  const p2 = join80(dir, OBS_FILE);
163832
164581
  let previous = null;
163833
164582
  try {
163834
- if (existsSync75(p2)) {
164583
+ if (existsSync76(p2)) {
163835
164584
  const parsed = JSON.parse(readFileSync86(p2, "utf8"));
163836
164585
  if (parsed.screens && typeof parsed.screens === "object" && !Array.isArray(parsed.screens) && Object.values(parsed.screens).every(
163837
164586
  (v2) => Array.isArray(v2) && v2.every((l2) => typeof l2 === "string")
@@ -164204,11 +164953,11 @@ __export(design_kits_exports, {
164204
164953
  kitsDir: () => kitsDir,
164205
164954
  listKits: () => listKits2
164206
164955
  });
164207
- import { existsSync as existsSync77, readFileSync as readFileSync88, readdirSync as readdirSync34 } from "node:fs";
164956
+ import { existsSync as existsSync78, readFileSync as readFileSync88, readdirSync as readdirSync34 } from "node:fs";
164208
164957
  import { join as join83, basename as basename20 } from "node:path";
164209
164958
  import { fileURLToPath as fileURLToPath28 } from "node:url";
164210
164959
  function kitsDir() {
164211
- return KIT_DIR_CANDIDATES.find((p2) => existsSync77(p2));
164960
+ return KIT_DIR_CANDIDATES.find((p2) => existsSync78(p2));
164212
164961
  }
164213
164962
  function listKits2() {
164214
164963
  const dir = kitsDir();
@@ -164703,7 +165452,7 @@ __export(coverage_exports2, {
164703
165452
  verifyNativeProof: () => verifyNativeProof
164704
165453
  });
164705
165454
  import { createHash as createHash39 } from "node:crypto";
164706
- import { existsSync as existsSync79, readFileSync as readFileSync90, writeFileSync as writeFileSync33 } from "node:fs";
165455
+ import { existsSync as existsSync80, readFileSync as readFileSync90, writeFileSync as writeFileSync33 } from "node:fs";
164707
165456
  import { isAbsolute as isAbsolute8, join as join85, resolve as resolve64 } from "node:path";
164708
165457
  function verifiedEvidence(evidenceDir) {
164709
165458
  const manifest2 = obj3(JSON.parse(readFileSync90(join85(evidenceDir, "manifest.json"), "utf8")));
@@ -164799,7 +165548,7 @@ function deriveRequirements(evidenceDir) {
164799
165548
  function verifyNativeProof(contentDir2, releaseHash, requirementIds) {
164800
165549
  const root = resolve64(contentDir2);
164801
165550
  const path2 = join85(root, NATIVE_PROOF_FILE);
164802
- if (!existsSync79(path2)) return { ok: false, issues: [`${NATIVE_PROOF_FILE} is absent.`] };
165551
+ if (!existsSync80(path2)) return { ok: false, issues: [`${NATIVE_PROOF_FILE} is absent.`] };
164803
165552
  let proof;
164804
165553
  try {
164805
165554
  proof = obj3(JSON.parse(readFileSync90(path2, "utf8")));
@@ -164821,7 +165570,7 @@ function verifyNativeProof(contentDir2, releaseHash, requirementIds) {
164821
165570
  continue;
164822
165571
  }
164823
165572
  const artifact = record2.artifact;
164824
- if (typeof artifact !== "string" || !artifact.trim() || isAbsolute8(artifact) || artifact.split(/[\\/]/).includes("..") || !existsSync79(join85(root, artifact))) {
165573
+ if (typeof artifact !== "string" || !artifact.trim() || isAbsolute8(artifact) || artifact.split(/[\\/]/).includes("..") || !existsSync80(join85(root, artifact))) {
164825
165574
  issues.push(`Native walkthrough check ${id} needs a reviewable artifact file.`);
164826
165575
  }
164827
165576
  }
@@ -164830,7 +165579,7 @@ function verifyNativeProof(contentDir2, releaseHash, requirementIds) {
164830
165579
  function syncCoverage(evidenceDir, contentDir2, write2 = true) {
164831
165580
  const current = deriveRequirements(evidenceDir);
164832
165581
  const path2 = join85(resolve64(contentDir2), COVERAGE_FILE);
164833
- const existed = existsSync79(path2);
165582
+ const existed = existsSync80(path2);
164834
165583
  const old = existed ? obj3(JSON.parse(readFileSync90(path2, "utf8"))) : {};
164835
165584
  const hashesChanged = existed && JSON.stringify(old.sourceHashes) !== JSON.stringify(current.sourceHashes);
164836
165585
  const prior = Array.isArray(old.requirements) ? old.requirements : [];
@@ -164871,7 +165620,7 @@ function verifyCoverage(evidenceDir, contentDir2, releaseHash, builtScreenIds) {
164871
165620
  const saved = result.existed ? obj3(JSON.parse(readFileSync90(join85(resolve64(contentDir2), COVERAGE_FILE), "utf8"))) : {};
164872
165621
  const rows = Array.isArray(saved.requirements) ? saved.requirements.map(obj3) : [];
164873
165622
  const contentManifest = join85(resolve64(contentDir2), "himalaya.content.json");
164874
- const declaredScreens = existsSync79(contentManifest) ? obj3(obj3(JSON.parse(readFileSync90(contentManifest, "utf8"))).screens) : void 0;
165623
+ const declaredScreens = existsSync80(contentManifest) ? obj3(obj3(JSON.parse(readFileSync90(contentManifest, "utf8"))).screens) : void 0;
164875
165624
  const availableScreens = builtScreenIds ? new Set(builtScreenIds) : declaredScreens && Object.keys(declaredScreens).length ? new Set(Object.keys(declaredScreens)) : void 0;
164876
165625
  for (const row2 of rows) {
164877
165626
  const id = typeof row2.id === "string" ? row2.id : void 0;
@@ -164907,7 +165656,7 @@ function verifyCoverage(evidenceDir, contentDir2, releaseHash, builtScreenIds) {
164907
165656
  const path2 = check.evidence;
164908
165657
  if (typeof path2 !== "string" || !path2.trim() || isAbsolute8(path2) || path2.split(/[\\/]/).includes("..")) {
164909
165658
  issues.push({ id, message: `Check ${required3} needs a safe relative evidence path.` });
164910
- } else if (!existsSync79(join85(resolve64(contentDir2), path2))) {
165659
+ } else if (!existsSync80(join85(resolve64(contentDir2), path2))) {
164911
165660
  issues.push({ id, message: `Check ${required3} evidence file is absent: ${path2}.` });
164912
165661
  } else {
164913
165662
  try {
@@ -164918,7 +165667,7 @@ function verifyCoverage(evidenceDir, contentDir2, releaseHash, builtScreenIds) {
164918
165667
  issues.push({ id, message: `Check ${required3} has no latest passed record for this requirement and target.` });
164919
165668
  } else {
164920
165669
  const artifact = record2.artifact;
164921
- if (typeof artifact !== "string" || !artifact.trim() || isAbsolute8(artifact) || artifact.split(/[\\/]/).includes("..") || !existsSync79(join85(resolve64(contentDir2), artifact))) {
165670
+ if (typeof artifact !== "string" || !artifact.trim() || isAbsolute8(artifact) || artifact.split(/[\\/]/).includes("..") || !existsSync80(join85(resolve64(contentDir2), artifact))) {
164922
165671
  issues.push({ id, message: `Check ${required3} needs a reviewable artifact file.` });
164923
165672
  }
164924
165673
  }
@@ -164958,7 +165707,7 @@ __export(validate_topbar_exports, {
164958
165707
  runOneAppTopBarValidation: () => runOneAppTopBarValidation
164959
165708
  });
164960
165709
  import { createHash as createHash40 } from "node:crypto";
164961
- import { existsSync as existsSync80, readFileSync as readFileSync91, statSync as statSync22 } from "node:fs";
165710
+ import { existsSync as existsSync81, readFileSync as readFileSync91, statSync as statSync22 } from "node:fs";
164962
165711
  import { resolve as resolve65, join as join86 } from "node:path";
164963
165712
  import ts8 from "typescript";
164964
165713
  function enrichedControls(raw, views) {
@@ -165167,7 +165916,7 @@ function configActions(configPath) {
165167
165916
  }
165168
165917
  function screenActions2(contentDir2) {
165169
165918
  const path2 = join86(contentDir2, "dev", "index.ts");
165170
- if (!existsSync80(path2)) return /* @__PURE__ */ new Map();
165919
+ if (!existsSync81(path2)) return /* @__PURE__ */ new Map();
165171
165920
  const source = ts8.createSourceFile(path2, readFileSync91(path2, "utf8"), ts8.ScriptTarget.Latest, true, ts8.ScriptKind.TS);
165172
165921
  if (source.parseDiagnostics.length) throw Error("dev/index.ts could not be parsed.");
165173
165922
  const declaration = source.statements.filter(ts8.isVariableStatement).flatMap((statement) => [...statement.declarationList.declarations]).find((item) => ts8.isIdentifier(item.name) && item.name.text === "SCREENS");
@@ -165268,7 +166017,7 @@ function validate3(evidenceDir, contentDir2) {
165268
166017
  }
165269
166018
  const mappings = /* @__PURE__ */ new Map();
165270
166019
  const coveragePath = join86(contentDir2, "ONE-APP-COVERAGE.json");
165271
- if (existsSync80(coveragePath)) {
166020
+ if (existsSync81(coveragePath)) {
165272
166021
  try {
165273
166022
  const coverage = readJson7(coveragePath);
165274
166023
  for (const row2 of Array.isArray(coverage.requirements) ? coverage.requirements : []) {
@@ -166134,7 +166883,7 @@ async function generatePkce() {
166134
166883
  return { verifier, challenge: base64url(new Uint8Array(digest2)) };
166135
166884
  }
166136
166885
  async function hostedAuthUrl(req, visitorToken, fetchImpl = fetch) {
166137
- const res = await fetchImpl(`${WIX_API2}${REDIRECT_SESSION_PATH}`, {
166886
+ const res = await fetchImpl(`${WIX_API3}${REDIRECT_SESSION_PATH}`, {
166138
166887
  method: "POST",
166139
166888
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${visitorToken}` },
166140
166889
  body: JSON.stringify({
@@ -166177,7 +166926,7 @@ async function hostedAuthUrl(req, visitorToken, fetchImpl = fetch) {
166177
166926
  return fullUrl;
166178
166927
  }
166179
166928
  async function exchangeAuthCode(cfg, code, verifier, fetchImpl = fetch) {
166180
- const res = await fetchImpl(`${WIX_API2}${TOKEN_PATH}`, {
166929
+ const res = await fetchImpl(`${WIX_API3}${TOKEN_PATH}`, {
166181
166930
  method: "POST",
166182
166931
  headers: { "Content-Type": "application/json" },
166183
166932
  body: JSON.stringify({
@@ -166226,10 +166975,10 @@ function safeReturnPath(value2, fallback) {
166226
166975
  if (/[-]/.test(value2)) return fallback;
166227
166976
  return value2;
166228
166977
  }
166229
- var WIX_API2, REDIRECT_SESSION_PATH, TOKEN_PATH, MEMBER_SESSION_COOKIE, MEMBER_SESSION_TTL_MS, PENDING_LOGIN_TTL_MS, MEMBER_CALLBACK_PATH;
166978
+ var WIX_API3, REDIRECT_SESSION_PATH, TOKEN_PATH, MEMBER_SESSION_COOKIE, MEMBER_SESSION_TTL_MS, PENDING_LOGIN_TTL_MS, MEMBER_CALLBACK_PATH;
166230
166979
  var init_wix_member_auth = __esm({
166231
166980
  "../../core/serve-runtime/src/wix-member-auth.ts"() {
166232
- WIX_API2 = "https://www.wixapis.com";
166981
+ WIX_API3 = "https://www.wixapis.com";
166233
166982
  REDIRECT_SESSION_PATH = "/_api/redirects-api/v1/redirect-session";
166234
166983
  TOKEN_PATH = "/oauth2/token";
166235
166984
  MEMBER_SESSION_COOKIE = "himi_wm_sid";
@@ -168052,37 +168801,38 @@ var init_preview_assets_generated = __esm({
168052
168801
  "../../packages/serve/src/preview-assets.generated.ts"() {
168053
168802
  init_preview_assets_format();
168054
168803
  PREVIEW_ASSET_MANIFEST = [
168055
- { key: "assets/DashboardHost-D0AIh2Fi.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 2916, sha256: "eca2f8260addf4ead475e304f4bdb9aa3a5655aa9b9042a0107c73d3c5d8147f" },
168056
- { key: "assets/DevDrawer-Sm3GT4me.js", contentType: "application/javascript; charset=utf-8", offset: 2924, length: 16744, sha256: "1764380f2536a2da8715514073c657a2e7c1bcb8f299e5e8e273acae3bdc3164" },
168057
- { key: "assets/IdiomCompare-d9cqrgVi.js", contentType: "application/javascript; charset=utf-8", offset: 19668, length: 1892, sha256: "ea482691eaa9cda3d3239568d177e9332b94a0a59e9e9e5d269d059fe07ddd58" },
168058
- { key: "assets/LightboxViewer-NWgAZkvo.js", contentType: "application/javascript; charset=utf-8", offset: 21560, length: 8132, sha256: "21f6c5678752b22d095626e89c039bf1ab1cf566e9b0a880ddc7c64de2635f6a" },
168059
- { key: "assets/PhonePreviewControl-DmWDJR7y.js", contentType: "application/javascript; charset=utf-8", offset: 29692, length: 37729, sha256: "c528ff6a6503b5cecddcb95d98e7b10e71b38718513a992c95c3e61aac178c9a" },
168060
- { key: "assets/SchemeCompare-DAe05rjM.js", contentType: "application/javascript; charset=utf-8", offset: 67421, length: 1824, sha256: "ed47f5a463367279abfa343aaabb348b2cf419a48072a265442f84ba585976da" },
168804
+ { key: "assets/DashboardHost-CKAKQQH0.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 2916, sha256: "bb3e4ce667ae9992367c62d035e5cef2367bfd684484d0ccd6689952624dd0ec" },
168805
+ { key: "assets/DevDrawer-Bo1-NtPp.js", contentType: "application/javascript; charset=utf-8", offset: 2924, length: 16744, sha256: "73c480764b062926b68dec0e4976232c8b08dd6f54bdc8ea1dab74b2b3ded5d1" },
168806
+ { key: "assets/IdiomCompare-z7cS66yR.js", contentType: "application/javascript; charset=utf-8", offset: 19668, length: 1892, sha256: "1031b3129bca32bfb5d16744b12ce887ca6bd80526c54d96e24061ed85df2836" },
168807
+ { key: "assets/LightboxViewer-CtEUVaFK.js", contentType: "application/javascript; charset=utf-8", offset: 21560, length: 8132, sha256: "ff0fcd314ce86c2dcce9e62fd0637be7b65780c9c865324fab5ed2147eaee8dd" },
168808
+ { key: "assets/PhonePreviewControl-BQSqif6v.js", contentType: "application/javascript; charset=utf-8", offset: 29692, length: 37729, sha256: "9edaf0f361aa26eb84999a2c26d2ec5d3b8bcd9b0751992346301292fcdd34c0" },
168809
+ { key: "assets/SchemeCompare-CnLhoKms.js", contentType: "application/javascript; charset=utf-8", offset: 67421, length: 1824, sha256: "e34139136ef0b09ed4d035cccd288aad174cad001fbf37ea7190a95d021daa0a" },
168061
168810
  { key: "assets/glassPreviewBrowser-Bt5ZFmG4.js", contentType: "application/javascript; charset=utf-8", offset: 69245, length: 342, sha256: "20d73f97d38f6d9a0b79e68e24954cd6bbfe66833a6e6aecae00a9102e64cab3" },
168062
- { key: "assets/index-DZLNpgeb.js", contentType: "application/javascript; charset=utf-8", offset: 69587, length: 1337208, sha256: "89aa5fffddb672994a2a13f4a209b5694ff41f2055b01d9d5837829682b7be6f" },
168063
- { key: "assets/pdf-DkBJdVwB.js", contentType: "application/javascript; charset=utf-8", offset: 1406795, length: 488199, sha256: "8d77ca7222c2580c60a06abe6c78163894a40593fae3a071e664a3a05110dbec" },
168064
- { key: "assets/pdf.worker.min-BQa_JDET.js", contentType: "application/javascript; charset=utf-8", offset: 1894994, length: 73, sha256: "41bcfda4f3c8c0a81c785ea87c69afc8e7d0ed8c333324aee94c273d881bb6aa" },
168065
- { key: "assets/pdf.worker.min-BmVo14Nb.mjs", contentType: "application/javascript; charset=utf-8", offset: 1895067, length: 1317034, sha256: "a33cfe728c584fdba4fcc1fd54bcdc2f9f2f13889ddbb5b2bd1d0f8cbe49b84e" },
168066
- { key: "assets/pdfDocument-DKE-Ra33.js", contentType: "application/javascript; charset=utf-8", offset: 3212101, length: 3379, sha256: "675e5f6d7a6d04607c86b32573e1d28aa126a049f6df26e39d407a9cb3059fc9" },
168067
- { key: "assets/pdfFetch-Cc8i1I1h.js", contentType: "application/javascript; charset=utf-8", offset: 3215480, length: 2266, sha256: "1d21ad008921942217c9eac0c35b1713773b9d89c71e3ab4412781f7bb88f463" },
168068
- { key: "assets/webviewBridgeHost-Tij-rBHM.js", contentType: "application/javascript; charset=utf-8", offset: 3217746, length: 9781, sha256: "9ac08d6b6839d3927c9cd364e53a5b01992e534bf77247568e24b18b3e4d2bb7" },
168069
- { key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset: 3227527, length: 4610, sha256: "994062dd7af4186a739de55dd9e151c63b6301f8e2cbafc608d35c2e87da0cd2" },
168070
- { key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset: 3232137, length: 488584, sha256: "d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134" },
168071
- { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 3720721, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
168072
- { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 3811645, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
168073
- { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 3902629, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
168074
- { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 3993609, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
168075
- { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 4084481, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
168076
- { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 4175461, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
168077
- { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 4284097, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
168078
- { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 4393181, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
168079
- { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 4502229, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
168080
- { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 4609929, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
168081
- { key: "himi-sw.js", contentType: "application/javascript; charset=utf-8", offset: 4698037, length: 6748, sha256: "4a92459977d7cefa1a6a7e020c3a63509737f083b3f2773557c1a5771665811a" },
168082
- { key: "index.html", contentType: "text/html; charset=utf-8", offset: 4704785, length: 4947, sha256: "ce6250b8f09a5c349489f0db1b7410dbac5627087c11b4dddc7958fbde5641db" },
168083
- { key: "ios-glass-preview.css", contentType: "text/css; charset=utf-8", offset: 4709732, length: 7193, sha256: "a482f4796147c2a3893942e10ab225bd3b6f749f7125fe0330680d4c20ea0212" },
168084
- { key: "ios-glass-preview.svg", contentType: "image/svg+xml", offset: 4716925, length: 423, sha256: "b9cd5989d31464a0422f260a332af6be5add0b04de2148944de35158f3b75efc" },
168085
- { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 4717348, length: 18778, sha256: "ba734d58c88281c71c01d9a2842a991d06f3ed91bf03449427ef11c7f6d1605d" }
168811
+ { key: "assets/index-C4VDe6F7.js", contentType: "application/javascript; charset=utf-8", offset: 69587, length: 1339680, sha256: "d3a004b8bc8713b9f3a96d38a7ffedf2bb4ad3992c8b9f1d46d4c5906c1a69a0" },
168812
+ { key: "assets/pdf-Bh2VDDGs.js", contentType: "application/javascript; charset=utf-8", offset: 1409267, length: 488199, sha256: "ecc062652805a1f0b10c43e9e0bd272738471baae10af272fd8cf0bbaefe9afe" },
168813
+ { key: "assets/pdf.worker.min-BQa_JDET.js", contentType: "application/javascript; charset=utf-8", offset: 1897466, length: 73, sha256: "41bcfda4f3c8c0a81c785ea87c69afc8e7d0ed8c333324aee94c273d881bb6aa" },
168814
+ { key: "assets/pdf.worker.min-BmVo14Nb.mjs", contentType: "application/javascript; charset=utf-8", offset: 1897539, length: 1317034, sha256: "a33cfe728c584fdba4fcc1fd54bcdc2f9f2f13889ddbb5b2bd1d0f8cbe49b84e" },
168815
+ { key: "assets/pdfDocument-Beot4wow.js", contentType: "application/javascript; charset=utf-8", offset: 3214573, length: 3379, sha256: "f65ebbbff93207e6d06e016710c3bd2d64d1c1cb3c3cbbd78c98fccc261c1b91" },
168816
+ { key: "assets/pdfFetch-Cc8i1I1h.js", contentType: "application/javascript; charset=utf-8", offset: 3217952, length: 2266, sha256: "1d21ad008921942217c9eac0c35b1713773b9d89c71e3ab4412781f7bb88f463" },
168817
+ { key: "assets/webviewBridgeHost-U7EnNQhQ.js", contentType: "application/javascript; charset=utf-8", offset: 3220218, length: 9781, sha256: "38dc9521ea546e2a9df2832916f07cda0179a60d5aa40fdd3f5af6e6fda5c620" },
168818
+ { key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset: 3229999, length: 4610, sha256: "994062dd7af4186a739de55dd9e151c63b6301f8e2cbafc608d35c2e87da0cd2" },
168819
+ { key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset: 3234609, length: 488584, sha256: "d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134" },
168820
+ { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 3723193, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
168821
+ { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 3814117, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
168822
+ { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 3905101, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
168823
+ { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 3996081, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
168824
+ { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 4086953, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
168825
+ { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 4177933, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
168826
+ { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 4286569, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
168827
+ { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 4395653, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
168828
+ { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 4504701, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
168829
+ { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 4612401, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
168830
+ { key: "himi-sw.js", contentType: "application/javascript; charset=utf-8", offset: 4700509, length: 6748, sha256: "4a92459977d7cefa1a6a7e020c3a63509737f083b3f2773557c1a5771665811a" },
168831
+ { key: "index.html", contentType: "text/html; charset=utf-8", offset: 4707257, length: 4947, sha256: "c371161e8847353be43f370a3103a51d47bc3d3b980c04e703ad1e5ce1dff2e5" },
168832
+ { key: "ios-glass-preview.css", contentType: "text/css; charset=utf-8", offset: 4712204, length: 7193, sha256: "a482f4796147c2a3893942e10ab225bd3b6f749f7125fe0330680d4c20ea0212" },
168833
+ { key: "ios-glass-preview.svg", contentType: "image/svg+xml", offset: 4719397, length: 423, sha256: "b9cd5989d31464a0422f260a332af6be5add0b04de2148944de35158f3b75efc" },
168834
+ { key: "kit-tab-bar.css", contentType: "text/css; charset=utf-8", offset: 4719820, length: 1171, sha256: "9e2c3a0faaf05d5471badf167a4d3bdf1c4e6dd65c432eea6d254158bfd99585" },
168835
+ { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 4720991, length: 18778, sha256: "ba734d58c88281c71c01d9a2842a991d06f3ed91bf03449427ef11c7f6d1605d" }
168086
168836
  ];
168087
168837
  }
168088
168838
  });
@@ -168101,7 +168851,7 @@ __export(run_exports, {
168101
168851
  runPackage: () => runPackage,
168102
168852
  withoutProdServe: () => withoutProdServe
168103
168853
  });
168104
- import { cpSync as cpSync2, existsSync as existsSync83, mkdirSync as mkdirSync39, mkdtempSync as mkdtempSync7, readFileSync as readFileSync93, rmSync as rmSync23, statSync as statSync24 } from "node:fs";
168854
+ import { cpSync as cpSync2, existsSync as existsSync84, mkdirSync as mkdirSync39, mkdtempSync as mkdtempSync7, readFileSync as readFileSync93, rmSync as rmSync23, statSync as statSync24 } from "node:fs";
168105
168855
  import { networkInterfaces as osNetworkInterfaces, tmpdir as tmpdir8 } from "node:os";
168106
168856
  import { dirname as dirname44, join as join89 } from "node:path";
168107
168857
  import { fileURLToPath as fileURLToPath29 } from "node:url";
@@ -168131,9 +168881,9 @@ async function fetchBytes(url) {
168131
168881
  }
168132
168882
  async function resolvePackage(source, workDir) {
168133
168883
  const isUrl2 = /^https?:\/\//i.test(source);
168134
- if (!isUrl2 && existsSync83(source) && statSync24(source).isDirectory()) {
168884
+ if (!isUrl2 && existsSync84(source) && statSync24(source).isDirectory()) {
168135
168885
  const appDirManifest = join89(source, "release-manifest.json");
168136
- if (existsSync83(appDirManifest)) {
168886
+ if (existsSync84(appDirManifest)) {
168137
168887
  const opened2 = openPackageDir(source);
168138
168888
  if (!opened2.validation.ok) {
168139
168889
  throw new Error(`package is not valid:
@@ -168191,7 +168941,7 @@ async function loadPreviewAssets() {
168191
168941
  // in-repo checkout
168192
168942
  ];
168193
168943
  for (const path2 of candidates) {
168194
- if (!existsSync83(path2)) continue;
168944
+ if (!existsSync84(path2)) continue;
168195
168945
  const blob = readFileSync93(path2);
168196
168946
  return mod.assemblePreviewAssetsFromBlob(new Uint8Array(blob.buffer, blob.byteOffset, blob.byteLength));
168197
168947
  }
@@ -168330,7 +169080,7 @@ __export(run_browser_exports, {
168330
169080
  runInBrowser: () => runInBrowser
168331
169081
  });
168332
169082
  import { createServer as createServer6 } from "node:http";
168333
- import { existsSync as existsSync84, readFileSync as readFileSync94 } from "node:fs";
169083
+ import { existsSync as existsSync85, readFileSync as readFileSync94 } from "node:fs";
168334
169084
  import { spawnSync as spawnSync5 } from "node:child_process";
168335
169085
  import { dirname as dirname45, resolve as resolve69 } from "node:path";
168336
169086
  import { fileURLToPath as fileURLToPath30 } from "node:url";
@@ -168338,7 +169088,7 @@ function stagedDir() {
168338
169088
  return process.env.HIMI_BROWSER_PLANE_OUT ? resolve69(process.env.HIMI_BROWSER_PLANE_OUT) : resolve69(REPO2, "packages", "serve", "dist", "browser-plane");
168339
169089
  }
168340
169090
  function missingStaged() {
168341
- return [...SERVED].filter((f2) => !existsSync84(resolve69(stagedDir(), f2))).sort();
169091
+ return [...SERVED].filter((f2) => !existsSync85(resolve69(stagedDir(), f2))).sort();
168342
169092
  }
168343
169093
  function ensureBrowserPlaneStaged() {
168344
169094
  if (missingStaged().length === 0) return { ok: true, detail: "already staged" };
@@ -168428,7 +169178,7 @@ async function runInBrowser(releaseRoot, app, header, opts = {}) {
168428
169178
  }
168429
169179
  const name = path2 === "/" || path2 === "/index.html" ? "host.html" : path2.slice(1);
168430
169180
  if (SERVED.has(name)) {
168431
- if (!existsSync84(resolve69(stagedDir(), name))) {
169181
+ if (!existsSync85(resolve69(stagedDir(), name))) {
168432
169182
  const restaged = ensureBrowserPlaneStaged();
168433
169183
  if (!restaged.ok) {
168434
169184
  res.writeHead(503, { "content-type": "application/json" });
@@ -168491,14 +169241,14 @@ var hhp_preview_exports = {};
168491
169241
  __export(hhp_preview_exports, {
168492
169242
  hhpPreviewResponse: () => hhpPreviewResponse
168493
169243
  });
168494
- import { existsSync as existsSync85, readFileSync as readFileSync95 } from "node:fs";
169244
+ import { existsSync as existsSync86, readFileSync as readFileSync95 } from "node:fs";
168495
169245
  import { join as join90 } from "node:path";
168496
169246
  function hhpPreviewResponse(root, request) {
168497
- if (new URL(request.url).pathname !== "/__himi/hhp-preview" || !existsSync85(join90(root, "hhp.json"))) return null;
169247
+ if (new URL(request.url).pathname !== "/__himi/hhp-preview" || !existsSync86(join90(root, "hhp.json"))) return null;
168498
169248
  if (request.method !== "GET") return new Response(null, { status: 405 });
168499
169249
  try {
168500
169250
  const file2 = localPath(root, ".himi/hhp-preview.json");
168501
- const authored2 = existsSync85(file2) ? JSON.parse(readFileSync95(file2, "utf8")) : {};
169251
+ const authored2 = existsSync86(file2) ? JSON.parse(readFileSync95(file2, "utf8")) : {};
168502
169252
  if (authored2.mockCapabilities && (!Array.isArray(authored2.mockCapabilities) || authored2.mockCapabilities.some((v2) => typeof v2 !== "string"))) throw new Error("mockCapabilities must be a string array.");
168503
169253
  const fixtures = authored2.fixtures ?? {};
168504
169254
  if (typeof fixtures !== "object" || Array.isArray(fixtures) || fixtures === null) throw new Error("fixtures must be an object.");
@@ -171195,7 +171945,7 @@ __export(credential_profile_exports, {
171195
171945
  profilePath: () => profilePath,
171196
171946
  resolveStoreCredentials: () => resolveStoreCredentials
171197
171947
  });
171198
- import { existsSync as existsSync87, readFileSync as readFileSync101 } from "node:fs";
171948
+ import { existsSync as existsSync88, readFileSync as readFileSync101 } from "node:fs";
171199
171949
  import { homedir as homedir11 } from "node:os";
171200
171950
  import { join as join93 } from "node:path";
171201
171951
  function credentialsDir(home = homedir11()) {
@@ -171239,7 +171989,7 @@ function resolveStoreCredentials(opts) {
171239
171989
  const env = opts.env ?? process.env;
171240
171990
  const home = opts.home ?? homedir11();
171241
171991
  const read = opts.readProfile ?? ((p2) => readFileSync101(p2, "utf8"));
171242
- const exists = opts.profileExists ?? existsSync87;
171992
+ const exists = opts.profileExists ?? existsSync88;
171243
171993
  const ios = cfg.ios ?? {};
171244
171994
  const flagName = opts.profileFlag?.trim();
171245
171995
  const named = namedProfile(cfg, opts.profileFlag);
@@ -171305,7 +172055,7 @@ var init_credential_profile = __esm({
171305
172055
 
171306
172056
  // ../store-release/iap-credentials.ts
171307
172057
  import { createHash as createHash45 } from "node:crypto";
171308
- import { existsSync as existsSync88, readFileSync as readFileSync102, realpathSync as realpathSync12 } from "node:fs";
172058
+ import { existsSync as existsSync89, readFileSync as readFileSync102, realpathSync as realpathSync12 } from "node:fs";
171309
172059
  import { homedir as homedir12 } from "node:os";
171310
172060
  function accountFingerprint(keyId, issuerId) {
171311
172061
  return `sha256:${createHash45("sha256").update(`${issuerId}:${keyId}`).digest("hex").slice(0, 16)}`;
@@ -171352,7 +172102,7 @@ function resolveIapCredentials(options) {
171352
172102
  env: {},
171353
172103
  home,
171354
172104
  readProfile: readFile3,
171355
- profileExists: options.exists ?? existsSync88
172105
+ profileExists: options.exists ?? existsSync89
171356
172106
  });
171357
172107
  assertCredentialOutsideRepo(`credential profile "${profile}"`, realpath(profilePath(profile, home)));
171358
172108
  assertCredentialOutsideRepo(`credential profile "${profile}" ascKeyPath`, canonicalKeyPath(creds.ascKeyPath, profile, realpath));
@@ -171857,7 +172607,7 @@ var init_store_spec = __esm({
171857
172607
  });
171858
172608
 
171859
172609
  // src/iap-config-edit.ts
171860
- import { existsSync as existsSync89, readFileSync as readFileSync104 } from "node:fs";
172610
+ import { existsSync as existsSync90, readFileSync as readFileSync104 } from "node:fs";
171861
172611
  import { basename as basename24, join as join94 } from "node:path";
171862
172612
  import ts9 from "typescript";
171863
172613
  function bindPurchasesAppInConfig(source, options) {
@@ -171938,7 +172688,7 @@ function capabilityFinding(app, fileName) {
171938
172688
  function withStoreBundle(dir, options) {
171939
172689
  if (options.storeBundleId) return options;
171940
172690
  const path2 = join94(dir, "store", "store.config.yaml");
171941
- if (!existsSync89(path2)) return options;
172691
+ if (!existsSync90(path2)) return options;
171942
172692
  const storeBundleId = parseStoreConfig(readFileSync104(path2, "utf8")).ios?.bundleId;
171943
172693
  return storeBundleId ? { ...options, storeBundleId } : options;
171944
172694
  }
@@ -172678,7 +173428,7 @@ var init_store_iap_screenshots = __esm({
172678
173428
  });
172679
173429
 
172680
173430
  // src/store-iap-screenshot-render.ts
172681
- import { existsSync as existsSync90, mkdtempSync as mkdtempSync9, readFileSync as readFileSync105, rmSync as rmSync25 } from "node:fs";
173431
+ import { existsSync as existsSync91, mkdtempSync as mkdtempSync9, readFileSync as readFileSync105, rmSync as rmSync25 } from "node:fs";
172682
173432
  import { tmpdir as tmpdir10 } from "node:os";
172683
173433
  import { join as join96 } from "node:path";
172684
173434
  function renderProblems(render, entityId) {
@@ -172741,7 +173491,7 @@ function createReviewScreenRenderer() {
172741
173491
  async capture(html, contentDir2) {
172742
173492
  const { pngPageHtml: pngPageHtml2, stabilizePngPage: stabilizePngPage2 } = await Promise.resolve().then(() => (init_render_descriptor(), render_descriptor_exports));
172743
173493
  const tokensPath = join96(contentDir2, "tokens.json");
172744
- const tokens2 = existsSync90(tokensPath) ? JSON.parse(readFileSync105(tokensPath, "utf8")) : null;
173494
+ const tokens2 = existsSync91(tokensPath) ? JSON.parse(readFileSync105(tokensPath, "utf8")) : null;
172745
173495
  const { width, height, scale } = REVIEW_SCREENSHOT_FRAME;
172746
173496
  const page = await (await (browser ??= launch())).newPage({ viewport: { width, height }, deviceScaleFactor: scale, colorScheme: "light" });
172747
173497
  try {
@@ -172812,166 +173562,6 @@ var init_serve_preview = __esm({
172812
173562
  }
172813
173563
  });
172814
173564
 
172815
- // src/site-analyze/rest.ts
172816
- var rest_exports = {};
172817
- __export(rest_exports, {
172818
- WIX_API: () => WIX_API3,
172819
- WixApiError: () => WixApiError2,
172820
- classifyHttp: () => classifyHttp,
172821
- compactWixstaticUrl: () => compactWixstaticUrl,
172822
- isGenericWixFavicon: () => isGenericWixFavicon,
172823
- makeTransport: () => makeTransport,
172824
- mediaUrlFromLogo: () => mediaUrlFromLogo,
172825
- ownerTransportFrom: () => ownerTransportFrom,
172826
- probeCall: () => probeCall,
172827
- resolveWixUrl: () => resolveWixUrl,
172828
- uploadMediaBytes: () => uploadMediaBytes,
172829
- visitorTransportFrom: () => visitorTransportFrom,
172830
- wixMediaFileId: () => wixMediaFileId
172831
- });
172832
- function resolveWixUrl(path2) {
172833
- if (/^https?:\/\//i.test(path2)) return path2;
172834
- return `${WIX_API3}${path2}`;
172835
- }
172836
- function classifyHttp(status, count2) {
172837
- if (status === 428) return "not-installed";
172838
- if (status === 404) return "wrong-path";
172839
- if (status && status >= 400) return "error";
172840
- return count2 > 0 ? "ok" : "empty";
172841
- }
172842
- function makeTransport(fetchImpl, auth, timeoutMs = DEFAULT_TIMEOUT_MS3) {
172843
- return async (method, path2, body) => {
172844
- const headers2 = { Accept: "application/json" };
172845
- if (auth?.token) headers2.Authorization = auth.token;
172846
- if (auth?.msid) headers2["wix-site-id"] = auth.msid;
172847
- if (body !== void 0) headers2["Content-Type"] = "application/json";
172848
- const res = await fetchImpl(resolveWixUrl(path2), {
172849
- method,
172850
- headers: headers2,
172851
- body: body === void 0 ? void 0 : JSON.stringify(body),
172852
- signal: AbortSignal.timeout(timeoutMs)
172853
- });
172854
- const text11 = await res.text();
172855
- let parsed = text11;
172856
- try {
172857
- parsed = text11 ? JSON.parse(text11) : null;
172858
- } catch {
172859
- }
172860
- if (!res.ok) throw new WixApiError2(res.status, method, path2, parsed);
172861
- return parsed;
172862
- };
172863
- }
172864
- function ownerTransportFrom(fetchImpl, owner) {
172865
- return makeTransport(fetchImpl, { token: owner.token, msid: owner.msid });
172866
- }
172867
- function visitorTransportFrom(fetchImpl, token, msid) {
172868
- return makeTransport(fetchImpl, { token, msid });
172869
- }
172870
- async function probeCall(call, method, path2, body) {
172871
- try {
172872
- return { data: await call(method, path2, body), err: null };
172873
- } catch (e2) {
172874
- if (e2 instanceof WixApiError2) return { data: null, err: e2 };
172875
- throw e2;
172876
- }
172877
- }
172878
- function mediaUrlFromLogo(logo) {
172879
- const s2 = (logo ?? "").trim();
172880
- if (!s2) return null;
172881
- if (/^https?:\/\//i.test(s2)) return s2;
172882
- const id = s2.replace(/^wix:image:\/\/v1\//, "").split("/")[0].split("#")[0];
172883
- if (!id) return null;
172884
- if (/^https?:\/\//i.test(id)) return id;
172885
- return `https://static.wixstatic.com/media/${id}`;
172886
- }
172887
- function isGenericWixFavicon(url) {
172888
- try {
172889
- const h2 = new URL(url).hostname.toLowerCase();
172890
- return h2 === "wix.com" || h2.endsWith(".wix.com");
172891
- } catch {
172892
- return false;
172893
- }
172894
- }
172895
- function wixMediaFileId(url) {
172896
- const m2 = url.match(/static\.wixstatic\.com\/media\/([^/?#]+)/i);
172897
- return m2?.[1] ? decodeURIComponent(m2[1]) : void 0;
172898
- }
172899
- function compactWixstaticUrl(url, maxEdge = 800) {
172900
- if (!/static\.wixstatic\.com\/media\//i.test(url)) return url;
172901
- if (/\.(svg|ico)(\?|#|$)/i.test(url.split("?")[0] ?? url)) return url;
172902
- const w2 = url.match(/(?:\/|,)w_(\d+)/)?.[1];
172903
- if (w2 && Number(w2) <= maxEdge) return url;
172904
- const id = wixMediaFileId(url);
172905
- if (!id) return url;
172906
- return `https://static.wixstatic.com/media/${id}/v1/fill/w_${maxEdge},h_${maxEdge},al_c,q_80,enc_auto/file.jpg`;
172907
- }
172908
- async function uploadMediaBytes(call, fetchImpl, bytes2, fileName, mimeType) {
172909
- const { uploadUrl } = await call(
172910
- "POST",
172911
- "/site-media/v1/files/generate-upload-url",
172912
- { mimeType, fileName: `himi-business-book/${fileName}` }
172913
- );
172914
- const put = await fetchImpl(`${uploadUrl}?filename=${encodeURIComponent(fileName)}`, {
172915
- method: "PUT",
172916
- headers: { "Content-Type": mimeType },
172917
- body: bytes2,
172918
- signal: AbortSignal.timeout(12e4)
172919
- });
172920
- if (!put.ok) throw new Error(`media upload PUT failed: ${put.status}`);
172921
- const payload = await put.json();
172922
- const file2 = payload.file ?? payload;
172923
- const id = file2?.id ?? file2?.fileId;
172924
- const url = file2?.url ?? (id ? `https://static.wixstatic.com/media/${id}` : void 0);
172925
- if (!id || !url) throw new Error("media upload returned no file id");
172926
- return { id, url };
172927
- }
172928
- var WIX_API3, DEFAULT_TIMEOUT_MS3, WixApiError2;
172929
- var init_rest = __esm({
172930
- "src/site-analyze/rest.ts"() {
172931
- WIX_API3 = "https://www.wixapis.com";
172932
- DEFAULT_TIMEOUT_MS3 = 8e3;
172933
- WixApiError2 = class extends Error {
172934
- constructor(status, method, path2, body) {
172935
- super(`${method} ${path2} \u2192 ${status}`);
172936
- this.status = status;
172937
- this.method = method;
172938
- this.path = path2;
172939
- this.body = body;
172940
- this.name = "WixApiError";
172941
- }
172942
- };
172943
- }
172944
- });
172945
-
172946
- // src/site-analyze/visitor-auth.ts
172947
- var visitor_auth_exports = {};
172948
- __export(visitor_auth_exports, {
172949
- mintVisitorToken: () => mintVisitorToken
172950
- });
172951
- async function mintVisitorToken(fetchImpl, clientId) {
172952
- const res = await fetchImpl(`${WIX_API3}/oauth2/token`, {
172953
- method: "POST",
172954
- headers: { "Content-Type": "application/json", Accept: "application/json" },
172955
- body: JSON.stringify({ clientId, grantType: "anonymous" }),
172956
- signal: AbortSignal.timeout(8e3)
172957
- });
172958
- const text11 = await res.text();
172959
- let parsed = text11;
172960
- try {
172961
- parsed = text11 ? JSON.parse(text11) : null;
172962
- } catch {
172963
- }
172964
- if (!res.ok) throw new WixApiError2(res.status, "POST", "/oauth2/token", parsed);
172965
- const token = parsed?.access_token ?? parsed?.accessToken;
172966
- if (!token) throw new Error("visitor mint returned no access_token");
172967
- return token;
172968
- }
172969
- var init_visitor_auth = __esm({
172970
- "src/site-analyze/visitor-auth.ts"() {
172971
- init_rest();
172972
- }
172973
- });
172974
-
172975
173565
  // src/store-iap.ts
172976
173566
  var store_iap_exports = {};
172977
173567
  __export(store_iap_exports, {
@@ -174183,7 +174773,7 @@ __export(preflight_app_exports, {
174183
174773
  profileAccount: () => profileAccount,
174184
174774
  readXcconfigVars: () => readXcconfigVars
174185
174775
  });
174186
- import { readFileSync as readFileSync107, existsSync as existsSync91, readdirSync as readdirSync38, statSync as statSync25 } from "node:fs";
174776
+ import { readFileSync as readFileSync107, existsSync as existsSync92, readdirSync as readdirSync38, statSync as statSync25 } from "node:fs";
174187
174777
  import { createHash as createHash47 } from "node:crypto";
174188
174778
  import { dirname as dirname48, join as join98 } from "node:path";
174189
174779
  function analyze(projectYml, storeConfig, icon, account) {
@@ -174310,7 +174900,7 @@ function readXcconfigVars(iosDir, projectYml) {
174310
174900
  const vars = {};
174311
174901
  const seen = /* @__PURE__ */ new Set();
174312
174902
  const read = (path2) => {
174313
- if (seen.has(path2) || !existsSync91(path2)) return;
174903
+ if (seen.has(path2) || !existsSync92(path2)) return;
174314
174904
  seen.add(path2);
174315
174905
  for (const raw of readFileSync107(path2, "utf8").split("\n")) {
174316
174906
  const inc = /^\s*#include\??\s+"([^"]+)"/.exec(raw);
@@ -174339,8 +174929,8 @@ function profileAccount(app, storeConfig, opts = {}) {
174339
174929
  }
174340
174930
  }
174341
174931
  async function preflightApp(app, opts = {}) {
174342
- const projectYml = existsSync91(iosProjectYml(app)) ? readFileSync107(iosProjectYml(app), "utf8") : "";
174343
- const storeConfig = existsSync91(storeConfigPath(app)) ? readFileSync107(storeConfigPath(app), "utf8") : "";
174932
+ const projectYml = existsSync92(iosProjectYml(app)) ? readFileSync107(iosProjectYml(app), "utf8") : "";
174933
+ const storeConfig = existsSync92(storeConfigPath(app)) ? readFileSync107(storeConfigPath(app), "utf8") : "";
174344
174934
  const identity = projectYml ? analyzeStoreIdentity(projectYml, storeConfig, readXcconfigVars(join98(appDir(app), "ios"), projectYml)) : [];
174345
174935
  if (!storeConfig) return [{ level: "error", message: `no apps/${app}/store/store.config.yaml \u2014 run /setup-store-signing first.` }, ...identity];
174346
174936
  const findings = analyze(
@@ -174378,15 +174968,15 @@ function analyzeSubmissionRecord(appLevel, review, opts) {
174378
174968
  function appLevelMetadataFiles(app, locale = "en-US") {
174379
174969
  const root = join98(storeDir(app), "metadata");
174380
174970
  const out2 = /* @__PURE__ */ new Set();
174381
- if (existsSync91(root)) {
174971
+ if (existsSync92(root)) {
174382
174972
  for (const n2 of readdirSync38(root)) if (n2.endsWith(".txt")) out2.add(n2);
174383
174973
  }
174384
- if (existsSync91(join98(root, locale, "privacy_url.txt"))) out2.add("privacy_url.txt");
174974
+ if (existsSync92(join98(root, locale, "privacy_url.txt"))) out2.add("privacy_url.txt");
174385
174975
  return out2;
174386
174976
  }
174387
174977
  function reviewInfoFiles(app) {
174388
174978
  const dir = join98(storeDir(app), "review_information");
174389
- if (!existsSync91(dir)) return /* @__PURE__ */ new Set();
174979
+ if (!existsSync92(dir)) return /* @__PURE__ */ new Set();
174390
174980
  return new Set(readdirSync38(dir).filter((n2) => n2.endsWith(".txt")));
174391
174981
  }
174392
174982
  function isValidAppStoreSize(w2, h2) {
@@ -174533,20 +175123,20 @@ function analyzeListing(metaFiles, shots) {
174533
175123
  }
174534
175124
  function metadataFilesPresent(app, locale = "en-US") {
174535
175125
  const dir = join98(storeDir(app), "metadata", locale);
174536
- if (!existsSync91(dir)) return /* @__PURE__ */ new Set();
175126
+ if (!existsSync92(dir)) return /* @__PURE__ */ new Set();
174537
175127
  return new Set(readdirSync38(dir).filter((n2) => n2.endsWith(".txt")));
174538
175128
  }
174539
175129
  function listScreenshots(app, locale = "en-US") {
174540
175130
  const out2 = [];
174541
175131
  const flat = join98(storeDir(app), "screenshots", locale);
174542
- if (existsSync91(flat)) {
175132
+ if (existsSync92(flat)) {
174543
175133
  for (const png of readdirSync38(flat).filter((n2) => n2.endsWith(".png"))) {
174544
175134
  const sz = pngSize2(readFileSync107(join98(flat, png)));
174545
175135
  if (sz) out2.push({ name: png, w: sz.w, h: sz.h });
174546
175136
  }
174547
175137
  }
174548
175138
  const legacy = join98(storeDir(app), "metadata", locale, "screenshots");
174549
- if (existsSync91(legacy)) {
175139
+ if (existsSync92(legacy)) {
174550
175140
  for (const deviceDir of readdirSync38(legacy)) {
174551
175141
  const d2 = join98(legacy, deviceDir);
174552
175142
  if (!statSync25(d2).isDirectory()) continue;
@@ -174560,7 +175150,7 @@ function listScreenshots(app, locale = "en-US") {
174560
175150
  }
174561
175151
  function placeholderHashes2() {
174562
175152
  const templateIos = join98(appDir("_template"), "ios");
174563
- if (!existsSync91(templateIos)) return [LEGACY_PLACEHOLDER_SHA2562];
175153
+ if (!existsSync92(templateIos)) return [LEGACY_PLACEHOLDER_SHA2562];
174564
175154
  for (const target of readdirSync38(templateIos)) {
174565
175155
  const p2 = join98(templateIos, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
174566
175156
  try {
@@ -174596,7 +175186,7 @@ async function pixelIssues(bytes2) {
174596
175186
  }
174597
175187
  }
174598
175188
  async function appIconState(iosDir) {
174599
- if (!existsSync91(iosDir)) return { exists: false, isPlaceholder: false, storeIssues: [] };
175189
+ if (!existsSync92(iosDir)) return { exists: false, isPlaceholder: false, storeIssues: [] };
174600
175190
  for (const target of readdirSync38(iosDir)) {
174601
175191
  const p2 = join98(iosDir, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
174602
175192
  try {
@@ -174732,6 +175322,19 @@ var init_asc_status = __esm({
174732
175322
  }
174733
175323
  });
174734
175324
 
175325
+ // ../../core/serve-control/src/captcha-bindable.ts
175326
+ var captcha_bindable_exports = {};
175327
+ __export(captcha_bindable_exports, {
175328
+ captchaBindable: () => captchaBindable
175329
+ });
175330
+ function captchaBindable(shell, externalContract) {
175331
+ return !externalContract && ["branded-lite", "owner-lite"].includes(shell);
175332
+ }
175333
+ var init_captcha_bindable = __esm({
175334
+ "../../core/serve-control/src/captcha-bindable.ts"() {
175335
+ }
175336
+ });
175337
+
174735
175338
  // src/browser-login.ts
174736
175339
  import { createServer as createServer7 } from "node:http";
174737
175340
  import { randomBytes as randomBytes6 } from "node:crypto";
@@ -175663,7 +176266,7 @@ function headers(session) {
175663
176266
  ...session ? { "X-Admin-Session": session } : {}
175664
176267
  };
175665
176268
  }
175666
- function truncate2(token) {
176269
+ function truncate3(token) {
175667
176270
  return token.length <= 20 ? token : `${token.slice(0, 8)}\u2026${token.slice(-8)}`;
175668
176271
  }
175669
176272
  function parseDataFlag(raw) {
@@ -175789,7 +176392,7 @@ async function runNotify(pos, flags, io2, deps = {}) {
175789
176392
  const bits = [
175790
176393
  String(t2.id).padStart(4),
175791
176394
  t2.platform.padEnd(8),
175792
- truncate2(t2.token).padEnd(19),
176395
+ truncate3(t2.token).padEnd(19),
175793
176396
  (t2.environment ?? "-").padEnd(11),
175794
176397
  (t2.appVersion ?? "-").padEnd(10),
175795
176398
  t2.lastSeen,
@@ -176001,7 +176604,7 @@ __export(base44_adopt_exports, {
176001
176604
  renderAdoptModule: () => renderAdoptModule,
176002
176605
  runBase44Adopt: () => runBase44Adopt
176003
176606
  });
176004
- import { existsSync as existsSync95, readFileSync as readFileSync114, writeFileSync as writeFileSync38 } from "node:fs";
176607
+ import { existsSync as existsSync96, readFileSync as readFileSync114, writeFileSync as writeFileSync38 } from "node:fs";
176005
176608
  import { join as join104, resolve as resolve74 } from "node:path";
176006
176609
  function prop(entity, key3) {
176007
176610
  const props = entity.schema?.properties;
@@ -176110,7 +176713,7 @@ function runBase44Adopt(opts) {
176110
176713
  const issues = validateBase44Entities({ entities: result.entities, functions: result.functions }, opts.app);
176111
176714
  if (opts.write === void 0 || opts.write === false || issues.some((i2) => i2.severity === "error")) return { result, module, issues };
176112
176715
  const target = typeof opts.write === "string" ? resolve74(opts.cwd, opts.write) : join104(opts.cwd, ADOPT_MODULE_FILENAME);
176113
- if (existsSync95(target)) {
176716
+ if (existsSync96(target)) {
176114
176717
  throw new AdoptError("adopt_target_exists", `${target} already exists \u2014 adopt never overwrites. Delete or rename it, or pass --write <other path>.`, 1, { path: target });
176115
176718
  }
176116
176719
  writeFileSync38(target, module);
@@ -176359,7 +176962,7 @@ __export(generate_exports, {
176359
176962
  writeGenerated: () => writeGenerated
176360
176963
  });
176361
176964
  import { createHash as createHash50 } from "node:crypto";
176362
- import { existsSync as existsSync96, mkdirSync as mkdirSync42, readdirSync as readdirSync39, readFileSync as readFileSync115, writeFileSync as writeFileSync39 } from "node:fs";
176965
+ import { existsSync as existsSync97, mkdirSync as mkdirSync42, readdirSync as readdirSync39, readFileSync as readFileSync115, writeFileSync as writeFileSync39 } from "node:fs";
176363
176966
  import { dirname as dirname51, join as join105 } from "node:path";
176364
176967
  function withHeader(body) {
176365
176968
  return `${GENERATED_HEADER}${sha2566(body)}
@@ -176486,7 +177089,7 @@ function writeGenerated(dir, files, opts = {}) {
176486
177089
  const abs = join105(dir, f2.path);
176487
177090
  const next = withHeader(f2.body);
176488
177091
  let outcome;
176489
- if (!existsSync96(abs)) outcome = "written";
177092
+ if (!existsSync97(abs)) outcome = "written";
176490
177093
  else {
176491
177094
  const cur = readFileSync115(abs, "utf8");
176492
177095
  if (cur === next) outcome = "unchanged";
@@ -176505,14 +177108,14 @@ function orphanedFiles(dir, current) {
176505
177108
  const keep = new Set(current.map((f2) => f2.path));
176506
177109
  const found = [];
176507
177110
  const t5 = join105(dir, "tier5-src");
176508
- if (!existsSync96(t5)) return found;
177111
+ if (!existsSync97(t5)) return found;
176509
177112
  const candidates = readdirSync39(t5).filter((d2) => d2.startsWith("b44-")).map((d2) => `tier5-src/${d2}/index.ts`);
176510
177113
  const shared = join105(t5, "_shared");
176511
- if (existsSync96(shared)) {
177114
+ if (existsSync97(shared)) {
176512
177115
  for (const f2 of readdirSync39(shared)) if (/^b44-.*-plan\.ts$/.test(f2)) candidates.push(`tier5-src/_shared/${f2}`);
176513
177116
  }
176514
177117
  for (const rel of candidates.sort()) {
176515
- if (keep.has(rel) || !existsSync96(join105(dir, rel))) continue;
177118
+ if (keep.has(rel) || !existsSync97(join105(dir, rel))) continue;
176516
177119
  if (readFileSync115(join105(dir, rel), "utf8").startsWith(GENERATED_HEADER)) found.push(rel);
176517
177120
  }
176518
177121
  return found;
@@ -176551,7 +177154,7 @@ __export(base44_auth_exports, {
176551
177154
  usableBase44Auth: () => usableBase44Auth,
176552
177155
  writeBase44Session: () => writeBase44Session
176553
177156
  });
176554
- import { chmodSync as chmodSync4, existsSync as existsSync97, mkdirSync as mkdirSync43, readFileSync as readFileSync116, rmSync as rmSync27, writeFileSync as writeFileSync40 } from "node:fs";
177157
+ import { chmodSync as chmodSync4, existsSync as existsSync98, mkdirSync as mkdirSync43, readFileSync as readFileSync116, rmSync as rmSync27, writeFileSync as writeFileSync40 } from "node:fs";
176555
177158
  import { homedir as homedir15 } from "node:os";
176556
177159
  import { dirname as dirname52, join as join106 } from "node:path";
176557
177160
  function base44ApiBase(env = process.env) {
@@ -176562,7 +177165,7 @@ function base44SessionPath(home = homedir15()) {
176562
177165
  }
176563
177166
  function readBase44Session(home) {
176564
177167
  const p2 = base44SessionPath(home);
176565
- if (!existsSync97(p2)) return void 0;
177168
+ if (!existsSync98(p2)) return void 0;
176566
177169
  try {
176567
177170
  const s2 = JSON.parse(readFileSync116(p2, "utf8"));
176568
177171
  return typeof s2.accessToken === "string" && s2.accessToken ? s2 : void 0;
@@ -176580,7 +177183,7 @@ function writeBase44Session(session, home) {
176580
177183
  }
176581
177184
  function deleteBase44Session(home) {
176582
177185
  const p2 = base44SessionPath(home);
176583
- if (!existsSync97(p2)) return false;
177186
+ if (!existsSync98(p2)) return false;
176584
177187
  rmSync27(p2, { force: true });
176585
177188
  return true;
176586
177189
  }
@@ -176683,7 +177286,7 @@ function hasBase44WriteScope(auth) {
176683
177286
  }
176684
177287
  function importBase44CliSession(home = homedir15(), env = process.env) {
176685
177288
  const src = join106(home, ".base44", "auth", "auth.json");
176686
- if (!existsSync97(src)) throw new Error(`no Base44 CLI session at ${src} \u2014 run \`npx base44 login\` first, or use \`himi base44 login\``);
177289
+ if (!existsSync98(src)) throw new Error(`no Base44 CLI session at ${src} \u2014 run \`npx base44 login\` first, or use \`himi base44 login\``);
176687
177290
  const a2 = JSON.parse(readFileSync116(src, "utf8"));
176688
177291
  if (typeof a2.accessToken !== "string" || !a2.accessToken) throw new Error(`${src} holds no access token`);
176689
177292
  const session = {
@@ -176781,11 +177384,11 @@ __export(seed_exports, {
176781
177384
  seedBase44Entities: () => seedBase44Entities,
176782
177385
  writeBase44SeedRows: () => writeBase44SeedRows
176783
177386
  });
176784
- import { existsSync as existsSync98, readFileSync as readFileSync117, writeFileSync as writeFileSync41 } from "node:fs";
177387
+ import { existsSync as existsSync99, readFileSync as readFileSync117, writeFileSync as writeFileSync41 } from "node:fs";
176785
177388
  import { join as join107 } from "node:path";
176786
177389
  function readBase44SeedFile(dir) {
176787
177390
  const file2 = join107(dir, BASE44_SEED_FILE);
176788
- if (!existsSync98(file2)) return {};
177391
+ if (!existsSync99(file2)) return {};
176789
177392
  let parsed;
176790
177393
  try {
176791
177394
  parsed = JSON.parse(readFileSync117(file2, "utf8"));
@@ -176945,7 +177548,7 @@ function writeBase44SeedRows(opts) {
176945
177548
  return { ok: false, path: path2, entities: {}, agentPrompt: "", next: [], note: opts.only ? `--only ${opts.only.join(",")} matched no owned entity` : `no owned Base44 entities declared \u2014 add one with \`name\` (physically ${base44Prefix(app)}<Name>). Adopted entities are never seeded.` };
176946
177549
  }
176947
177550
  let existing = {};
176948
- if (existsSync98(path2)) {
177551
+ if (existsSync99(path2)) {
176949
177552
  let parsed;
176950
177553
  try {
176951
177554
  parsed = JSON.parse(readFileSync117(path2, "utf8"));
@@ -177300,7 +177903,7 @@ __export(functions_exports2, {
177300
177903
  markerContent: () => markerContent,
177301
177904
  readFunctionSource: () => readFunctionSource
177302
177905
  });
177303
- import { existsSync as existsSync99, lstatSync as lstatSync22 } from "node:fs";
177906
+ import { existsSync as existsSync100, lstatSync as lstatSync22 } from "node:fs";
177304
177907
  import { join as join108 } from "node:path";
177305
177908
  function markerContent(app) {
177306
177909
  return `${JSON.stringify({ app, by: "himi" })}
@@ -177309,7 +177912,7 @@ function markerContent(app) {
177309
177912
  function readFunctionSource(appDir3, name, app) {
177310
177913
  const rel = `base44/functions/${name}/`;
177311
177914
  const folder = join108(appDir3, "base44", "functions", name);
177312
- if (!existsSync99(folder) || !lstatSync22(folder).isDirectory()) throw new FunctionSourceError("function_source_missing", `no source folder at ${rel}`);
177915
+ if (!existsSync100(folder) || !lstatSync22(folder).isDirectory()) throw new FunctionSourceError("function_source_missing", `no source folder at ${rel}`);
177313
177916
  const { entries, skipped } = collectAppSource(folder);
177314
177917
  if (skipped.length) throw new FunctionSourceError("function_source_unsafe", `${rel} holds paths himi will not upload (symlinks or denied names): ${skipped.join(", ")} \u2014 remove them`);
177315
177918
  const secrets = secretFindings(entries);
@@ -177464,9 +178067,9 @@ function propsOf2(schema) {
177464
178067
  function isOwnedPhysical(name, app) {
177465
178068
  return name.startsWith(base44Prefix(app));
177466
178069
  }
177467
- function foreignGuard(snapshot2, next, owned) {
178070
+ function foreignGuard(snapshot3, next, owned) {
177468
178071
  const out2 = [];
177469
- for (const e2 of snapshot2) {
178072
+ for (const e2 of snapshot3) {
177470
178073
  if (owned.has(e2.name)) continue;
177471
178074
  if (!Object.prototype.hasOwnProperty.call(next, e2.name)) {
177472
178075
  out2.push({ code: "would_delete_foreign_entity", entity: e2.name, detail: `"${e2.name}" is not himi's and would be left out of the full-set sync \u2014 Base44 would delete it and its rows` });
@@ -177503,20 +178106,20 @@ function inheritUndeclaredPermissions(desired, remote, spec) {
177503
178106
  if (f2.rls === void 0 && remoteProps[f2.key]?.rls !== void 0) desiredProps[f2.key].rls = remoteProps[f2.key].rls;
177504
178107
  }
177505
178108
  }
177506
- function planEntitySync(declared, snapshot2, opts) {
178109
+ function planEntitySync(declared, snapshot3, opts) {
177507
178110
  const { app, allowDestructive = false, applyPermissions = false, emptyAppOk = false } = opts;
177508
178111
  const plan = { next: {}, actions: [], refusals: [], warnings: [], owned: [] };
177509
- if (snapshot2.length === 0 && !emptyAppOk) {
178112
+ if (snapshot3.length === 0 && !emptyAppOk) {
177510
178113
  plan.refusals.push({ code: "schema_snapshot_empty", detail: "the project download holds no entity schemas \u2014 if the Base44 app really has no entities, pass --empty-app-ok" });
177511
178114
  }
177512
178115
  const specs = declared.filter((s2) => !!s2 && typeof s2 === "object");
177513
178116
  const owned = new Map(specs.filter(isOwnedEntity).map((s2) => [physicalEntityName(s2, app), s2]));
177514
178117
  const adopted = new Set(specs.filter(isAdoptedEntity).map((s2) => physicalEntityName(s2, app)));
177515
- const live3 = new Map(snapshot2.map((e2) => [e2.name, e2]));
178118
+ const live3 = new Map(snapshot3.map((e2) => [e2.name, e2]));
177516
178119
  const provisioned = new Set((opts.provisioned ?? []).filter((n2) => isOwnedPhysical(n2, app)));
177517
- const ownedHere = /* @__PURE__ */ new Set([...snapshot2.map((e2) => e2.name).filter((n2) => provisioned.has(n2)), ...[...owned.keys()].filter((n2) => !live3.has(n2))]);
178120
+ const ownedHere = /* @__PURE__ */ new Set([...snapshot3.map((e2) => e2.name).filter((n2) => provisioned.has(n2)), ...[...owned.keys()].filter((n2) => !live3.has(n2))]);
177518
178121
  plan.owned = [...ownedHere].sort();
177519
- for (const e2 of snapshot2) {
178122
+ for (const e2 of snapshot3) {
177520
178123
  if (!ownedHere.has(e2.name)) {
177521
178124
  plan.next[e2.name] = e2.schema;
177522
178125
  if (owned.has(e2.name)) {
@@ -177580,7 +178183,7 @@ function planEntitySync(declared, snapshot2, opts) {
177580
178183
  for (const name of adopted) {
177581
178184
  if (!live3.has(name)) plan.warnings.push(`adopted entity "${name}" is not on the live app \u2014 himi never creates an entity it does not own`);
177582
178185
  }
177583
- plan.refusals.push(...foreignGuard(snapshot2, plan.next, ownedHere));
178186
+ plan.refusals.push(...foreignGuard(snapshot3, plan.next, ownedHere));
177584
178187
  return plan;
177585
178188
  }
177586
178189
  var BUILTINS2;
@@ -177647,12 +178250,12 @@ __export(apply_exports, {
177647
178250
  createBase44Entities: () => createBase44Entities,
177648
178251
  fileLedger: () => fileLedger
177649
178252
  });
177650
- import { existsSync as existsSync100, readFileSync as readFileSync118, writeFileSync as writeFileSync42 } from "node:fs";
178253
+ import { existsSync as existsSync101, readFileSync as readFileSync118, writeFileSync as writeFileSync42 } from "node:fs";
177651
178254
  import { join as join109 } from "node:path";
177652
178255
  function fileLedger(dir, appId2) {
177653
178256
  const path2 = join109(dir, LEDGER_FILE2);
177654
178257
  const load3 = () => {
177655
- if (!existsSync100(path2)) return {};
178258
+ if (!existsSync101(path2)) return {};
177656
178259
  let v2;
177657
178260
  try {
177658
178261
  v2 = JSON.parse(readFileSync118(path2, "utf8"));
@@ -180697,7 +181300,7 @@ var init_analyze = __esm({
180697
181300
  });
180698
181301
 
180699
181302
  // src/base44-analyze/write-artifacts.ts
180700
- import { existsSync as existsSync101, mkdirSync as mkdirSync45, readFileSync as readFileSync119, rmSync as rmSync29, writeFileSync as writeFileSync44 } from "node:fs";
181303
+ import { existsSync as existsSync102, mkdirSync as mkdirSync45, readFileSync as readFileSync119, rmSync as rmSync29, writeFileSync as writeFileSync44 } from "node:fs";
180701
181304
  import { dirname as dirname53, join as join111, resolve as resolve75, sep as sep20 } from "node:path";
180702
181305
  function isBookFolder(dir) {
180703
181306
  try {
@@ -180788,7 +181391,7 @@ function writeBase44Book(result, outDir, opts = {}) {
180788
181391
  const md = renderBookMd(book);
180789
181392
  assertNoSecrets(json8);
180790
181393
  assertNoSecrets(md);
180791
- const owned = ["book.json", "BOOK.md", "source", "screenshots"].filter((n2) => existsSync101(join111(out2, n2)));
181394
+ const owned = ["book.json", "BOOK.md", "source", "screenshots"].filter((n2) => existsSync102(join111(out2, n2)));
180792
181395
  if (owned.length) {
180793
181396
  if (!isBookFolder(out2)) throw new Error(`refusing to write the app book into ${out2}: it already has ${owned.join(", ")} that ${owned.length === 1 ? "is" : "are"} not from an app book \u2014 pick an empty --out`);
180794
181397
  for (const d2 of ["source", "screenshots"]) rmSync29(join111(out2, d2), { recursive: true, force: true });
@@ -184864,11 +185467,11 @@ async function collectOneApp(input, deps = {}) {
184864
185467
  const enriched = {};
184865
185468
  const contextWarnings = [];
184866
185469
  for (const [index, platform] of ["ios", "android"].entries()) {
184867
- const snapshot2 = snapshots[index];
184868
- if (snapshot2.status === "fulfilled") {
184869
- enriched[platform] = snapshot2.value;
185470
+ const snapshot3 = snapshots[index];
185471
+ if (snapshot3.status === "fulfilled") {
185472
+ enriched[platform] = snapshot3.value;
184870
185473
  } else {
184871
- const error = snapshot2.reason;
185474
+ const error = snapshot3.reason;
184872
185475
  if (!(error instanceof OneAppError) || ![
184873
185476
  "source_not_found",
184874
185477
  "source_request_failed",
@@ -187349,7 +187952,7 @@ var init_customer_build = __esm({
187349
187952
  });
187350
187953
 
187351
187954
  // src/site-analyze/apply.ts
187352
- import { existsSync as existsSync103, readFileSync as readFileSync121, writeFileSync as writeFileSync47, copyFileSync as copyFileSync2, mkdirSync as mkdirSync48, realpathSync as realpathSync15, statSync as statSync27 } from "node:fs";
187955
+ import { existsSync as existsSync104, readFileSync as readFileSync121, writeFileSync as writeFileSync47, copyFileSync as copyFileSync2, mkdirSync as mkdirSync48, realpathSync as realpathSync15, statSync as statSync27 } from "node:fs";
187353
187956
  import { dirname as dirname55, isAbsolute as isAbsolute9, join as join115, resolve as resolve79, sep as sep21 } from "node:path";
187354
187957
  import { spawnSync as spawnSync6 } from "node:child_process";
187355
187958
  function unpairedRedirectNote(overlay) {
@@ -187365,7 +187968,7 @@ function committedShellProvisioning(path2) {
187365
187968
  function findRepoRoot(cwd) {
187366
187969
  let dir = cwd;
187367
187970
  for (let i2 = 0; i2 < 8; i2++) {
187368
- if (SHELL_NAMES.some((name) => existsSync103(join115(dir, shellAppDir(name), "package.json")))) return dir;
187971
+ if (SHELL_NAMES.some((name) => existsSync104(join115(dir, shellAppDir(name), "package.json")))) return dir;
187369
187972
  const next = dirname55(dir);
187370
187973
  if (next === dir) break;
187371
187974
  dir = next;
@@ -187469,7 +188072,7 @@ function sameKnownSite(previous, next) {
187469
188072
  function buildMergedContract(options) {
187470
188073
  const { appDir: appDir3, packageDir, overlay } = options;
187471
188074
  const committedPath = join115(appDir3, "provisioning.json");
187472
- if (!existsSync103(committedPath)) {
188075
+ if (!existsSync104(committedPath)) {
187473
188076
  throw new Error(`shell has no committed provisioning.json at ${committedPath} to build a contract from`);
187474
188077
  }
187475
188078
  const committed = JSON.parse(readFileSync121(committedPath, "utf8"));
@@ -187485,7 +188088,7 @@ function buildMergedContract(options) {
187485
188088
  const stage = (fromRel, toRel) => {
187486
188089
  const from = contained(packageDir, fromRel);
187487
188090
  const to2 = contained(join115(appDir3, STAGED), toRel.slice(STAGED.length + 1));
187488
- if (!from || !to2 || !existsSync103(from)) return void 0;
188091
+ if (!from || !to2 || !existsSync104(from)) return void 0;
187489
188092
  let real;
187490
188093
  let realRoot;
187491
188094
  try {
@@ -187508,7 +188111,7 @@ function buildMergedContract(options) {
187508
188111
  const icon = stage("media/icon.png", `${STAGED}/icon.png`);
187509
188112
  if (icon) branding.appIconPath = icon;
187510
188113
  const facesPath = join115(packageDir, "media/fonts/faces.json");
187511
- if (existsSync103(facesPath)) {
188114
+ if (existsSync104(facesPath)) {
187512
188115
  let faces = [];
187513
188116
  try {
187514
188117
  const parsed = JSON.parse(readFileSync121(facesPath, "utf8"));
@@ -187570,7 +188173,7 @@ function staticFaqFor(overlay, overlayPath) {
187570
188173
  const own6 = overlay.faq;
187571
188174
  if (own6 !== void 0) return deriveStaticFaq(own6);
187572
188175
  const bookPath = join115(dirname55(resolve79(overlayPath)), "book.json");
187573
- if (!existsSync103(bookPath)) return void 0;
188176
+ if (!existsSync104(bookPath)) return void 0;
187574
188177
  try {
187575
188178
  const book = JSON.parse(readFileSync121(bookPath, "utf8"));
187576
188179
  const copy = book?.copy;
@@ -187587,7 +188190,7 @@ function staticGalleriesFor(overlay, overlayPath) {
187587
188190
  overlay.galleries.map((gallery) => ({ role: "gallery", title: gallery.title, galleryImageUrls: gallery.photos }))
187588
188191
  );
187589
188192
  const bookPath = join115(dirname55(resolve79(overlayPath)), "book.json");
187590
- if (!existsSync103(bookPath)) return void 0;
188193
+ if (!existsSync104(bookPath)) return void 0;
187591
188194
  try {
187592
188195
  const book = JSON.parse(readFileSync121(bookPath, "utf8"));
187593
188196
  if (!book.look || book.look.unavailable || !Array.isArray(book.look.pages)) return void 0;
@@ -187621,7 +188224,7 @@ async function applyOverlays(input) {
187621
188224
  }
187622
188225
  const appDir3 = join115(repoRoot2, shellAppDir(shell));
187623
188226
  const committedPath = join115(appDir3, "provisioning.json");
187624
- const committedSite = existsSync103(committedPath) ? JSON.parse(readFileSync121(committedPath, "utf8")).site : void 0;
188227
+ const committedSite = existsSync104(committedPath) ? JSON.parse(readFileSync121(committedPath, "utf8")).site : void 0;
187625
188228
  if (committedSite !== void 0 && overlay.site === void 0) {
187626
188229
  throw new Error(
187627
188230
  `shell "${shell}" is a site shell: its contract names the customer's website (a \`site\` block), and this overlay has none. Re-run \`himi site analyze --url <site> --shell ${shell}\` to derive the site's page map (edit \`site.pages\` in provisioning.overlay.json if needed), then --apply.`
@@ -187662,7 +188265,7 @@ async function applyOverlays(input) {
187662
188265
  };
187663
188266
  let packageFaq = faq;
187664
188267
  let packageGalleries = galleries;
187665
- if (existsSync103(pkgProv)) {
188268
+ if (existsSync104(pkgProv)) {
187666
188269
  const cur = JSON.parse(readFileSync121(pkgProv, "utf8"));
187667
188270
  if (galleries === void 0 && !sameKnownSite(cur, overlay)) overlay.galleries = [];
187668
188271
  const merged = deepMerge4(cur, overlay);
@@ -187680,7 +188283,7 @@ async function applyOverlays(input) {
187680
188283
  overlay.installedVerticals.push("galleries");
187681
188284
  }
187682
188285
  const pkgTokens = join115(cwd, "tokens.json");
187683
- if (existsSync103(pkgTokens) && (tokens2.colors || tokens2.typography)) {
188286
+ if (existsSync104(pkgTokens) && (tokens2.colors || tokens2.typography)) {
187684
188287
  const cur = JSON.parse(readFileSync121(pkgTokens, "utf8"));
187685
188288
  let tokensIn = tokens2;
187686
188289
  if (tokens2.typography) {
@@ -187707,7 +188310,7 @@ async function applyOverlays(input) {
187707
188310
  }
187708
188311
  const homeAction = homeRefreshActionId(shell);
187709
188312
  const homeSrc = join115(cwd, "dev/index.ts");
187710
- if (homeAction && existsSync103(homeSrc)) {
188313
+ if (homeAction && existsSync104(homeSrc)) {
187711
188314
  const prev = readFileSync121(homeSrc, "utf8");
187712
188315
  const patched = patchBrandParams(prev, overlay, homeAction);
187713
188316
  let next = patched.src;
@@ -187743,13 +188346,13 @@ async function applyOverlays(input) {
187743
188346
  notes.push(`${patched.unparsed} onAppear params block(s) in ${homeSrc} could not be read \u2014 any brand values inside them were not applied`);
187744
188347
  }
187745
188348
  }
187746
- if (!input.iconPath || !existsSync103(input.iconPath)) {
188349
+ if (!input.iconPath || !existsSync104(input.iconPath)) {
187747
188350
  const book = input.iconPath ? dirname55(dirname55(resolve79(input.iconPath))) : void 0;
187748
188351
  notes.push(
187749
188352
  book ? `no icon installed \u2014 ${siteLogoAbsence(book).hint}` : "no icon installed and no business book to say why \u2014 `himi icon generate` draws one from the accent, or `himi icon set <file.png>` installs the customer's own mark"
187750
188353
  );
187751
188354
  }
187752
- if (input.iconPath && existsSync103(input.iconPath)) {
188355
+ if (input.iconPath && existsSync104(input.iconPath)) {
187753
188356
  try {
187754
188357
  const installed = await installIcon(cwd, input.iconPath, { derivePlay: true });
187755
188358
  wrote.push(...installed.wrote);
@@ -188708,7 +189311,7 @@ __export(cli_exports3, {
188708
189311
  runSiteAnalyze: () => runSiteAnalyze,
188709
189312
  runSiteFunctionCli: () => runSiteFunctionCli
188710
189313
  });
188711
- import { existsSync as existsSync104, readFileSync as readFileSync122 } from "node:fs";
189314
+ import { existsSync as existsSync105, readFileSync as readFileSync122 } from "node:fs";
188712
189315
  import { resolve as resolve80 } from "node:path";
188713
189316
  function applyNeedsClient(shell) {
188714
189317
  if (shell === void 0 || !SHELL_NAMES.includes(shell)) return true;
@@ -188776,7 +189379,7 @@ async function runSiteAnalyze(opts) {
188776
189379
  if (book?.skipped) result.warnings = [...result.warnings ?? [], book.skipped];
188777
189380
  const derived = deriveSiteShell({ siteUrl: result.book.input.siteUrl, look: result.book.look, kind, routes });
188778
189381
  const prevOverlayPath = resolve80(outDir, "provisioning.overlay.json");
188779
- const prevSite = existsSync104(prevOverlayPath) ? (() => {
189382
+ const prevSite = existsSync105(prevOverlayPath) ? (() => {
188780
189383
  try {
188781
189384
  return JSON.parse(readFileSync122(prevOverlayPath, "utf8")).site;
188782
189385
  } catch {
@@ -188797,7 +189400,7 @@ async function runSiteAnalyze(opts) {
188797
189400
  }
188798
189401
  const previousOverlay = resolve80(outDir, "provisioning.overlay.json");
188799
189402
  carryOverGoals(
188800
- existsSync104(previousOverlay) ? readFileSync122(previousOverlay, "utf8") : void 0,
189403
+ existsSync105(previousOverlay) ? readFileSync122(previousOverlay, "utf8") : void 0,
188801
189404
  result.provisioningOverlay
188802
189405
  );
188803
189406
  const ownerCall = ownerAuth ? ownerTransportFrom(fetchImpl, ownerAuth) : void 0;
@@ -188883,7 +189486,7 @@ async function runSiteFunctionCli(opts) {
188883
189486
  });
188884
189487
  }
188885
189488
  function base44BookRoutes(bookPath, siteUrl) {
188886
- if (!existsSync104(bookPath)) return void 0;
189489
+ if (!existsSync105(bookPath)) return void 0;
188887
189490
  try {
188888
189491
  const book = JSON.parse(readFileSync122(bookPath, "utf8"));
188889
189492
  if (book.kind !== "base44-app-book" || !Array.isArray(book.routes)) return void 0;
@@ -189140,7 +189743,7 @@ __export(site_create_exports, {
189140
189743
  runSiteList: () => runSiteList,
189141
189744
  writeProvisioningBinding: () => writeProvisioningBinding
189142
189745
  });
189143
- import { existsSync as existsSync105, readFileSync as readFileSync123, writeFileSync as writeFileSync48 } from "node:fs";
189746
+ import { existsSync as existsSync106, readFileSync as readFileSync123, writeFileSync as writeFileSync48 } from "node:fs";
189144
189747
  import { resolve as resolvePath2 } from "node:path";
189145
189748
  function oauthClientName(projectName) {
189146
189749
  return `${projectName} client`;
@@ -189289,7 +189892,7 @@ async function runSiteCreate(opts) {
189289
189892
  if (!wantOauthApp) return { ...base, nextSteps: nextSteps(metaSiteId) };
189290
189893
  return { ...base, clientId, redirectUri, nextSteps: nextSteps(metaSiteId, clientId) };
189291
189894
  }
189292
- function writeProvisioningBinding(target, binding2, fs2 = { existsSync: existsSync105, readFileSync: readFileSync123, writeFileSync: writeFileSync48 }) {
189895
+ function writeProvisioningBinding(target, binding2, fs2 = { existsSync: existsSync106, readFileSync: readFileSync123, writeFileSync: writeFileSync48 }) {
189293
189896
  const msid = binding2.siteId;
189294
189897
  const path2 = resolvePath2(target);
189295
189898
  const committed = committedShellProvisioning(path2);
@@ -190068,7 +190671,7 @@ __export(capture_exports, {
190068
190671
  nativeNotConfigured: () => nativeNotConfigured,
190069
190672
  variantWidth: () => variantWidth
190070
190673
  });
190071
- import { existsSync as existsSync106, mkdirSync as mkdirSync49, rmSync as rmSync31, writeFileSync as writeFileSync49 } from "node:fs";
190674
+ import { existsSync as existsSync107, mkdirSync as mkdirSync49, rmSync as rmSync31, writeFileSync as writeFileSync49 } from "node:fs";
190072
190675
  import { join as join116 } from "node:path";
190073
190676
  import { pathToFileURL as pathToFileURL8 } from "node:url";
190074
190677
  function variantWidth(variant) {
@@ -190081,7 +190684,7 @@ function frameFile(outDir, screen, variant, surface) {
190081
190684
  async function captureMockup(root, screen, entry, variant, outDir, session) {
190082
190685
  if (!entry.mockup) throw new MockupMissingError(`screen ${screen} declares no mockup in hhp.json`);
190083
190686
  const file2 = localPath(root, entry.mockup);
190084
- if (!existsSync106(file2)) throw new MockupMissingError(`screen ${screen}: mockup ${entry.mockup} does not exist`);
190687
+ if (!existsSync107(file2)) throw new MockupMissingError(`screen ${screen}: mockup ${entry.mockup} does not exist`);
190085
190688
  const own6 = session ?? new MockupSession();
190086
190689
  try {
190087
190690
  const png = await own6.shoot(file2, variant);
@@ -190389,8 +190992,8 @@ var init_score = __esm({
190389
190992
  });
190390
190993
 
190391
190994
  // ../visual-proof/evidence.mjs
190392
- import { existsSync as existsSync107, rmSync as rmSync34 } from "node:fs";
190393
- function resolveCaptionFont({ exists = existsSync107, env = process.env } = {}) {
190995
+ import { existsSync as existsSync108, rmSync as rmSync34 } from "node:fs";
190996
+ function resolveCaptionFont({ exists = existsSync108, env = process.env } = {}) {
190394
190997
  if (env?.VISUAL_PROOF_FONT) return env.VISUAL_PROOF_FONT;
190395
190998
  return CAPTION_FONT_CANDIDATES.find((p2) => exists(p2)) ?? null;
190396
190999
  }
@@ -190643,7 +191246,7 @@ __export(fidelity_exports, {
190643
191246
  himalayaRepoRoot: () => himalayaRepoRoot
190644
191247
  });
190645
191248
  import { execFileSync as execFileSync10 } from "node:child_process";
190646
- import { existsSync as existsSync108, realpathSync as realpathSync16 } from "node:fs";
191249
+ import { existsSync as existsSync109, realpathSync as realpathSync16 } from "node:fs";
190647
191250
  import { join as join121, relative as relative19, sep as sep22 } from "node:path";
190648
191251
  function himalayaRepoRoot(dir) {
190649
191252
  let top;
@@ -190652,7 +191255,7 @@ function himalayaRepoRoot(dir) {
190652
191255
  } catch {
190653
191256
  return null;
190654
191257
  }
190655
- if (!existsSync108(join121(top, "tools/judges/fidelity/JUDGE.md"))) return null;
191258
+ if (!existsSync109(join121(top, "tools/judges/fidelity/JUDGE.md"))) return null;
190656
191259
  const rel = relative19(realpathSync16(top), realpathSync16(dir));
190657
191260
  return rel.startsWith(`..${sep22}`) || rel === ".." ? null : top;
190658
191261
  }
@@ -190662,7 +191265,7 @@ function fidelityEnvelope(report3) {
190662
191265
  async function fidelityCommand(ctx) {
190663
191266
  const { io: io2, flags, print } = ctx;
190664
191267
  const dir = contentDir(flags);
190665
- if (!existsSync108(dir)) {
191268
+ if (!existsSync109(dir)) {
190666
191269
  io2.error(failure("fidelity_bad_flag", `content dir ${dir} does not exist`));
190667
191270
  return 2;
190668
191271
  }
@@ -190836,8 +191439,11 @@ var ServeCliClient = class {
190836
191439
  fetchTokens(app, release2) {
190837
191440
  return this.request("serve", "GET", `/v1/tokens?app=${encodeURIComponent(app)}${this.pinQ(release2)}`);
190838
191441
  }
190839
- fetchAppConfig(app, release2) {
190840
- return this.request("serve", "GET", `/v1/app-config/${encodeURIComponent(app)}${release2 ? `?release=${encodeURIComponent(release2)}` : ""}`);
191442
+ /** A pinned non-live [release] on a deployed plane needs [previewToken] (see `fetchScreen`). */
191443
+ fetchAppConfig(app, release2, previewToken) {
191444
+ return this.request("serve", "GET", `/v1/app-config/${encodeURIComponent(app)}${release2 ? `?release=${encodeURIComponent(release2)}` : ""}`, {
191445
+ ...previewToken ? { headers: { "x-himalaya-preview-token": previewToken } } : {}
191446
+ });
190841
191447
  }
190842
191448
  fetchBundle(app, hash2) {
190843
191449
  return this.request("serve", "GET", `/v1/bundles/${hash2}.bundle.js?app=${encodeURIComponent(app)}`);
@@ -191378,7 +191984,8 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
191378
191984
  "empty-app-ok",
191379
191985
  "aab",
191380
191986
  "managed",
191381
- "source-hash"
191987
+ "source-hash",
191988
+ "skip-captcha-check"
191382
191989
  ]);
191383
191990
  var SWITCH_FLAGS = new Set([...BOOLEAN_FLAGS].filter((name) => name !== "deep"));
191384
191991
  var SWITCH_CONSEQUENCE = {
@@ -192288,7 +192895,7 @@ var COMMANDS = [
192288
192895
  { name: "patch", summary: 'change ONE item of a published app \u2014 a screen descriptor, a Tier-5 bundle, tokens, or the app-config baseline \u2014 from a RAW FILE, with no content package and no build. The low-level door: it does not lint your package, because there is no package here; `himi push --only <selector>` is the same edit with the full build + lint gate and is what to reach for when the package is in hand. Derives a new release from the app\'s current LIVE release, or from `--from-release <id>`. An explicit `--draft` or `--live` is REQUIRED \u2014 a patch has no default blast radius \u2014 and `--notes` is required with `--live` on a screen or app-config patch, because off-repo `gitSha` is "dev" and the ledger notes are then the only durable record of bytes that correspond to no commit. A branch does not merge: activating one derived from an older release reverts every item the patch does not move, so that case is refused until `--accept-regressions`. A bundle patch must repoint a screen (`--for-screen`) or the bytes land under a manifest key nothing reads. It cannot ADD a screen (screens are git-only, RFC 0012), never claims a slug \u2014 the app must already be published \u2014 and carries no attestation, source archive, assets, icon or minBinaryVersion, each named in the output.', required: "screen <id> --file <descriptor.json> [--bundle <sha256|none>] | bundle --file <bundle.js> (--for-screen <id>[,<id>] | --no-rebind) | tokens --file <tokens.json> | app-config --file <app-config.json> ; (--draft|--live) --app <a> [--from-release <id>] [--accept-regressions] [--label <n>] [--notes <t>] [--force] [--allow-binary-gap] [--target <t>] (--control-token)" },
192289
192896
  { name: "flags", summary: "read and change the app's OPERATIONAL flags (RFC 0013) \u2014 `list` prints what the DEVICE door serves, `set <key> --definition` creates or replaces one, `ramp <key>` moves its rollout share or kills it, `rm <key>` deletes it and echoes the definition back so the removal is reversible. Every write is followed by a read of the same door the device uses, and the answer is reported as `servedNow`: flags are stored in the app's git-committed flags.json, so a control plane with no checkout accepts a write it will never serve.", required: "list|set|ramp|rm [<key>] [--definition <json|@file>] [--percent 0-100] [--enabled true|false] [--app <a>] (--control-token)" },
192290
192897
  { 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)" },
192291
- { 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 | brandy | base44 | player | demo-app) and defaults to the content package's himalaya.content.json `shell` (templates carry the one they were written for), else branded-lite. The per-app shells ADD the release's declared capabilities to the binary, while Himi Player and demo-app refuse a release declaring one they lack; `--plan` previews it without building; `brandy` is the site shell \u2014 the customer's own website as native-framed tabs. `--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 --site <id>` reuses an existing customer ad-hoc profile and certificate for iOS; requires an owned site and a completed personal signing binding. `--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). `--aab` builds an Android App Bundle (.aab) for the owner to upload to Google Play AND an APK from the same build \u2014 a download link for the .aab, an install link and QR for the APK; Android only; the bundle is signed with the Wix production key (`wix-keystore`, the upload key Branded apps use) \u2014 any other `--android-signing` is refused \u2014 and the APK with the committed QA key; a self-serve caller gets one only as the store build of its own Containers app (it must own the app's site, and `--aab` sends your Wix login); any other self-serve `--aab` gets 403 android_format_not_allowed. 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|brandy|base44|player|demo-app] [--signing wix-managed|byo] [--site <id>] [--android-signing qa-keystore|wix-keystore|debug] [--aab] [--borrow-ios-id <bundleId>] [--no-wait] [--force] [--plan] | status <jobId> [--target <t>] | watch <jobId> [--target <t>] [--interval <ms>] | list --app <a> [--target <t>] | cancel <jobId> [--target <t>]" },
192898
+ { 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 | brandy | base44 | player | demo-app) and defaults to the content package's himalaya.content.json `shell` (templates carry the one they were written for), else branded-lite. The per-app shells ADD the release's declared capabilities to the binary, while Himi Player and demo-app refuse a release declaring one they lack; `--plan` previews it without building; `brandy` is the site shell \u2014 the customer's own website as native-framed tabs. `--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 --site <id>` reuses an existing customer ad-hoc profile and certificate for iOS; requires an owned site and a completed personal signing binding. `--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). `--aab` builds an Android App Bundle (.aab) for the owner to upload to Google Play AND an APK from the same build \u2014 a download link for the .aab, an install link and QR for the APK; Android only; the bundle is signed with the Wix production key (`wix-keystore`, the upload key Branded apps use) \u2014 any other `--android-signing` is refused \u2014 and the APK with the committed QA key; a self-serve caller gets one only as the store build of its own Containers app (it must own the app's site, and `--aab` sends your Wix login); any other self-serve `--aab` gets 403 android_format_not_allowed. 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. Also refuses a release whose member login (WixConsumerAuthProvider) names no siteId, or not in lower case, when Wix says its site requires a member CAPTCHA \u2014 such a binary ships without the CAPTCHA key and every member sign-in fails; whatever it cannot read (the release, the site's setting) only warns and builds; `--skip-captcha-check` builds anyway", required: "[--app <a>] [--platform ios,android] [--release <id>] [--allow-draft] [--target <t>] [--shell branded-lite|owner-lite|brandy|base44|player|demo-app] [--signing wix-managed|byo] [--site <id>] [--android-signing qa-keystore|wix-keystore|debug] [--aab] [--borrow-ios-id <bundleId>] [--no-wait] [--force] [--skip-captcha-check] [--plan] | status <jobId> [--target <t>] | watch <jobId> [--target <t>] [--interval <ms>] | list --app <a> [--target <t>] | cancel <jobId> [--target <t>]" },
192292
192899
  { 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]" },
192293
192900
  { 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. `iap draft|plan|apply|status|connect|screenshots|check|mappings` registers an app owner's digital products as in-app purchases (non-consumables, or consumable price tiers): draft reads the Wix catalog and writes the manifest, plan and status only read, apply is the one App Store mutation boundary, connect readies the Wix site to sell them (purchases app, In-App Purchase key, appleIAP provider, product mappings; --preview-tag routes only its Serve calls to a deploy preview), legacy screenshots --profile renders each product's purchase screen from the app (--content) as a bound iPhone shows it to a signed-in member and names the 1290\xD72796 PNG as the item's App Review screenshot, and none of them builds, signs or needs a checkout (`himi docs iap-products`) IAP provisioning defaults to Catalog; managed apply generates screenshots on the server with no local .p8 or profile fallback; --managed is optional and --profile selects legacy mode; --catalog-route or HIMI_IAP_CATALOG_ROUTE has no default.", required: "preflight <app> [--profile <n>] | upload <app> [--track <t>] [--profile <n>] [--yes] [--dry-run] | status <app> [--profile <n>] | iap draft --site <msid> " + IAP_CREDENTIAL_OPTIONS + " --apple-app <id> --bundle <id> --base-territory <t> --out <f> [--territories <a,b>] [--locale <l>] [--mode per-item|tiers] [--merge <f>] [--report <f>] [--json] | iap plan --manifest <f> " + IAP_CREDENTIAL_OPTIONS + " --out <f> [--json] | iap apply --plan <f> " + IAP_CREDENTIAL_OPTIONS + " --out <f> [--yes] [--limit <n>] [--no-submit] [--json] | iap status --manifest <f> " + IAP_CREDENTIAL_OPTIONS + " [--out <f>] [--json] | iap connect --manifest <f> [--profile <n>] [--catalog-route <prefix>] [--iap-key <AuthKey.p8> --iap-key-id <id>] [--content <dir>] [--preview-tag dp-<tag>] [--dry-run] [--yes] [--out <f>] [--json] | iap screenshots --manifest <f> --content <dir> --profile <n> [--out-dir <d>] [--only <id,\u2026>] [--force] [--dry-run] [--json] | iap check --manifest <f> --catalog-route <prefix> [--purchases-app <id>] [--content <dir>] [--plist <file>] [--visitor-client <id>] [--json] | iap mappings --site <msid> --purchases-app <id> --catalog-route <prefix> [--product <id> --active true|false --yes] [--json]" },
192294
192901
  { name: "guide", summary: "print the Himalaya overview + headless dev loop + available topics (offline)", required: "[--json]" },
@@ -192899,7 +193506,7 @@ async function hhpCommand(ctx) {
192899
193506
  // src/commands/init.ts
192900
193507
  init_scaffold();
192901
193508
  init_store();
192902
- import { existsSync as existsSync45 } from "node:fs";
193509
+ import { existsSync as existsSync46 } from "node:fs";
192903
193510
  import { join as join44, resolve as resolve43 } from "node:path";
192904
193511
  init_cli_shared();
192905
193512
  async function adoptAtInit(dir) {
@@ -192926,7 +193533,7 @@ var NoBase44SlotError = class extends Error {
192926
193533
  };
192927
193534
  async function initFromRemoteTemplate(name, parentDir, template, c2, opts = {}) {
192928
193535
  const dir = resolve43(parentDir, name);
192929
- if (existsSync45(join44(dir, "himalaya.content.json"))) {
193536
+ if (existsSync46(join44(dir, "himalaya.content.json"))) {
192930
193537
  throw new Error(`content package already exists at ${dir}`);
192931
193538
  }
192932
193539
  const r3 = await c2.fetchTemplateSource(TEMPLATE_APP_PREFIX + template);
@@ -193002,7 +193609,7 @@ async function initCommand(ctx) {
193002
193609
  const owed = openApprovals2(readApprovals2(dir).events).length;
193003
193610
  next.push(`carried the planning journal into the app (${carried.join(", ")}${owed ? `; ${owed} approval${owed === 1 ? "" : "s"} still owed` : ""}) \u2014 \`himi progress --brief\` there shows it`);
193004
193611
  }
193005
- const planInParent = ["SPEC.md", "MOBILE-UX.md"].filter((f2) => existsSync45(join44(parentDir, f2)));
193612
+ const planInParent = ["SPEC.md", "MOBILE-UX.md"].filter((f2) => existsSync46(join44(parentDir, f2)));
193006
193613
  if (planInParent.length) {
193007
193614
  next.push(`${planInParent.join(" and ")} in ${parentDir} ${planInParent.length > 1 ? "are" : "is"} not the app's \u2014 if that is the approved plan, move it over the template's boilerplate in ${dir}`);
193008
193615
  }
@@ -193069,7 +193676,7 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
193069
193676
  }
193070
193677
 
193071
193678
  // src/commands/template.ts
193072
- import { mkdtempSync as mkdtempSync2, readFileSync as readFileSync67, existsSync as existsSync57, rmSync as rmSync16 } from "node:fs";
193679
+ import { mkdtempSync as mkdtempSync2, readFileSync as readFileSync67, existsSync as existsSync58, rmSync as rmSync16 } from "node:fs";
193073
193680
  import { createHash as createHash30 } from "node:crypto";
193074
193681
  import { tmpdir as tmpdir3 } from "node:os";
193075
193682
  import { join as join57, resolve as resolve46, basename as basename15 } from "node:path";
@@ -193136,7 +193743,7 @@ async function cmsIssues(dir, app, strict, opts) {
193136
193743
  // src/surface-lint.ts
193137
193744
  init_car();
193138
193745
  init_preview_surfaces();
193139
- import { existsSync as existsSync46, readFileSync as readFileSync55 } from "node:fs";
193746
+ import { existsSync as existsSync47, readFileSync as readFileSync55 } from "node:fs";
193140
193747
  import { join as join45 } from "node:path";
193141
193748
  var VALID_PLATFORM_KEYS2 = /* @__PURE__ */ new Set([
193142
193749
  ...PREVIEW_SURFACES.map((s2) => s2.platformKey).filter((k2) => k2 !== null),
@@ -193149,7 +193756,7 @@ function surfaceIssues(dir, surfaceNav, strict) {
193149
193756
  let platforms = {};
193150
193757
  let envelopeUnreadable = false;
193151
193758
  const p2 = join45(dir, "platforms.json");
193152
- if (existsSync46(p2)) {
193759
+ if (existsSync47(p2)) {
193153
193760
  let raw;
193154
193761
  try {
193155
193762
  raw = JSON.parse(readFileSync55(p2, "utf8"));
@@ -193182,7 +193789,7 @@ function surfaceIssues(dir, surfaceNav, strict) {
193182
193789
  }
193183
193790
  if (envelopeUnreadable) return issues;
193184
193791
  const configTs = join45(dir, "config.ts");
193185
- if (existsSync46(configTs)) {
193792
+ if (existsSync47(configTs)) {
193186
193793
  const declared = parseCarConfig(readFileSync55(configTs, "utf8")).category;
193187
193794
  const inEnvelope = platforms.androidauto === true;
193188
193795
  if (inEnvelope && !declared) {
@@ -193242,10 +193849,10 @@ async function fontIssues(dir, strict, opts = {}) {
193242
193849
  }
193243
193850
 
193244
193851
  // src/stores-api-lint.ts
193245
- import { existsSync as existsSync49, readdirSync as readdirSync26, readFileSync as readFileSync58 } from "node:fs";
193852
+ import { existsSync as existsSync50, readdirSync as readdirSync26, readFileSync as readFileSync58 } from "node:fs";
193246
193853
  import { join as join48 } from "node:path";
193247
193854
  function storesV1Issues(contentDir2, strict) {
193248
- const roots2 = [join48(contentDir2, "tier5-src"), join48(contentDir2, "dev")].filter(existsSync49);
193855
+ const roots2 = [join48(contentDir2, "tier5-src"), join48(contentDir2, "dev")].filter(existsSync50);
193249
193856
  const files = [];
193250
193857
  const visit = (dir) => {
193251
193858
  for (const entry of readdirSync26(dir, { withFileTypes: true })) {
@@ -193518,7 +194125,7 @@ async function templateCommand(ctx) {
193518
194125
  const result = { ...outcome.result, ...fromSpec };
193519
194126
  const adoptDir = contentDir(flags);
193520
194127
  const kept = flags["dry-run"] !== true && (outcome.code === 0 || outcome.result.forcedKeep === true);
193521
- if (kept && existsSync57(join57(adoptDir, adoptBits.ADOPT_FILE))) {
194128
+ if (kept && existsSync58(join57(adoptDir, adoptBits.ADOPT_FILE))) {
193522
194129
  try {
193523
194130
  const inv = adoptBits.inspectApp(adoptDir);
193524
194131
  adoptBits.writeInventory(adoptDir, inv, { companions: "if-missing" });
@@ -193903,16 +194510,16 @@ async function ejectCommand(ctx) {
193903
194510
  // src/commands/validate.ts
193904
194511
  init_wix_placeholders();
193905
194512
  init_lint_report();
193906
- import { readFileSync as readFileSync77, existsSync as existsSync66 } from "node:fs";
194513
+ import { readFileSync as readFileSync77, existsSync as existsSync67 } from "node:fs";
193907
194514
  import { join as join69 } from "node:path";
193908
194515
  init_token_lint();
193909
194516
 
193910
194517
  // src/icon-lint.ts
193911
194518
  init_icon2();
193912
- import { existsSync as existsSync60 } from "node:fs";
194519
+ import { existsSync as existsSync61 } from "node:fs";
193913
194520
  import { join as join60 } from "node:path";
193914
194521
  async function iconIssues(dir, strict, opts = {}) {
193915
- if (!existsSync60(join60(dir, "himalaya.content.json"))) return [];
194522
+ if (!existsSync61(join60(dir, "himalaya.content.json"))) return [];
193916
194523
  const status = await iconStatus(dir);
193917
194524
  const issue2 = (severity, message2) => ({
193918
194525
  screen: null,
@@ -193975,7 +194582,7 @@ async function nativeConfigAdvisories(app, configSource) {
193975
194582
  const { iosProjectYml: iosProjectYml2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
193976
194583
  const { androidOptedIn: androidOptedIn3, LABEL_IOS_SPLASH: LABEL_IOS_SPLASH2 } = await Promise.resolve().then(() => (init_splash(), splash_exports));
193977
194584
  const iosYmlPath = iosProjectYml2(app);
193978
- const iosYml = existsSync66(iosYmlPath) ? readFileSync77(iosYmlPath, "utf8") : "";
194585
+ const iosYml = existsSync67(iosYmlPath) ? readFileSync77(iosYmlPath, "utf8") : "";
193979
194586
  let optedIn = iosYml.includes(LABEL_IOS_SPLASH2);
193980
194587
  if (!optedIn) {
193981
194588
  const { androidManifestPath: androidManifestPath3 } = await Promise.resolve().then(() => (init_gen_native_config(), gen_native_config_exports));
@@ -194065,7 +194672,7 @@ import { readFileSync as readFileSync80 } from "node:fs";
194065
194672
 
194066
194673
  // src/dpx.ts
194067
194674
  import { spawnSync as spawnSync3 } from "node:child_process";
194068
- import { existsSync as existsSync67, readFileSync as readFileSync78 } from "node:fs";
194675
+ import { existsSync as existsSync68, readFileSync as readFileSync78 } from "node:fs";
194069
194676
  import { homedir as homedir9 } from "node:os";
194070
194677
  import { join as join70 } from "node:path";
194071
194678
  var BO_COOKIE = "WixBoAuthentication_1_19_0";
@@ -194093,7 +194700,7 @@ function dpxSessionTokenPath() {
194093
194700
  var DPX_SESSION_PORT = 5151;
194094
194701
  function dpxSessionPresent(path2 = dpxSessionTokenPath()) {
194095
194702
  try {
194096
- return existsSync67(path2) && readFileSync78(path2, "utf8").trim().length > 0;
194703
+ return existsSync68(path2) && readFileSync78(path2, "utf8").trim().length > 0;
194097
194704
  } catch {
194098
194705
  return false;
194099
194706
  }
@@ -194328,13 +194935,13 @@ async function mcpCommand(ctx) {
194328
194935
 
194329
194936
  // src/commands/studio.ts
194330
194937
  init_cli_shared();
194331
- import { mkdirSync as mkdirSync36, writeFileSync as writeFileSync30, existsSync as existsSync70 } from "node:fs";
194938
+ import { mkdirSync as mkdirSync36, writeFileSync as writeFileSync30, existsSync as existsSync71 } from "node:fs";
194332
194939
  import { join as join74, resolve as resolve60, basename as basename19, dirname as dirname42 } from "node:path";
194333
194940
  async function studioCommand(ctx) {
194334
194941
  const { io: io2, pos, flags, print } = ctx;
194335
194942
  const { openStudio: openStudio2 } = await Promise.resolve().then(() => (init_studio(), studio_exports));
194336
194943
  const dir = contentDir(flags);
194337
- if (!existsSync70(join74(dir, "himalaya.content.json"))) {
194944
+ if (!existsSync71(join74(dir, "himalaya.content.json"))) {
194338
194945
  io2.error(JSON.stringify({ ok: false, error: "not_a_content_package", dir, hint: "run from the app directory (or pass --content <dir>) \u2014 the board reads that package's .himi/" }));
194339
194946
  return 2;
194340
194947
  }
@@ -194394,7 +195001,7 @@ ${handover.hint[0].toUpperCase()}${handover.hint.slice(1)}.`);
194394
195001
 
194395
195002
  // src/commands/progress.ts
194396
195003
  init_cli_shared();
194397
- import { existsSync as existsSync71 } from "node:fs";
195004
+ import { existsSync as existsSync72 } from "node:fs";
194398
195005
  import { join as join75 } from "node:path";
194399
195006
  async function progressCommand2(ctx) {
194400
195007
  const { io: io2, pos, flags, print } = ctx;
@@ -194418,7 +195025,7 @@ async function progressCommand2(ctx) {
194418
195025
  } = await Promise.resolve().then(() => (init_progress(), progress_exports));
194419
195026
  const dir = contentDir(flags);
194420
195027
  const journal2 = journalPath2(dir);
194421
- const isContentPackage = existsSync71(join75(dir, "himalaya.content.json"));
195028
+ const isContentPackage = existsSync72(join75(dir, "himalaya.content.json"));
194422
195029
  const hint = isContentPackage ? {} : { hint: "no himalaya.content.json here \u2014 run from the app directory (or pass --content <dir>) so the build board finds this journal" };
194423
195030
  const message2 = pos.slice(1).join(" ").trim();
194424
195031
  const approvalFlags = ["approve", "done", "drop"].filter((f2) => flags[f2] !== void 0);
@@ -194608,7 +195215,7 @@ init_himi_report();
194608
195215
  init_attestation();
194609
195216
  init_wix_placeholders();
194610
195217
  init_lint_report();
194611
- import { existsSync as existsSync76, rmSync as rmSync21 } from "node:fs";
195218
+ import { existsSync as existsSync77, rmSync as rmSync21 } from "node:fs";
194612
195219
  import { join as join81 } from "node:path";
194613
195220
  init_crawl_layers();
194614
195221
  init_cli_shared();
@@ -194631,7 +195238,7 @@ async function testCommand(ctx) {
194631
195238
  const { io: io2, deps, pos, flags, print, serveBase } = ctx;
194632
195239
  const dir = contentDir(flags);
194633
195240
  const structuredOutput = flags.json === true || io2.isTTY !== true;
194634
- if (existsSync76(join81(dir, "functions"))) {
195241
+ if (existsSync77(join81(dir, "functions"))) {
194635
195242
  const { invokeLocalFunction: invokeLocalFunction2, loadFunctionsApp: loadFunctionsApp2 } = await Promise.resolve().then(() => (init_functions(), functions_exports));
194636
195243
  const loaded = await loadFunctionsApp2(dir);
194637
195244
  const results = [];
@@ -195296,7 +195903,7 @@ async function iconsCommand(ctx) {
195296
195903
 
195297
195904
  // src/commands/pull.ts
195298
195905
  init_cli_shared();
195299
- import { existsSync as existsSync78, readdirSync as readdirSync35, statSync as statSync21 } from "node:fs";
195906
+ import { existsSync as existsSync79, readdirSync as readdirSync35, statSync as statSync21 } from "node:fs";
195300
195907
  import { join as join84, resolve as resolve63 } from "node:path";
195301
195908
  async function pullCommand(ctx) {
195302
195909
  const { io: io2, pos, flags, print, client: client2 } = ctx;
@@ -195314,7 +195921,7 @@ async function pullCommand(ctx) {
195314
195921
  io2.error(JSON.stringify(linked));
195315
195922
  return 1;
195316
195923
  }
195317
- if (existsSync78(dest)) {
195924
+ if (existsSync79(dest)) {
195318
195925
  if (!statSync21(dest).isDirectory()) {
195319
195926
  io2.error(JSON.stringify({
195320
195927
  error: `${dest} exists and is not a directory`,
@@ -195327,7 +195934,7 @@ async function pullCommand(ctx) {
195327
195934
  io2.error(JSON.stringify({ error: `${dest} already exists and is not empty`, hint: "pass --force to write into it anyway (merging, and naming what it keeps), --replace to restore exactly what was archived, or --out/--name to land somewhere else" }));
195328
195935
  return 1;
195329
195936
  }
195330
- if (replace && occupied && !existsSync78(join84(dest, "himalaya.content.json"))) {
195937
+ if (replace && occupied && !existsSync79(join84(dest, "himalaya.content.json"))) {
195331
195938
  io2.error(JSON.stringify({
195332
195939
  error: `${dest} is not a content package \u2014 refusing to --replace it`,
195333
195940
  hint: "--replace only clears a directory that holds himalaya.content.json. Check --out/--name, or pass --force to merge into it instead."
@@ -195408,7 +196015,7 @@ async function pullCommand(ctx) {
195408
196015
 
195409
196016
  // src/commands/push.ts
195410
196017
  import { createHash as createHash41 } from "node:crypto";
195411
- import { existsSync as existsSync81 } from "node:fs";
196018
+ import { existsSync as existsSync82 } from "node:fs";
195412
196019
  import { join as join87, relative as relative17 } from "node:path";
195413
196020
  init_config();
195414
196021
  init_release();
@@ -195576,7 +196183,7 @@ async function pushCommand(ctx) {
195576
196183
  const payload = await loadReleaseFromDir(declared, out2);
195577
196184
  const oneAppEvidence = join87(dir, ".himi", "one-app");
195578
196185
  const oneAppCoverage = join87(dir, "ONE-APP-COVERAGE.json");
195579
- const oneAppMarked = existsSync81(join87(oneAppEvidence, "manifest.json")) || existsSync81(oneAppCoverage);
196186
+ const oneAppMarked = existsSync82(join87(oneAppEvidence, "manifest.json")) || existsSync82(oneAppCoverage);
195580
196187
  let oneAppCoverageCount = 0;
195581
196188
  let oneAppCoverageReady = false;
195582
196189
  let oneAppNativeProof;
@@ -196244,12 +196851,12 @@ async function packCommand(ctx) {
196244
196851
 
196245
196852
  // src/commands/import.ts
196246
196853
  init_cli_shared();
196247
- import { existsSync as existsSync82, readdirSync as readdirSync36, statSync as statSync23 } from "node:fs";
196854
+ import { existsSync as existsSync83, readdirSync as readdirSync36, statSync as statSync23 } from "node:fs";
196248
196855
  import { resolve as resolve67 } from "node:path";
196249
196856
  function restoreDestinationIssue(dest, force) {
196250
196857
  const link = symlinkDestinationIssue(dest);
196251
196858
  if (link) return link;
196252
- if (!existsSync82(dest)) return null;
196859
+ if (!existsSync83(dest)) return null;
196253
196860
  if (!statSync23(dest).isDirectory()) {
196254
196861
  return { error: `${dest} exists and is not a directory`, hint: "pass --out/--name to land somewhere else, or remove the file" };
196255
196862
  }
@@ -197441,7 +198048,7 @@ async function promoteCommand(ctx) {
197441
198048
  // src/commands/patch.ts
197442
198049
  init_lint_report();
197443
198050
  init_cli_shared();
197444
- import { readFileSync as readFileSync98, existsSync as existsSync86 } from "node:fs";
198051
+ import { readFileSync as readFileSync98, existsSync as existsSync87 } from "node:fs";
197445
198052
  import { createHash as createHash42 } from "node:crypto";
197446
198053
  var PATCH_HELP = `himi patch \u2014 change ONE item of a published app, from a raw file, on a machine
197447
198054
  that does not have the content package.
@@ -197520,7 +198127,7 @@ async function patchCommand(ctx) {
197520
198127
  io2.error(JSON.stringify({ error: `patch ${kind} needs --file`, usage: PATCH_USAGE }));
197521
198128
  return 2;
197522
198129
  }
197523
- if (!existsSync86(file2)) {
198130
+ if (!existsSync87(file2)) {
197524
198131
  io2.error(JSON.stringify({ error: `no such file: ${file2}` }));
197525
198132
  return 2;
197526
198133
  }
@@ -198081,7 +198688,7 @@ async function testflightCommand(ctx) {
198081
198688
  }
198082
198689
 
198083
198690
  // src/commands/dist.ts
198084
- import { existsSync as existsSync92 } from "node:fs";
198691
+ import { existsSync as existsSync93 } from "node:fs";
198085
198692
  import { join as join99 } from "node:path";
198086
198693
  init_wix_owner();
198087
198694
  init_cli_shared();
@@ -198121,7 +198728,7 @@ async function distCommand(ctx) {
198121
198728
  const rememberLastDist = async (jobs2) => {
198122
198729
  try {
198123
198730
  const dir = contentDir(flags);
198124
- if (!existsSync92(join99(dir, "himalaya.content.json"))) return;
198731
+ if (!existsSync93(join99(dir, "himalaya.content.json"))) return;
198125
198732
  const { lastDistFromJob: lastDistFromJob2, writeLastDist: writeLastDist2 } = await Promise.resolve().then(() => (init_capabilities(), capabilities_exports));
198126
198733
  const own6 = await appId(dir);
198127
198734
  for (const job of jobs2) {
@@ -198365,9 +198972,35 @@ ${label3}`);
198365
198972
  return 0;
198366
198973
  }
198367
198974
  const platform = str3(flags.platform)?.split(",").map((p2) => p2.trim()).filter(Boolean);
198975
+ const { captchaContentInput: captchaContentInput2, captchaDistGate: captchaDistGate2 } = await Promise.resolve().then(() => (init_captcha2(), captcha_exports));
198976
+ const captchaSiteId = str3(flags.site) ?? (await appId(contentDir(flags)) === app ? captchaContentInput2(contentDir(flags)).siteId : void 0);
198977
+ const { captchaBindable: captchaBindable2 } = await Promise.resolve().then(() => (init_captcha_bindable(), captcha_bindable_exports));
198978
+ const { DEFAULT_DIST_SHELL: DEFAULT_DIST_SHELL2 } = await Promise.resolve().then(() => (init_dist_jobs(), dist_jobs_exports));
198979
+ if (flags.force !== true && flags["skip-captcha-check"] !== true && captchaBindable2(distShell ?? DEFAULT_DIST_SHELL2, false)) {
198980
+ const verdict = await captchaDistGate2({
198981
+ client: c2,
198982
+ app,
198983
+ release: str3(flags.release),
198984
+ requestedSite: captchaSiteId,
198985
+ // The plane's own default when --platform is absent: Android (iOS for a customer TestFlight build).
198986
+ platforms: platform?.length ? platform : str3(flags.destination) === "testflight" ? ["ios"] : ["android"]
198987
+ });
198988
+ if (verdict.refuse) {
198989
+ print({
198990
+ ok: false,
198991
+ code: verdict.refuse.code,
198992
+ error: verdict.refuse.code,
198993
+ message: verdict.refuse.message,
198994
+ captchaPolicy: verdict.refuse.captchaPolicy,
198995
+ hint: "fix config.ts and `himi push`, then build that release: `himi dist --release <its id> --allow-draft` (a draft), or promote it first \u2014 or `himi dist --skip-captcha-check` to build without the member CAPTCHA key"
198996
+ });
198997
+ return 1;
198998
+ }
198999
+ if (verdict.advisory) (flags.json === true ? io2.error : io2.log)(`\u26A0 ${verdict.advisory}`);
199000
+ }
198368
199001
  {
198369
199002
  const distDir = contentDir(flags);
198370
- if (existsSync92(join99(distDir, "himalaya.content.json"))) {
199003
+ if (existsSync93(join99(distDir, "himalaya.content.json"))) {
198371
199004
  const issues = await iconIssues(distDir, flags.strict === true, { requireDeclared: true, requireVerified: true });
198372
199005
  const errors = issues.filter((i2) => i2.severity === "error");
198373
199006
  for (const i2 of issues.filter((i3) => i3.severity === "warning")) {
@@ -198384,8 +199017,6 @@ ${label3}`);
198384
199017
  }
198385
199018
  }
198386
199019
  }
198387
- const { captchaContentInput: captchaContentInput2 } = await Promise.resolve().then(() => (init_captcha2(), captcha_exports));
198388
- const captchaSiteId = str3(flags.site) ?? captchaContentInput2(contentDir(flags)).siteId;
198389
199020
  let wixAuthorization;
198390
199021
  const customerTestflight = str3(flags.signing)?.trim().toLowerCase() === "byo" && str3(flags.destination) === "testflight";
198391
199022
  if (str3(flags.signing)?.trim().toLowerCase() === "byo") {
@@ -199377,7 +200008,7 @@ ${report3.ok ? "OK \u2014 data + serve plane reachable." : typeof report3.hint =
199377
200008
  // src/commands/guide.ts
199378
200009
  init_guides();
199379
200010
  init_cli_shared();
199380
- import { existsSync as existsSync93 } from "node:fs";
200011
+ import { existsSync as existsSync94 } from "node:fs";
199381
200012
  import { join as join101, resolve as resolve72 } from "node:path";
199382
200013
  async function runGuideCommand(command, pos, flags, io2, print) {
199383
200014
  const { referenceCache: referenceCache2, referenceIdentity: referenceIdentity2 } = await Promise.resolve().then(() => (init_guides(), guides_exports));
@@ -199605,7 +200236,7 @@ Seed your coding agent with \`himi agent-init\`. Guides: ${idx.portalUrl}`);
199605
200236
  ...res.removed.length ? { removed: res.removed, note: "older copies at the app root, moved to .himi/legacy-agent-files/ (a backup, in case one became app code) \u2014 the current ones live in .agents/skills/himalaya/" } : {},
199606
200237
  // In a git repo the refresh moves the diff identity an earlier `himi test` attested (that
199607
200238
  // hash is shared with the repo gates and deliberately exempts nothing but its own metadata).
199608
- ...existsSync93(join101(dir, ".himi", "attestations", "latest.json")) ? { next: "if `himi push` then refuses the attestation as stale, re-run `himi test` \u2014 in a git checkout this refresh changed the tree it covered" } : {},
200239
+ ...existsSync94(join101(dir, ".himi", "attestations", "latest.json")) ? { next: "if `himi push` then refuses the attestation as stale, re-run `himi test` \u2014 in a git checkout this refresh changed the tree it covered" } : {},
199609
200240
  ...res.skipped.length ? { skipped: res.skipped } : {},
199610
200241
  portalUrl: idx.portalUrl
199611
200242
  });
@@ -199673,7 +200304,7 @@ init_schema2();
199673
200304
  // src/cms.ts
199674
200305
  init_cms_schema();
199675
200306
  init_wix_owner();
199676
- import { existsSync as existsSync94, readFileSync as readFileSync112, writeFileSync as writeFileSync36 } from "node:fs";
200307
+ import { existsSync as existsSync95, readFileSync as readFileSync112, writeFileSync as writeFileSync36 } from "node:fs";
199677
200308
  import { join as join102 } from "node:path";
199678
200309
  var FOREIGN_DETAIL_LIMIT = 25;
199679
200310
  var MAX_COLLECTION_PAGES = 40;
@@ -200106,7 +200737,7 @@ async function seedCms(opts) {
200106
200737
  }
200107
200738
  function readSeedFile(dir) {
200108
200739
  const file2 = join102(dir, "cms-seed.json");
200109
- if (!existsSync94(file2)) return {};
200740
+ if (!existsSync95(file2)) return {};
200110
200741
  let parsed;
200111
200742
  try {
200112
200743
  parsed = JSON.parse(readFileSync112(file2, "utf8"));
@@ -200168,7 +200799,7 @@ async function writeSeedRows(opts) {
200168
200799
  };
200169
200800
  }
200170
200801
  let existing = {};
200171
- if (existsSync94(file2)) {
200802
+ if (existsSync95(file2)) {
200172
200803
  let parsed;
200173
200804
  try {
200174
200805
  parsed = JSON.parse(readFileSync112(file2, "utf8"));
@@ -200483,7 +201114,7 @@ async function cmsCommand(ctx) {
200483
201114
 
200484
201115
  // src/commands/base44.ts
200485
201116
  init_cli_shared();
200486
- import { existsSync as existsSync102 } from "node:fs";
201117
+ import { existsSync as existsSync103 } from "node:fs";
200487
201118
  import { join as join113, resolve as resolve77 } from "node:path";
200488
201119
  async function base44Command(ctx) {
200489
201120
  const { io: io2, pos, flags, print } = ctx;
@@ -200555,7 +201186,7 @@ async function base44Command(ctx) {
200555
201186
  return 1;
200556
201187
  };
200557
201188
  const gen = await Promise.resolve().then(() => (init_generate(), generate_exports));
200558
- const missing3 = gen.ENGINE_FILES.filter((f2) => !existsSync102(join113(dir, f2)));
201189
+ const missing3 = gen.ENGINE_FILES.filter((f2) => !existsSync103(join113(dir, f2)));
200559
201190
  if (missing3.length) {
200560
201191
  return fail6("content_dir_not_base44_starter", `${dir} is not a base44-starter content package: the generated screens import a shared engine it does not have (${missing3.join(", ")})`, { missing: missing3, hint: "scaffold one with `himi init <name> --template base44-starter --base44-app-id <id>`" });
200561
201192
  }
@@ -200641,7 +201272,7 @@ async function base44Command(ctx) {
200641
201272
  if (!provisioning || str3(flags.content) !== void 0 || !slug) return contentDir(flags);
200642
201273
  if (!/^[a-z0-9][a-z0-9-]*$/.test(slug)) return void 0;
200643
201274
  const dir = resolve77("apps", slug);
200644
- return existsSync102(join113(dir, "config.ts")) || existsSync102(join113(dir, "config.mjs")) ? dir : void 0;
201275
+ return existsSync103(join113(dir, "config.ts")) || existsSync103(join113(dir, "config.mjs")) ? dir : void 0;
200645
201276
  };
200646
201277
  if (sub === "entities" || sub === "functions") {
200647
201278
  if (sub === "entities" && !["query", "create", "seed"].includes(pos[2] ?? "")) {