@absolutejs/absolute 0.20.0-beta.113 → 0.20.0-beta.114

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.
@@ -11,6 +11,7 @@ var UPDATE_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/u;
11
11
  var RELEASE_TARGET_PATTERN = /^[a-z0-9][a-z0-9._-]{0,63}$/u;
12
12
  var UPDATE_PUBLIC_KEY_PATTERN = /^[A-Za-z0-9+/]+={0,2}$/u;
13
13
  var ENVIRONMENT_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/u;
14
+ var COLOR_PATTERN = /^#[0-9A-F]{6}$/u;
14
15
  var DEFAULT_UPDATE_BOOT_TIMEOUT_MS = 20000;
15
16
  var DEFAULT_UPDATE_HEALTH_FAILURE_RATE = 0.2;
16
17
  var DEFAULT_UPDATE_HEALTH_MINIMUM_REPORTS = 20;
@@ -43,6 +44,58 @@ var resolveProjectPath = (projectRoot, value, field) => {
43
44
  }
44
45
  return path;
45
46
  };
47
+ var normalizeBrandingColor = (value, fallback, field) => {
48
+ const normalized = (value ?? fallback).trim().toUpperCase();
49
+ if (!COLOR_PATTERN.test(normalized))
50
+ throw new TypeError(`${field} must use #RRGGBB hexadecimal notation.`);
51
+ return normalized;
52
+ };
53
+ var normalizeBrandingPath = (projectRoot, value, field) => {
54
+ const path = resolveProjectPath(projectRoot, requireText(value, field), field);
55
+ if (!path.toLowerCase().endsWith(".png"))
56
+ throw new TypeError(`${field} must reference a PNG file.`);
57
+ return path;
58
+ };
59
+ var normalizeBranding = (config, projectRoot) => {
60
+ const { branding } = config;
61
+ if (!branding)
62
+ return;
63
+ const darkIcon = branding.ios?.darkIcon ? normalizeBrandingPath(projectRoot, branding.ios.darkIcon, "mobile.branding.ios.darkIcon") : undefined;
64
+ const tintedIcon = branding.ios?.tintedIcon ? normalizeBrandingPath(projectRoot, branding.ios.tintedIcon, "mobile.branding.ios.tintedIcon") : undefined;
65
+ const logoScale = branding.splash?.logoScale ?? 0.2;
66
+ if (!Number.isFinite(logoScale) || logoScale < 0.1 || logoScale > 0.4)
67
+ throw new TypeError("mobile.branding.splash.logoScale must be between 0.1 and 0.4.");
68
+ return {
69
+ android: {
70
+ backgroundColor: normalizeBrandingColor(branding.android?.backgroundColor, "#FFFFFF", "mobile.branding.android.backgroundColor"),
71
+ ...branding.android?.backgroundImage ? {
72
+ backgroundImage: normalizeBrandingPath(projectRoot, branding.android.backgroundImage, "mobile.branding.android.backgroundImage")
73
+ } : {},
74
+ ...branding.android?.foreground ? {
75
+ foreground: normalizeBrandingPath(projectRoot, branding.android.foreground, "mobile.branding.android.foreground")
76
+ } : {},
77
+ ...branding.android?.monochrome ? {
78
+ monochrome: normalizeBrandingPath(projectRoot, branding.android.monochrome, "mobile.branding.android.monochrome")
79
+ } : {}
80
+ },
81
+ icon: normalizeBrandingPath(projectRoot, branding.icon, "mobile.branding.icon"),
82
+ ios: {
83
+ ...darkIcon ? { darkIcon } : {},
84
+ ...tintedIcon ? { tintedIcon } : {}
85
+ },
86
+ splash: {
87
+ backgroundColor: normalizeBrandingColor(branding.splash?.backgroundColor, "#FFFFFF", "mobile.branding.splash.backgroundColor"),
88
+ darkBackgroundColor: normalizeBrandingColor(branding.splash?.darkBackgroundColor, "#111111", "mobile.branding.splash.darkBackgroundColor"),
89
+ ...branding.splash?.darkImage ? {
90
+ darkImage: normalizeBrandingPath(projectRoot, branding.splash.darkImage, "mobile.branding.splash.darkImage")
91
+ } : {},
92
+ ...branding.splash?.image ? {
93
+ image: normalizeBrandingPath(projectRoot, branding.splash.image, "mobile.branding.splash.image")
94
+ } : {},
95
+ logoScale
96
+ }
97
+ };
98
+ };
46
99
  var requireText = (value, field) => {
47
100
  const normalized = value.trim();
48
101
  if (!normalized)
@@ -445,11 +498,13 @@ var normalizeAbsoluteMobileConfig = (config, projectRoot) => {
445
498
  const updates = normalizeUpdates(config, productionOrigin, projectRoot);
446
499
  const updateServer = normalizeUpdateServer(config, productionOrigin, projectRoot, updates);
447
500
  const observability = normalizeObservability(config, productionOrigin);
501
+ const branding = normalizeBranding(config, projectRoot);
448
502
  return {
449
503
  androidCertificateFingerprints: normalizeCertificateFingerprints(config.deepLinks?.android?.sha256CertificateFingerprints),
450
504
  appId,
451
505
  appleAppIdPrefix: normalizeAppleAppIdPrefix(config.deepLinks?.apple?.appIdPrefix),
452
506
  appName: requireText(config.appName, "mobile.appName"),
507
+ ...branding ? { branding } : {},
453
508
  bundleDirectory: resolveProjectPath(projectRoot, config.bundleDirectory ?? ".absolutejs/mobile/web", "mobile.bundleDirectory"),
454
509
  deepLinkHosts: normalizeHosts(config.deepLinks?.hosts, productionOrigin),
455
510
  deepLinkScheme,
package/dist/cli/index.js CHANGED
@@ -58,7 +58,7 @@ if (command === "dev") {
58
58
  }
59
59
  const positionalArgs = stripNamedArgs("--config", "--android-device", "--ios-device").filter((arg) => arg !== "--no-mobile" && arg !== "--eager");
60
60
  const serverEntry = positionalArgs[0] ?? DEFAULT_SERVER_ENTRY;
61
- const { dev } = await import("./dev-f0safhsr.js");
61
+ const { dev } = await import("./dev-5cqmf7za.js");
62
62
  await dev(serverEntry, configPath, {
63
63
  androidDevice,
64
64
  eager: args.includes("--eager"),
@@ -71,7 +71,7 @@ if (command === "dev") {
71
71
  const configPath = parseNamedArg("--config");
72
72
  const positionalArgs = stripNamedArgs("--outdir", "--config").filter((arg) => arg !== "--prebuilt");
73
73
  const serverEntry = positionalArgs[0] ?? DEFAULT_SERVER_ENTRY;
74
- const { start } = await import("./start-8v6g2y31.js");
74
+ const { start } = await import("./start-jt61f40d.js");
75
75
  await start(serverEntry, outdir, configPath, {
76
76
  prebuilt: args.includes("--prebuilt")
77
77
  });
@@ -81,7 +81,7 @@ if (command === "dev") {
81
81
  const configPath = parseNamedArg("--config");
82
82
  const positionalArgs = stripNamedArgs("--outdir", "--config");
83
83
  const serverEntry = positionalArgs[0] ?? DEFAULT_SERVER_ENTRY;
84
- const { start } = await import("./start-8v6g2y31.js");
84
+ const { start } = await import("./start-jt61f40d.js");
85
85
  await start(serverEntry, outdir, configPath, { prepareOnly: true });
86
86
  } else if (command === "build") {
87
87
  sendTelemetryEvent("cli:command", { command });
@@ -197,13 +197,13 @@ if (command === "dev") {
197
197
  const configPath = parseNamedArg("--config");
198
198
  const positionalArgs = stripNamedArgs("--outdir", "--outfile", "--config");
199
199
  const serverEntry = positionalArgs[0] ?? DEFAULT_SERVER_ENTRY;
200
- const { compile } = await import("./compile-1d5arbqj.js");
200
+ const { compile } = await import("./compile-ya4kd2sg.js");
201
201
  await compile(serverEntry, outdir, outfile, configPath);
202
202
  } else if (command === "mobile") {
203
203
  sendTelemetryEvent("cli:command", {
204
204
  command: `mobile:${workspaceCommand ?? "unknown"}`
205
205
  });
206
- const { runMobile } = await import("./mobile-v11nwcj9.js");
206
+ const { runMobile } = await import("./mobile-55wjg3nd.js");
207
207
  try {
208
208
  await runMobile(args);
209
209
  } catch (error) {
@@ -238,7 +238,7 @@ if (command === "dev") {
238
238
  console.error(" prepare [entry] [--outdir dir] Build production assets and server without launching");
239
239
  console.error(" start [entry] [--outdir dir] [--prebuilt] Start production server");
240
240
  console.error(" compile [entry] [--outdir dir] [--outfile path] Compile standalone executable");
241
- console.error(" mobile <init|sync|inspect|ci|pair|remotes|doctor|test> Manage Capacitor apps and the experimental Expo hybrid shell");
241
+ console.error(" mobile <init|sync|assets|inspect|ci|pair|remotes|doctor|test> Manage Capacitor apps and the experimental Expo hybrid shell");
242
242
  console.error(" config [--port n] Open the unified config UI (ESLint, tsconfig, Prettier)");
243
243
  console.error(" db <backup|restore|seed> Backup/restore any Postgres DB (ORM-agnostic, upsert by PK) or run the seed script");
244
244
  console.error(" doctor [--fix] [--json] Diagnose the project (bun, type graph, config, framework dirs, env, port)");
@@ -7,12 +7,12 @@ import {
7
7
  } from "./index-zh6hhrwy.js";
8
8
  import {
9
9
  start
10
- } from "./index-gps0zk0m.js";
10
+ } from "./index-5fmgn0nx.js";
11
11
  import {
12
12
  ABSOLUTE_MOBILE_CLIENT_MANIFEST_FORMAT,
13
13
  ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION,
14
14
  resolveAbsoluteMobileRoute
15
- } from "./index-dfqzrznk.js";
15
+ } from "./index-6mbm4n3g.js";
16
16
  import"./index-bzs19w3r.js";
17
17
  import"./index-s2tazax7.js";
18
18
  import {
@@ -56,21 +56,25 @@ import {
56
56
  import"./index-w5vswatm.js";
57
57
  import {
58
58
  normalizeAbsoluteMobileConfig
59
- } from "./index-df2mjbdy.js";
59
+ } from "./index-exdd5k1g.js";
60
60
  import {
61
+ ABSOLUTE_CAPACITOR_ASSETS_SPEC,
61
62
  ABSOLUTE_MOBILE_UPDATE_FORMAT,
62
63
  absoluteDeviceNativeRequirements,
63
64
  absoluteMobileUpdateSigningPayload,
64
65
  assertAbsoluteDeviceCapabilityPackages,
65
66
  canonicalizeAbsoluteMobileUpdate,
66
67
  discoverAbsoluteSyncSchema,
68
+ generateAbsoluteCapacitorBranding,
69
+ inspectAbsoluteMobileBranding,
67
70
  parseAbsoluteMobileUpdateManifest,
71
+ renderAbsoluteMobileBrandingPreview,
68
72
  resolveAbsoluteDeviceCapabilityPlan,
69
73
  resolveAbsoluteMobileUpdateRuntime,
70
74
  syncAbsoluteExpoWebAssets,
71
75
  unsignedAbsoluteMobileUpdate,
72
76
  writeAbsoluteExpoProject
73
- } from "./index-0zcebhm4.js";
77
+ } from "./index-dr21p6ae.js";
74
78
  import {
75
79
  buildAbsoluteExpoAndroidWslBundle
76
80
  } from "./index-28nxv57v.js";
@@ -19779,6 +19783,14 @@ var mobileUpdateServerCheck = async (config, projectRoot) => {
19779
19783
  return fail("updates.trusted-server", error instanceof Error ? error.message : "The trusted mobile update server is not release-ready.", config.updateServer?.registryModule ?? "mobile.update.ts", "Run `absolute mobile update provision --storage s3 --force`, provision its environment variables on the trusted server, and rerun the release doctor.");
19780
19784
  }
19781
19785
  };
19786
+ var mobileBrandingCheck = async (config, projectRoot) => {
19787
+ const inspection = await inspectAbsoluteMobileBranding(config, projectRoot);
19788
+ if (inspection.status === "absent")
19789
+ return warn("mobile.branding", inspection.detail, undefined, "Configure mobile.branding and run `absolute mobile assets` before store submission.");
19790
+ if (!inspection.ready)
19791
+ return fail("mobile.branding", inspection.detail, inspection.manifestPath, "Run `absolute mobile assets`, review the generated preview, and commit the native resource changes.");
19792
+ return pass("mobile.branding", inspection.detail, inspection.manifestPath);
19793
+ };
19782
19794
  var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
19783
19795
  var readJsonObject = async (path) => {
19784
19796
  const value = JSON.parse(await readFile9(path, "utf8"));
@@ -20538,6 +20550,7 @@ var inspectAbsoluteMobileRelease = async (config, projectRoot) => {
20538
20550
  Promise.resolve(associationIdentityCheck(config, projectRoot)),
20539
20551
  dependencyLockCheck(projectRoot),
20540
20552
  config.engine === "expo" ? expoVersionCheck(config) : capacitorVersionCheck(config, projectRoot),
20553
+ mobileBrandingCheck(config, projectRoot),
20541
20554
  mobileUpdateServerCheck(config, projectRoot)
20542
20555
  ]);
20543
20556
  const checks = globalChecks.filter((check) => check !== undefined).map((check) => ({
@@ -24983,13 +24996,13 @@ var resolvedPackageVersion = async (projectRoot, packageName) => {
24983
24996
  }
24984
24997
  };
24985
24998
  var exactVersionFromSpec = (spec) => spec.slice(spec.lastIndexOf("@") + 1);
24986
- var installApprovedPackages = async (projectRoot, args, message, specs) => {
24999
+ var installApprovedPackages = async (projectRoot, args, message, specs, dev = false) => {
24987
25000
  if (specs.length === 0)
24988
25001
  return;
24989
25002
  const approved = args.includes("--yes") || await confirmInstall(message);
24990
25003
  if (!approved)
24991
- throw new TypeError(`Mobile initialization requires: bun add ${specs.join(" ")}`);
24992
- if (!installPackages(projectRoot, specs))
25004
+ throw new TypeError(`Mobile tooling requires: bun add${dev ? " --dev" : ""} ${specs.join(" ")}`);
25005
+ if (!installPackages(projectRoot, specs, dev))
24993
25006
  throw new TypeError("Failed to install the AbsoluteJS mobile toolchain.");
24994
25007
  };
24995
25008
  var packagesNeedingExactInstall = async (projectRoot, specs, installed, exactPackages) => (await Promise.all(specs.map(async (spec) => {
@@ -25010,6 +25023,11 @@ var ensureCapacitorPackages = async (projectRoot, args, mobile) => {
25010
25023
  const directCapabilityPackages = await directProjectPackages(projectRoot);
25011
25024
  const capabilityPackages = await packagesNeedingExactInstall(projectRoot, capabilityPlan.requiredPackages, directCapabilityPackages, new Set(capabilityPlan.requiredPackages.map(packageNameFromSpec)));
25012
25025
  await installApprovedPackages(projectRoot, args, `AbsoluteJS detected native device capabilities (${capabilityPlan.capabilities.join(", ")}). Install only their required Capacitor plugins now?`, capabilityPackages);
25026
+ if (mobile?.branding) {
25027
+ const installedBrandingPackages = await directProjectPackages(projectRoot);
25028
+ const brandingPackages = await packagesNeedingExactInstall(projectRoot, [ABSOLUTE_CAPACITOR_ASSETS_SPEC], installedBrandingPackages, new Set(["@capacitor/assets"]));
25029
+ await installApprovedPackages(projectRoot, args, "AbsoluteJS mobile branding uses the pinned official Capacitor asset generator. Install it as a development dependency now?", brandingPackages, true);
25030
+ }
25013
25031
  };
25014
25032
  var valueAfter = (args, flag) => {
25015
25033
  const index = args.indexOf(flag);
@@ -25234,6 +25252,8 @@ var initialize = async (args) => {
25234
25252
  if (args.includes("--no-native"))
25235
25253
  return;
25236
25254
  await runCapacitorForPlatforms(projectRoot, "add", mobile.platforms);
25255
+ if (mobile.branding)
25256
+ await generateAbsoluteCapacitorBranding(mobile, projectRoot);
25237
25257
  await applyAbsoluteNativeDeepLinks(mobile);
25238
25258
  await applyAbsoluteNativeDeviceCapabilities(projectRoot, mobile);
25239
25259
  await applyAbsoluteNativeBackgroundSync(projectRoot, mobile);
@@ -25270,6 +25290,10 @@ var sync = async (args) => {
25270
25290
  if (platforms.includes("ios"))
25271
25291
  await repairAbsoluteIosDevSession(projectRoot);
25272
25292
  await runCapacitorForPlatforms(projectRoot, "sync", platforms);
25293
+ if (mobile.branding)
25294
+ await generateAbsoluteCapacitorBranding(mobile, projectRoot, {
25295
+ platforms
25296
+ });
25273
25297
  await applyAbsoluteNativeDeepLinks(mobile, platforms);
25274
25298
  await applyAbsoluteNativeDeviceCapabilities(projectRoot, mobile, platforms);
25275
25299
  await applyAbsoluteNativeBackgroundSync(projectRoot, mobile, platforms);
@@ -25277,6 +25301,84 @@ var sync = async (args) => {
25277
25301
  await applyAbsoluteNativeObservability(mobile, platforms);
25278
25302
  await applyAbsoluteNativeReleaseReadiness(mobile, platforms);
25279
25303
  };
25304
+ var printMobileBrandingInspection = (inspection, json) => {
25305
+ if (json)
25306
+ console.log(JSON.stringify(inspection, null, 2));
25307
+ else
25308
+ console.log(inspection.detail);
25309
+ };
25310
+ var checkMobileBranding = async (mobile, projectRoot, json) => {
25311
+ const inspection = await inspectAbsoluteMobileBranding(mobile, projectRoot);
25312
+ printMobileBrandingInspection(inspection, json);
25313
+ if (!inspection.ready)
25314
+ throw new TypeError("Mobile branding is not current. Run `absolute mobile assets`.");
25315
+ return inspection;
25316
+ };
25317
+ var generateMobileBranding = async (args, mobile, platforms, projectRoot) => {
25318
+ if (!mobile.branding)
25319
+ throw new TypeError("absolute.config.ts must define mobile.branding before generating mobile assets.");
25320
+ if (mobile.engine !== "expo") {
25321
+ await ensureCapacitorPackages(projectRoot, args, mobile);
25322
+ await generateAbsoluteCapacitorBranding(mobile, projectRoot, {
25323
+ platforms
25324
+ });
25325
+ return;
25326
+ }
25327
+ await writeAbsoluteExpoProject(mobile, {
25328
+ force: args.includes("--force"),
25329
+ projectRoot
25330
+ });
25331
+ await ensureExpoPackages(mobile.nativeProjectDirectory, args);
25332
+ await runExpo(mobile.nativeProjectDirectory, [
25333
+ "prebuild",
25334
+ "--no-install",
25335
+ "--platform",
25336
+ platforms.length === 2 ? "all" : platforms[0] ?? "all"
25337
+ ]);
25338
+ };
25339
+ var renderMobileBrandingResult = (inspection, json, preview, projectRoot) => {
25340
+ const result = {
25341
+ ...inspection,
25342
+ ...preview ? { preview: relative17(projectRoot, preview).replaceAll("\\", "/") } : {}
25343
+ };
25344
+ if (json)
25345
+ console.log(JSON.stringify(result, null, 2));
25346
+ else
25347
+ console.log(`\u2713 ${inspection.detail}`);
25348
+ if (!json && result.preview)
25349
+ console.log(`Preview: ${result.preview}`);
25350
+ return result;
25351
+ };
25352
+ var assets = async (args) => {
25353
+ const startedAt = performance.now();
25354
+ const { mobile, projectRoot } = await loadMobile(valueAfter(args, "--config"));
25355
+ const requested = args.find((value) => value === "android" || value === "ios");
25356
+ if (requested && !mobile.platforms.includes(requested))
25357
+ throw new TypeError(`Mobile platform ${requested} is not enabled in mobile.platforms.`);
25358
+ const platforms = requested ? [requested] : [...mobile.platforms];
25359
+ try {
25360
+ if (args.includes("--check"))
25361
+ return await checkMobileBranding(mobile, projectRoot, args.includes("--json"));
25362
+ await generateMobileBranding(args, mobile, platforms, projectRoot);
25363
+ const preview = args.includes("--preview") ? await renderAbsoluteMobileBrandingPreview(mobile, projectRoot) : undefined;
25364
+ const inspection = await inspectAbsoluteMobileBranding(mobile, projectRoot);
25365
+ sendTelemetryEvent("mobile:assets", {
25366
+ durationMs: Math.round(performance.now() - startedAt),
25367
+ engine: mobile.engine,
25368
+ platforms: platforms.join(","),
25369
+ success: true
25370
+ });
25371
+ return renderMobileBrandingResult(inspection, args.includes("--json"), preview, projectRoot);
25372
+ } catch (error) {
25373
+ sendTelemetryEvent("mobile:assets", {
25374
+ durationMs: Math.round(performance.now() - startedAt),
25375
+ engine: mobile.engine,
25376
+ platforms: platforms.join(","),
25377
+ success: false
25378
+ });
25379
+ throw error;
25380
+ }
25381
+ };
25280
25382
  var associations = async (args) => {
25281
25383
  const { mobile, projectRoot } = await loadMobile(valueAfter(args, "--config"));
25282
25384
  const outputDirectory = resolve18(projectRoot, valueAfter(args, "--outdir") ?? ".absolutejs/mobile/associations");
@@ -28269,6 +28371,10 @@ var runMobile = async (args) => {
28269
28371
  await sync(args.slice(1));
28270
28372
  return;
28271
28373
  }
28374
+ if (command === "assets") {
28375
+ await assets(args.slice(1));
28376
+ return;
28377
+ }
28272
28378
  if (command === "associations") {
28273
28379
  await associations(args.slice(1));
28274
28380
  return;
@@ -28364,7 +28470,7 @@ var runMobile = async (args) => {
28364
28470
  await publishIos(args.slice(2));
28365
28471
  return;
28366
28472
  }
28367
- throw new TypeError("Usage: absolute mobile <pair mac <name> <user@host> [--port n] [--workspace path] | remotes [inspect [name] [--json] | clean [name] --yes | --json] | unpair mac <name> | init [--no-native] [--force] | sync [ios|android] | inspect [--json] [--require-bundle] | certify <release-dir> [--evidence report-dir]... [--require installed|simulator|device|store] [--outdir dir] [--json] | certify <release-dir> --verify certification-dir [--require installed|simulator|device|store] [--json] | associations [--outdir dir] [--verify] | ci github [server-entry] [--publish] [--registry module] [--secret-env NAME] [--output path] [--force] [--json] | ci promote <android|ios> --run-id id --certification path [--channel name] [--play-track track|--testflight-group group] [--ref branch] [--repo owner/name] [--watch] [--audit] [--outdir path] [--json] | ci promote --resume dispatch-id [--watch] [--audit] [--outdir path] [--json] | ci promotions [--json] | ci status --run-id id [--watch] [--repo owner/name] [--json] | ci audit --run-id id [--source-run-id id] [--repo owner/name] [--outdir path] [--json] | doctor [ios|android|release [ios|android]] [--remote name] [--json|--fix [--yes]] | build <android|ios> [server-entry] [--remote name] [--registered-device-artifact] [--outdir dir] [--web-outdir dir] [--unsigned] | update provision [--storage local|s3] [--registry module] [--force] [--yes] | update signing generate --private-key path [--certificate path] [--public-key path] [--key-id id] [--common-name name] [--validity-years n] | update build [server-entry] --classification bug-fix|content|security --key-id id --signing-key path --within-submitted-purpose [--outdir dir] [--web-outdir dir] | update publish <release-directory> [--rollout fraction] [--registry module] | update promote --release id --rollout fraction [--registry module] | update rollback [--release id] [--registry module] | update status [--registry module] [--json] | update advance [--rollout fraction] [--registry module] [--json] | update pause|resume|cancel|reconcile [--registry module] [--json] | update storage [--retain count] [--min-age-days days] [--registry module] [--json] | update gc [--retain count] [--min-age-days days] [--grace-days days] [--apply] [--registry module] [--json] | publish android [server-entry] [--release release-dir] [--certification certification-dir] [--certification-attestation verification-json] [--registry module] [--channel name] [--play-track track] [--play-status completed|draft|halted|in-progress] [--play-rollout fraction] [--play-name name] [--play-notes language=text] [--play-update-priority 0..5] [--play-hold-review] [--play-cancel-existing-review] [--outdir dir] [--web-outdir dir] [--unsigned] | publish ios [server-entry] [--release release-dir] [--certification certification-dir] [--certification-attestation verification-json] [--remote name] [--registry module] [--channel name] [--testflight-group name-or-id] [--testflight-notes locale=text] [--testflight-submit-review] [--outdir dir] [--web-outdir dir] [--unsigned] | test android [--release release-dir [--yes] | --route path [--wait-for-hmr] [--port n]] [--report [dir]] [--serial id] [--artifacts dir] [--json] [--config path] | test ios [--release release-dir [--remote name] [--device id [--testflight] --yes] | --wait-for-hmr] [--report [dir]] [--udid id] [--artifacts dir] [--json] [--config path]");
28473
+ throw new TypeError("Usage: absolute mobile <pair mac <name> <user@host> [--port n] [--workspace path] | remotes [inspect [name] [--json] | clean [name] --yes | --json] | unpair mac <name> | init [--no-native] [--force] | sync [ios|android] | assets [ios|android] [--check] [--preview] [--json] [--yes] | inspect [--json] [--require-bundle] | certify <release-dir> [--evidence report-dir]... [--require installed|simulator|device|store] [--outdir dir] [--json] | certify <release-dir> --verify certification-dir [--require installed|simulator|device|store] [--json] | associations [--outdir dir] [--verify] | ci github [server-entry] [--publish] [--registry module] [--secret-env NAME] [--output path] [--force] [--json] | ci promote <android|ios> --run-id id --certification path [--channel name] [--play-track track|--testflight-group group] [--ref branch] [--repo owner/name] [--watch] [--audit] [--outdir path] [--json] | ci promote --resume dispatch-id [--watch] [--audit] [--outdir path] [--json] | ci promotions [--json] | ci status --run-id id [--watch] [--repo owner/name] [--json] | ci audit --run-id id [--source-run-id id] [--repo owner/name] [--outdir path] [--json] | doctor [ios|android|release [ios|android]] [--remote name] [--json|--fix [--yes]] | build <android|ios> [server-entry] [--remote name] [--registered-device-artifact] [--outdir dir] [--web-outdir dir] [--unsigned] | update provision [--storage local|s3] [--registry module] [--force] [--yes] | update signing generate --private-key path [--certificate path] [--public-key path] [--key-id id] [--common-name name] [--validity-years n] | update build [server-entry] --classification bug-fix|content|security --key-id id --signing-key path --within-submitted-purpose [--outdir dir] [--web-outdir dir] | update publish <release-directory> [--rollout fraction] [--registry module] | update promote --release id --rollout fraction [--registry module] | update rollback [--release id] [--registry module] | update status [--registry module] [--json] | update advance [--rollout fraction] [--registry module] [--json] | update pause|resume|cancel|reconcile [--registry module] [--json] | update storage [--retain count] [--min-age-days days] [--registry module] [--json] | update gc [--retain count] [--min-age-days days] [--grace-days days] [--apply] [--registry module] [--json] | publish android [server-entry] [--release release-dir] [--certification certification-dir] [--certification-attestation verification-json] [--registry module] [--channel name] [--play-track track] [--play-status completed|draft|halted|in-progress] [--play-rollout fraction] [--play-name name] [--play-notes language=text] [--play-update-priority 0..5] [--play-hold-review] [--play-cancel-existing-review] [--outdir dir] [--web-outdir dir] [--unsigned] | publish ios [server-entry] [--release release-dir] [--certification certification-dir] [--certification-attestation verification-json] [--remote name] [--registry module] [--channel name] [--testflight-group name-or-id] [--testflight-notes locale=text] [--testflight-submit-review] [--outdir dir] [--web-outdir dir] [--unsigned] | test android [--release release-dir [--yes] | --route path [--wait-for-hmr] [--port n]] [--report [dir]] [--serial id] [--artifacts dir] [--json] [--config path] | test ios [--release release-dir [--remote name] [--device id [--testflight] --yes] | --wait-for-hmr] [--report [dir]] [--udid id] [--artifacts dir] [--json] [--config path]");
28368
28474
  };
28369
28475
  export {
28370
28476
  runMobile
@@ -1,8 +1,8 @@
1
1
  // @bun
2
2
  import {
3
3
  start
4
- } from "./index-gps0zk0m.js";
5
- import"./index-dfqzrznk.js";
4
+ } from "./index-5fmgn0nx.js";
5
+ import"./index-6mbm4n3g.js";
6
6
  import"./index-bzs19w3r.js";
7
7
  import"./index-s2tazax7.js";
8
8
  import"./index-fc9vxw56.js";
@@ -10,8 +10,8 @@ import"./index-r8x3839e.js";
10
10
  import"./index-06cmrcdq.js";
11
11
  import"./index-9kwmb3c0.js";
12
12
  import"./index-w5vswatm.js";
13
- import"./index-df2mjbdy.js";
14
- import"./index-0zcebhm4.js";
13
+ import"./index-exdd5k1g.js";
14
+ import"./index-dr21p6ae.js";
15
15
  import"./index-ar4gz15x.js";
16
16
  import"./index-t84wxk1p.js";
17
17
  import"./index-wtfnv3n2.js";
package/dist/index.js CHANGED
@@ -10644,13 +10644,62 @@ __export(exports_config, {
10644
10644
  import { readFileSync as readFileSync11 } from "fs";
10645
10645
  import { resolve as resolve12 } from "path";
10646
10646
  import { createHash as createHash4, createPublicKey, X509Certificate } from "crypto";
10647
- var APP_ID_PATTERN, SCHEME_PATTERN, APPLE_APP_ID_PREFIX_PATTERN, CERTIFICATE_FINGERPRINT_PATTERN, UPDATE_NAME_PATTERN, RELEASE_TARGET_PATTERN, UPDATE_PUBLIC_KEY_PATTERN, ENVIRONMENT_NAME_PATTERN, DEFAULT_UPDATE_BOOT_TIMEOUT_MS = 20000, DEFAULT_UPDATE_HEALTH_FAILURE_RATE = 0.2, DEFAULT_UPDATE_HEALTH_MINIMUM_REPORTS = 20, DEFAULT_UPDATE_ROLLOUT_FAILURE_RATE = 0.05, DEFAULT_UPDATE_ROLLOUT_OBSERVATION_MINUTES = 60, MINUTE_MS, DEFAULT_UPDATE_ROLLOUT_STAGES, MINIMUM_UPDATE_BOOT_TIMEOUT_MS = 5000, MAXIMUM_UPDATE_BOOT_TIMEOUT_MS = 120000, HOSTNAME_PATTERN, EXPO_RESERVED_ROUTE_PREFIXES, resolveProjectPath = (projectRoot, value, field) => {
10647
+ var APP_ID_PATTERN, SCHEME_PATTERN, APPLE_APP_ID_PREFIX_PATTERN, CERTIFICATE_FINGERPRINT_PATTERN, UPDATE_NAME_PATTERN, RELEASE_TARGET_PATTERN, UPDATE_PUBLIC_KEY_PATTERN, ENVIRONMENT_NAME_PATTERN, COLOR_PATTERN, DEFAULT_UPDATE_BOOT_TIMEOUT_MS = 20000, DEFAULT_UPDATE_HEALTH_FAILURE_RATE = 0.2, DEFAULT_UPDATE_HEALTH_MINIMUM_REPORTS = 20, DEFAULT_UPDATE_ROLLOUT_FAILURE_RATE = 0.05, DEFAULT_UPDATE_ROLLOUT_OBSERVATION_MINUTES = 60, MINUTE_MS, DEFAULT_UPDATE_ROLLOUT_STAGES, MINIMUM_UPDATE_BOOT_TIMEOUT_MS = 5000, MAXIMUM_UPDATE_BOOT_TIMEOUT_MS = 120000, HOSTNAME_PATTERN, EXPO_RESERVED_ROUTE_PREFIXES, resolveProjectPath = (projectRoot, value, field) => {
10648
10648
  const root = resolve12(projectRoot);
10649
10649
  const path = resolve12(root, value);
10650
10650
  if (path !== root && !path.startsWith(`${root}/`)) {
10651
10651
  throw new TypeError(`${field} must remain inside the project root.`);
10652
10652
  }
10653
10653
  return path;
10654
+ }, normalizeBrandingColor = (value, fallback, field) => {
10655
+ const normalized = (value ?? fallback).trim().toUpperCase();
10656
+ if (!COLOR_PATTERN.test(normalized))
10657
+ throw new TypeError(`${field} must use #RRGGBB hexadecimal notation.`);
10658
+ return normalized;
10659
+ }, normalizeBrandingPath = (projectRoot, value, field) => {
10660
+ const path = resolveProjectPath(projectRoot, requireText(value, field), field);
10661
+ if (!path.toLowerCase().endsWith(".png"))
10662
+ throw new TypeError(`${field} must reference a PNG file.`);
10663
+ return path;
10664
+ }, normalizeBranding = (config, projectRoot) => {
10665
+ const { branding } = config;
10666
+ if (!branding)
10667
+ return;
10668
+ const darkIcon = branding.ios?.darkIcon ? normalizeBrandingPath(projectRoot, branding.ios.darkIcon, "mobile.branding.ios.darkIcon") : undefined;
10669
+ const tintedIcon = branding.ios?.tintedIcon ? normalizeBrandingPath(projectRoot, branding.ios.tintedIcon, "mobile.branding.ios.tintedIcon") : undefined;
10670
+ const logoScale = branding.splash?.logoScale ?? 0.2;
10671
+ if (!Number.isFinite(logoScale) || logoScale < 0.1 || logoScale > 0.4)
10672
+ throw new TypeError("mobile.branding.splash.logoScale must be between 0.1 and 0.4.");
10673
+ return {
10674
+ android: {
10675
+ backgroundColor: normalizeBrandingColor(branding.android?.backgroundColor, "#FFFFFF", "mobile.branding.android.backgroundColor"),
10676
+ ...branding.android?.backgroundImage ? {
10677
+ backgroundImage: normalizeBrandingPath(projectRoot, branding.android.backgroundImage, "mobile.branding.android.backgroundImage")
10678
+ } : {},
10679
+ ...branding.android?.foreground ? {
10680
+ foreground: normalizeBrandingPath(projectRoot, branding.android.foreground, "mobile.branding.android.foreground")
10681
+ } : {},
10682
+ ...branding.android?.monochrome ? {
10683
+ monochrome: normalizeBrandingPath(projectRoot, branding.android.monochrome, "mobile.branding.android.monochrome")
10684
+ } : {}
10685
+ },
10686
+ icon: normalizeBrandingPath(projectRoot, branding.icon, "mobile.branding.icon"),
10687
+ ios: {
10688
+ ...darkIcon ? { darkIcon } : {},
10689
+ ...tintedIcon ? { tintedIcon } : {}
10690
+ },
10691
+ splash: {
10692
+ backgroundColor: normalizeBrandingColor(branding.splash?.backgroundColor, "#FFFFFF", "mobile.branding.splash.backgroundColor"),
10693
+ darkBackgroundColor: normalizeBrandingColor(branding.splash?.darkBackgroundColor, "#111111", "mobile.branding.splash.darkBackgroundColor"),
10694
+ ...branding.splash?.darkImage ? {
10695
+ darkImage: normalizeBrandingPath(projectRoot, branding.splash.darkImage, "mobile.branding.splash.darkImage")
10696
+ } : {},
10697
+ ...branding.splash?.image ? {
10698
+ image: normalizeBrandingPath(projectRoot, branding.splash.image, "mobile.branding.splash.image")
10699
+ } : {},
10700
+ logoScale
10701
+ }
10702
+ };
10654
10703
  }, requireText = (value, field) => {
10655
10704
  const normalized = value.trim();
10656
10705
  if (!normalized)
@@ -11036,11 +11085,13 @@ var APP_ID_PATTERN, SCHEME_PATTERN, APPLE_APP_ID_PREFIX_PATTERN, CERTIFICATE_FIN
11036
11085
  const updates = normalizeUpdates(config, productionOrigin, projectRoot);
11037
11086
  const updateServer = normalizeUpdateServer(config, productionOrigin, projectRoot, updates);
11038
11087
  const observability = normalizeObservability(config, productionOrigin);
11088
+ const branding = normalizeBranding(config, projectRoot);
11039
11089
  return {
11040
11090
  androidCertificateFingerprints: normalizeCertificateFingerprints(config.deepLinks?.android?.sha256CertificateFingerprints),
11041
11091
  appId,
11042
11092
  appleAppIdPrefix: normalizeAppleAppIdPrefix(config.deepLinks?.apple?.appIdPrefix),
11043
11093
  appName: requireText(config.appName, "mobile.appName"),
11094
+ ...branding ? { branding } : {},
11044
11095
  bundleDirectory: resolveProjectPath(projectRoot, config.bundleDirectory ?? ".absolutejs/mobile/web", "mobile.bundleDirectory"),
11045
11096
  deepLinkHosts: normalizeHosts(config.deepLinks?.hosts, productionOrigin),
11046
11097
  deepLinkScheme,
@@ -11068,6 +11119,7 @@ var init_config = __esm(() => {
11068
11119
  RELEASE_TARGET_PATTERN = /^[a-z0-9][a-z0-9._-]{0,63}$/u;
11069
11120
  UPDATE_PUBLIC_KEY_PATTERN = /^[A-Za-z0-9+/]+={0,2}$/u;
11070
11121
  ENVIRONMENT_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/u;
11122
+ COLOR_PATTERN = /^#[0-9A-F]{6}$/u;
11071
11123
  MINUTE_MS = 60 * 1000;
11072
11124
  DEFAULT_UPDATE_ROLLOUT_STAGES = [
11073
11125
  { minimumReports: 20, observationMinutes: 60, rollout: 0.05 },
@@ -45649,5 +45701,5 @@ export {
45649
45701
  wrapPageHandlerWithStreamingSlots
45650
45702
  };
45651
45703
 
45652
- //# debugId=35BD5CEBA947237E64756E2164756E21
45704
+ //# debugId=69E962978A5CFCEE64756E2164756E21
45653
45705
  //# sourceMappingURL=index.js.map