@absolutejs/absolute 0.20.0-beta.38 → 0.20.0-beta.39

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.
@@ -860,12 +860,12 @@ var init_deviceCapabilities = __esm(() => {
860
860
  });
861
861
 
862
862
  // src/cli/scripts/telemetry.ts
863
- import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync5, writeFileSync } from "fs";
863
+ import { existsSync as existsSync4, mkdirSync, readFileSync as readFileSync5, writeFileSync } from "fs";
864
864
  import { homedir as homedir3 } from "os";
865
865
  import { join as join15 } from "path";
866
866
  var configDir, configPath, getTelemetryConfig = () => {
867
867
  try {
868
- if (!existsSync3(configPath))
868
+ if (!existsSync4(configPath))
869
869
  return null;
870
870
  const raw = readFileSync5(configPath, "utf-8");
871
871
  const config = JSON.parse(raw);
@@ -880,11 +880,11 @@ var init_telemetry = __esm(() => {
880
880
  });
881
881
 
882
882
  // src/cli/telemetryEvent.ts
883
- import { existsSync as existsSync4, readFileSync as readFileSync6 } from "fs";
883
+ import { existsSync as existsSync5, readFileSync as readFileSync6 } from "fs";
884
884
  import { arch, platform } from "os";
885
- import { dirname as dirname10, join as join16, parse } from "path";
885
+ import { dirname as dirname11, join as join16, parse } from "path";
886
886
  var checkCandidate = (candidate) => {
887
- if (!existsSync4(candidate)) {
887
+ if (!existsSync5(candidate)) {
888
888
  return null;
889
889
  }
890
890
  const pkg = JSON.parse(readFileSync6(candidate, "utf-8"));
@@ -907,7 +907,7 @@ var checkCandidate = (candidate) => {
907
907
  if (version) {
908
908
  return version;
909
909
  }
910
- dir = dirname10(dir);
910
+ dir = dirname11(dir);
911
911
  }
912
912
  return "unknown";
913
913
  }, sendTelemetryEvent = (event, payload) => {
@@ -2032,6 +2032,21 @@ var verifyAabSignature = (artifactPath, capture, jarsigner) => {
2032
2032
  ]);
2033
2033
  return result.exitCode === 0 && /jar verified/iu.test(result.stdout);
2034
2034
  };
2035
+ var signAab = (artifactPath, capture, jarsigner, signing) => {
2036
+ const result = capture([
2037
+ jarsigner,
2038
+ "-keystore",
2039
+ signing.keystorePath,
2040
+ "-storepass:env",
2041
+ signing.storePasswordEnvironment,
2042
+ "-keypass:env",
2043
+ signing.keyPasswordEnvironment,
2044
+ artifactPath,
2045
+ signing.keyAlias
2046
+ ]);
2047
+ if (result.exitCode !== 0)
2048
+ throw new TypeError("jarsigner could not sign the Android App Bundle with the configured CI identity.");
2049
+ };
2035
2050
  var sha256File = async (path) => createHash4("sha256").update(await readFile4(path)).digest("hex");
2036
2051
  var safeOutputDirectory = (projectRoot, requested) => {
2037
2052
  const root = resolve3(projectRoot);
@@ -2126,7 +2141,16 @@ var buildAbsoluteAndroidRelease = async (options) => {
2126
2141
  throw new TypeError(`Android Gradle did not produce the expected App Bundle: ${artifactPath}`);
2127
2142
  }
2128
2143
  const capture = options.capture ?? defaultCapture;
2129
- const signed = verifyAabSignature(artifactPath, capture, options.jarsigner);
2144
+ const jarsigner = options.jarsigner === undefined ? Bun.which("jarsigner") : options.jarsigner;
2145
+ let signed = verifyAabSignature(artifactPath, capture, jarsigner);
2146
+ if (signed === false && options.signing) {
2147
+ if (!jarsigner)
2148
+ throw new TypeError("Could not sign the Android App Bundle because jarsigner is unavailable.");
2149
+ signAab(artifactPath, capture, jarsigner, options.signing);
2150
+ signed = verifyAabSignature(artifactPath, capture, jarsigner);
2151
+ if (!signed)
2152
+ throw new TypeError("Android App Bundle signature verification failed after CI signing.");
2153
+ }
2130
2154
  if (signed === null && !options.allowUnsigned) {
2131
2155
  throw new TypeError("Could not verify the Android App Bundle signature because jarsigner is unavailable. Install a JDK, or use --unsigned only for a non-publishable build.");
2132
2156
  }
@@ -2256,6 +2280,14 @@ import {
2256
2280
  } from "fs/promises";
2257
2281
  import { dirname as dirname3, isAbsolute as isAbsolute3, join as join5, relative as relative4, resolve as resolve4, sep as sep3 } from "path";
2258
2282
  var ABSOLUTE_IOS_RELEASE_FORMAT = 1;
2283
+ var developmentTeamArgument = (value) => {
2284
+ if (value === undefined)
2285
+ return;
2286
+ const team = value.trim().toUpperCase();
2287
+ if (!/^[A-Z0-9]{10}$/u.test(team))
2288
+ throw new TypeError("iOS development team must contain ten letters or digits.");
2289
+ return `DEVELOPMENT_TEAM=${team}`;
2290
+ };
2259
2291
  var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2260
2292
  var requireManifest2 = (value) => {
2261
2293
  if (!isRecord2(value) || typeof value.appBuild !== "string" || typeof value.appId !== "string" || typeof value.runtime !== "string") {
@@ -2448,8 +2480,10 @@ var buildAbsoluteIosRelease = async (options) => {
2448
2480
  await writeFile5(exportPlist, exportOptions());
2449
2481
  const run = options.run ?? defaultRun;
2450
2482
  try {
2483
+ const developmentTeam = developmentTeamArgument(options.developmentTeam);
2451
2484
  const versionArguments = [
2452
2485
  `MARKETING_VERSION=${marketingVersion}`,
2486
+ ...developmentTeam ? [developmentTeam] : [],
2453
2487
  ...buildNumber === undefined ? [] : [`CURRENT_PROJECT_VERSION=${buildNumber}`]
2454
2488
  ];
2455
2489
  const archiveExit = await run([
@@ -6140,6 +6174,500 @@ var installAbsoluteMobileSyncRemediation = (bridge = {
6140
6174
  // src/mobile/index.ts
6141
6175
  init_deviceCapabilities();
6142
6176
 
6177
+ // src/mobile/ciWorkflow.ts
6178
+ import { existsSync as existsSync3 } from "fs";
6179
+ import { access as access9, mkdir as mkdir11, readFile as readFile15, writeFile as writeFile12 } from "fs/promises";
6180
+ import { dirname as dirname10, extname as extname4, relative as relative10, resolve as resolve13, sep as sep6 } from "path";
6181
+ var ABSOLUTE_MOBILE_CI_WORKFLOW_FORMAT = 1;
6182
+ var SECRET_NAME_PATTERN = /^[A-Z][A-Z0-9_]*$/u;
6183
+ var CI_ENV_INDENTATION = 6;
6184
+ var RESERVED_SECRET_NAMES = new Set([
6185
+ "ABSOLUTE_ANDROID_KEYSTORE_BASE64",
6186
+ "ABSOLUTE_ANDROID_KEYSTORE_PASSWORD",
6187
+ "ABSOLUTE_ANDROID_KEY_ALIAS",
6188
+ "ABSOLUTE_ANDROID_KEY_PASSWORD",
6189
+ "ABSOLUTE_GOOGLE_CREDENTIALS_BASE64",
6190
+ "ABSOLUTE_IOS_CERTIFICATE_BASE64",
6191
+ "ABSOLUTE_IOS_CERTIFICATE_PASSWORD",
6192
+ "ABSOLUTE_IOS_PROVISIONING_PROFILE_BASE64",
6193
+ "ABSOLUTE_IOS_KEYCHAIN_PASSWORD",
6194
+ "ABSOLUTE_IOS_DEVELOPMENT_TEAM",
6195
+ "APP_STORE_CONNECT_ISSUER_ID",
6196
+ "APP_STORE_CONNECT_KEY_ID",
6197
+ "APP_STORE_CONNECT_PRIVATE_KEY_BASE64"
6198
+ ]);
6199
+ var exists3 = async (path) => {
6200
+ try {
6201
+ await access9(path);
6202
+ return true;
6203
+ } catch {
6204
+ return false;
6205
+ }
6206
+ };
6207
+ var yamlString = (value) => `'${value.replaceAll("'", "''")}'`;
6208
+ var projectPath = (projectRoot, value, field2, options = {}) => {
6209
+ const root = resolve13(projectRoot);
6210
+ const path = resolve13(root, value);
6211
+ const portable = relative10(root, path).replaceAll("\\", "/");
6212
+ if (portable === ".." || portable.startsWith(`..${sep6}`) || portable.startsWith("../") || portable === "") {
6213
+ throw new TypeError(`${field2} must remain inside the project root.`);
6214
+ }
6215
+ if (/\r|\n/u.test(portable) || portable.startsWith("-"))
6216
+ throw new TypeError(`${field2} contains an unsafe path.`);
6217
+ if (!options.allowMissing && !existsSync3(path))
6218
+ throw new TypeError(`${field2} does not exist inside the project.`);
6219
+ return portable;
6220
+ };
6221
+ var workflowOutputPath = (projectRoot, value) => {
6222
+ const root = resolve13(projectRoot);
6223
+ const workflows = resolve13(root, ".github/workflows");
6224
+ const path = resolve13(root, value ?? ".github/workflows/absolute-mobile.yml");
6225
+ const portable = relative10(workflows, path);
6226
+ if (portable === ".." || portable.startsWith(`..${sep6}`) || extname4(path) !== ".yml" && extname4(path) !== ".yaml") {
6227
+ throw new TypeError("mobile ci github --output must be a .yml or .yaml file inside .github/workflows.");
6228
+ }
6229
+ return path;
6230
+ };
6231
+ var normalizeSecretEnvironment = (values = []) => {
6232
+ const names = [...new Set(values)].sort();
6233
+ for (const name of names) {
6234
+ if (!SECRET_NAME_PATTERN.test(name))
6235
+ throw new TypeError("mobile ci github --secret-env values must be uppercase environment variable names.");
6236
+ if (name.startsWith("GITHUB_") || name.startsWith("RUNNER_") || name.startsWith("ACTIONS_") || RESERVED_SECRET_NAMES.has(name)) {
6237
+ throw new TypeError(`mobile ci github --secret-env cannot replace reserved variable ${name}.`);
6238
+ }
6239
+ }
6240
+ return names;
6241
+ };
6242
+ var customSecretEnvironment = (names, indentation = CI_ENV_INDENTATION) => names.map((name) => `${" ".repeat(indentation)}${name}: \${{ secrets.${name} }}`).join(`
6243
+ `);
6244
+ var commandEnvironment = (options) => ` ABSOLUTE_CONFIG_PATH: ${yamlString(options.configPath ?? "")}
6245
+ ABSOLUTE_REGISTRY_MODULE: ${yamlString(options.registryModule)}
6246
+ ABSOLUTE_SERVER_ENTRY: ${yamlString(options.serverEntry)}`;
6247
+ var appendConfigArgument = `if [[ -n "$ABSOLUTE_CONFIG_PATH" ]]; then
6248
+ args+=(--config "$ABSOLUTE_CONFIG_PATH")
6249
+ fi`;
6250
+ var installSteps = ` - name: Check out source
6251
+ uses: actions/checkout@v6
6252
+ - name: Install Bun
6253
+ uses: oven-sh/setup-bun@v2
6254
+ - name: Install exact dependencies
6255
+ run: bun ci`;
6256
+ var bundleAuditSteps = ` - name: Prepare production mobile bundle
6257
+ shell: bash
6258
+ run: |
6259
+ args=(bunx absolute prepare "$ABSOLUTE_SERVER_ENTRY" --outdir .absolutejs/mobile-ci/server)
6260
+ ${appendConfigArgument}
6261
+ "\${args[@]}"
6262
+ - name: Run cryptographic mobile bundle audit
6263
+ id: mobile-bundle-audit
6264
+ continue-on-error: true
6265
+ shell: bash
6266
+ run: |
6267
+ mkdir -p .absolutejs/mobile-ci
6268
+ args=(bunx absolute mobile inspect --json --require-bundle)
6269
+ ${appendConfigArgument}
6270
+ "\${args[@]}" > .absolutejs/mobile-ci/inspection.json
6271
+ - name: Upload mobile inspection report
6272
+ if: always()
6273
+ uses: actions/upload-artifact@v7
6274
+ with:
6275
+ name: absolute-mobile-inspection
6276
+ path: .absolutejs/mobile-ci/inspection.json
6277
+ if-no-files-found: error
6278
+ retention-days: 30
6279
+ include-hidden-files: true
6280
+ - name: Enforce mobile bundle audit
6281
+ if: steps.mobile-bundle-audit.outcome != 'success'
6282
+ run: exit 1`;
6283
+ var releaseAuditSteps = (platform) => ` - name: Run redacted mobile release audit
6284
+ id: mobile-release-audit
6285
+ continue-on-error: true
6286
+ shell: bash
6287
+ run: |
6288
+ mkdir -p .absolutejs/mobile-ci
6289
+ args=(bunx absolute mobile doctor release ${platform} --json)
6290
+ ${appendConfigArgument}
6291
+ "\${args[@]}" > .absolutejs/mobile-ci/compliance.json
6292
+ - name: Upload mobile compliance report
6293
+ if: always()
6294
+ uses: actions/upload-artifact@v7
6295
+ with:
6296
+ name: absolute-mobile-compliance-\${{ github.job }}
6297
+ path: .absolutejs/mobile-ci/compliance.json
6298
+ if-no-files-found: error
6299
+ retention-days: 30
6300
+ include-hidden-files: true
6301
+ - name: Enforce mobile release audit
6302
+ if: steps.mobile-release-audit.outcome != 'success'
6303
+ run: exit 1`;
6304
+ var platformInput = (platforms) => {
6305
+ const choices = platforms.length === 2 ? ["all", ...platforms] : platforms;
6306
+ return ` platform:
6307
+ description: Native platform to build
6308
+ required: true
6309
+ type: choice
6310
+ default: ${choices[0]}
6311
+ options:
6312
+ ${choices.map((value) => ` - ${value}`).join(`
6313
+ `)}`;
6314
+ };
6315
+ var publishingInputs = (platforms, includePublishing) => {
6316
+ if (!includePublishing)
6317
+ return "";
6318
+ const fields = [
6319
+ ` publish:
6320
+ description: Publish through mobile.release.ts after the signed build
6321
+ required: true
6322
+ type: boolean
6323
+ default: false`,
6324
+ ` channel:
6325
+ description: Optional AbsoluteJS immutable release channel
6326
+ required: false
6327
+ type: string`
6328
+ ];
6329
+ if (platforms.includes("android"))
6330
+ fields.push(` play_track:
6331
+ description: Optional Google Play track
6332
+ required: true
6333
+ type: choice
6334
+ default: registry-only
6335
+ options:
6336
+ - registry-only
6337
+ - internal
6338
+ - alpha
6339
+ - beta
6340
+ - production`);
6341
+ if (platforms.includes("ios")) {
6342
+ fields.push(` testflight_group:
6343
+ description: Optional internal or external TestFlight group
6344
+ required: false
6345
+ type: string`);
6346
+ fields.push(` submit_testflight_review:
6347
+ description: Explicitly submit an external TestFlight build for review
6348
+ required: true
6349
+ type: boolean
6350
+ default: false`);
6351
+ }
6352
+ return `
6353
+ ${fields.join(`
6354
+ `)}`;
6355
+ };
6356
+ var jobCondition = (platform) => `github.event_name == 'workflow_dispatch' && (inputs.platform == 'all' || inputs.platform == '${platform}')`;
6357
+ var androidJob = (options) => {
6358
+ const custom = customSecretEnvironment(options.customSecrets);
6359
+ const publishEnvironment = options.includePublishing ? `
6360
+ ABSOLUTE_PUBLISH: \${{ inputs.publish }}
6361
+ ABSOLUTE_RELEASE_CHANNEL: \${{ inputs.channel }}
6362
+ ABSOLUTE_PLAY_TRACK: \${{ inputs.play_track }}
6363
+ ABSOLUTE_GOOGLE_CREDENTIALS_BASE64: \${{ secrets.ABSOLUTE_GOOGLE_CREDENTIALS_BASE64 }}
6364
+ GOOGLE_APPLICATION_CREDENTIALS: \${{ runner.temp }}/absolute-google-credentials.json` : "";
6365
+ const publishCommand = options.includePublishing ? `if [[ "$ABSOLUTE_PUBLISH" == "true" ]]; then
6366
+ args=(bunx absolute mobile publish android "$ABSOLUTE_SERVER_ENTRY" --registry "$ABSOLUTE_REGISTRY_MODULE")
6367
+ if [[ -n "$ABSOLUTE_RELEASE_CHANNEL" ]]; then
6368
+ args+=(--channel "$ABSOLUTE_RELEASE_CHANNEL")
6369
+ fi
6370
+ if [[ "$ABSOLUTE_PLAY_TRACK" != "registry-only" ]]; then
6371
+ args+=(--play-track "$ABSOLUTE_PLAY_TRACK")
6372
+ fi
6373
+ else
6374
+ args=(bunx absolute mobile build android "$ABSOLUTE_SERVER_ENTRY")
6375
+ fi` : `args=(bunx absolute mobile build android "$ABSOLUTE_SERVER_ENTRY")`;
6376
+ const googleSetup = options.includePublishing ? `
6377
+ if [[ "$ABSOLUTE_PUBLISH" == "true" && "$ABSOLUTE_PLAY_TRACK" != "registry-only" ]]; then
6378
+ if [[ -z "$ABSOLUTE_GOOGLE_CREDENTIALS_BASE64" ]]; then
6379
+ echo "ABSOLUTE_GOOGLE_CREDENTIALS_BASE64 is required for Google Play publication." >&2
6380
+ exit 1
6381
+ fi
6382
+ printf '%s' "$ABSOLUTE_GOOGLE_CREDENTIALS_BASE64" | base64 --decode > "$GOOGLE_APPLICATION_CREDENTIALS"
6383
+ chmod 600 "$GOOGLE_APPLICATION_CREDENTIALS"
6384
+ fi` : "";
6385
+ return `
6386
+ android:
6387
+ name: Signed Android release
6388
+ needs: validate
6389
+ if: \${{ ${jobCondition("android")} }}
6390
+ runs-on: ubuntu-latest
6391
+ environment: absolute-mobile-release
6392
+ permissions:
6393
+ contents: read
6394
+ id-token: write
6395
+ attestations: write
6396
+ env:
6397
+ ABSOLUTE_ANDROID_KEYSTORE_BASE64: \${{ secrets.ABSOLUTE_ANDROID_KEYSTORE_BASE64 }}
6398
+ ABSOLUTE_ANDROID_KEYSTORE_PASSWORD: \${{ secrets.ABSOLUTE_ANDROID_KEYSTORE_PASSWORD }}
6399
+ ABSOLUTE_ANDROID_KEY_ALIAS: \${{ secrets.ABSOLUTE_ANDROID_KEY_ALIAS }}
6400
+ ABSOLUTE_ANDROID_KEY_PASSWORD: \${{ secrets.ABSOLUTE_ANDROID_KEY_PASSWORD }}
6401
+ ABSOLUTE_ANDROID_KEYSTORE_PATH: \${{ runner.temp }}/absolute-release.jks${publishEnvironment}${custom ? `
6402
+ ${custom}` : ""}
6403
+ ${commandEnvironment({ configPath: undefined, registryModule: "", serverEntry: "" })}
6404
+ steps:
6405
+ ${installSteps}
6406
+ - name: Provision Android signing
6407
+ shell: bash
6408
+ run: |
6409
+ required=(
6410
+ ABSOLUTE_ANDROID_KEYSTORE_BASE64
6411
+ ABSOLUTE_ANDROID_KEYSTORE_PASSWORD
6412
+ ABSOLUTE_ANDROID_KEY_ALIAS
6413
+ ABSOLUTE_ANDROID_KEY_PASSWORD
6414
+ )
6415
+ for name in "\${required[@]}"; do
6416
+ if [[ -z "\${!name}" ]]; then
6417
+ echo "$name is required in the absolute-mobile-release environment." >&2
6418
+ exit 1
6419
+ fi
6420
+ done
6421
+ printf '%s' "$ABSOLUTE_ANDROID_KEYSTORE_BASE64" | base64 --decode > "\${{ runner.temp }}/absolute-release.jks"
6422
+ chmod 600 "\${{ runner.temp }}/absolute-release.jks"${googleSetup}
6423
+ - name: Build or publish Android
6424
+ shell: bash
6425
+ run: |
6426
+ ${publishCommand}
6427
+ ${appendConfigArgument}
6428
+ "\${args[@]}"
6429
+ ${releaseAuditSteps("android")}
6430
+ - name: Attest Android App Bundle
6431
+ if: inputs.attest
6432
+ uses: actions/attest@v4
6433
+ with:
6434
+ subject-path: .absolutejs/mobile/releases/android/**/app-release.aab
6435
+ - name: Upload Android release
6436
+ uses: actions/upload-artifact@v7
6437
+ with:
6438
+ name: absolute-mobile-android
6439
+ path: .absolutejs/mobile/releases/android/
6440
+ if-no-files-found: error
6441
+ retention-days: 14
6442
+ include-hidden-files: true
6443
+ - name: Remove Android credentials
6444
+ if: always()
6445
+ shell: bash
6446
+ run: |
6447
+ rm -f "\${{ runner.temp }}/absolute-release.jks"
6448
+ rm -f "\${{ runner.temp }}/absolute-google-credentials.json"`;
6449
+ };
6450
+ var iosJob = (options) => {
6451
+ const custom = customSecretEnvironment(options.customSecrets);
6452
+ const publishEnvironment = options.includePublishing ? `
6453
+ ABSOLUTE_PUBLISH: \${{ inputs.publish }}
6454
+ ABSOLUTE_RELEASE_CHANNEL: \${{ inputs.channel }}
6455
+ ABSOLUTE_TESTFLIGHT_GROUP: \${{ inputs.testflight_group }}
6456
+ ABSOLUTE_TESTFLIGHT_SUBMIT_REVIEW: \${{ inputs.submit_testflight_review }}
6457
+ APP_STORE_CONNECT_ISSUER_ID: \${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}
6458
+ APP_STORE_CONNECT_KEY_ID: \${{ secrets.APP_STORE_CONNECT_KEY_ID }}
6459
+ APP_STORE_CONNECT_PRIVATE_KEY_BASE64: \${{ secrets.APP_STORE_CONNECT_PRIVATE_KEY_BASE64 }}
6460
+ APP_STORE_CONNECT_PRIVATE_KEY_PATH: \${{ runner.temp }}/AuthKey_AbsoluteJS.p8` : "";
6461
+ const publishCommand = options.includePublishing ? `if [[ "$ABSOLUTE_PUBLISH" == "true" ]]; then
6462
+ args=(bunx absolute mobile publish ios "$ABSOLUTE_SERVER_ENTRY" --registry "$ABSOLUTE_REGISTRY_MODULE")
6463
+ if [[ -n "$ABSOLUTE_RELEASE_CHANNEL" ]]; then
6464
+ args+=(--channel "$ABSOLUTE_RELEASE_CHANNEL")
6465
+ fi
6466
+ if [[ -n "$ABSOLUTE_TESTFLIGHT_GROUP" ]]; then
6467
+ args+=(--testflight-group "$ABSOLUTE_TESTFLIGHT_GROUP")
6468
+ fi
6469
+ if [[ "$ABSOLUTE_TESTFLIGHT_SUBMIT_REVIEW" == "true" ]]; then
6470
+ args+=(--testflight-submit-review)
6471
+ fi
6472
+ else
6473
+ args=(bunx absolute mobile build ios "$ABSOLUTE_SERVER_ENTRY")
6474
+ fi` : `args=(bunx absolute mobile build ios "$ABSOLUTE_SERVER_ENTRY")`;
6475
+ const appStoreSetup = options.includePublishing ? `
6476
+ if [[ "$ABSOLUTE_PUBLISH" == "true" && -n "$ABSOLUTE_TESTFLIGHT_GROUP" ]]; then
6477
+ required+=(APP_STORE_CONNECT_ISSUER_ID APP_STORE_CONNECT_KEY_ID APP_STORE_CONNECT_PRIVATE_KEY_BASE64)
6478
+ fi` : "";
6479
+ const appStoreDecode = options.includePublishing ? `
6480
+ if [[ "$ABSOLUTE_PUBLISH" == "true" && -n "$ABSOLUTE_TESTFLIGHT_GROUP" ]]; then
6481
+ printf '%s' "$APP_STORE_CONNECT_PRIVATE_KEY_BASE64" | base64 --decode > "$APP_STORE_CONNECT_PRIVATE_KEY_PATH"
6482
+ chmod 600 "$APP_STORE_CONNECT_PRIVATE_KEY_PATH"
6483
+ fi` : "";
6484
+ return `
6485
+ ios:
6486
+ name: Signed iOS release
6487
+ needs: validate
6488
+ if: \${{ ${jobCondition("ios")} }}
6489
+ runs-on: macos-latest
6490
+ environment: absolute-mobile-release
6491
+ permissions:
6492
+ contents: read
6493
+ id-token: write
6494
+ attestations: write
6495
+ env:
6496
+ ABSOLUTE_IOS_CERTIFICATE_BASE64: \${{ secrets.ABSOLUTE_IOS_CERTIFICATE_BASE64 }}
6497
+ ABSOLUTE_IOS_CERTIFICATE_PASSWORD: \${{ secrets.ABSOLUTE_IOS_CERTIFICATE_PASSWORD }}
6498
+ ABSOLUTE_IOS_PROVISIONING_PROFILE_BASE64: \${{ secrets.ABSOLUTE_IOS_PROVISIONING_PROFILE_BASE64 }}
6499
+ ABSOLUTE_IOS_KEYCHAIN_PASSWORD: \${{ secrets.ABSOLUTE_IOS_KEYCHAIN_PASSWORD }}${publishEnvironment}${custom ? `
6500
+ ${custom}` : ""}
6501
+ ABSOLUTE_IOS_DEVELOPMENT_TEAM: \${{ secrets.ABSOLUTE_IOS_DEVELOPMENT_TEAM }}
6502
+ ${commandEnvironment({ configPath: undefined, registryModule: "", serverEntry: "" })}
6503
+ steps:
6504
+ ${installSteps}
6505
+ - name: Provision iOS signing
6506
+ shell: bash
6507
+ run: |
6508
+ required=(
6509
+ ABSOLUTE_IOS_CERTIFICATE_BASE64
6510
+ ABSOLUTE_IOS_CERTIFICATE_PASSWORD
6511
+ ABSOLUTE_IOS_PROVISIONING_PROFILE_BASE64
6512
+ ABSOLUTE_IOS_KEYCHAIN_PASSWORD
6513
+ ABSOLUTE_IOS_DEVELOPMENT_TEAM
6514
+ )${appStoreSetup}
6515
+ for name in "\${required[@]}"; do
6516
+ if [[ -z "\${!name}" ]]; then
6517
+ echo "$name is required in the absolute-mobile-release environment." >&2
6518
+ exit 1
6519
+ fi
6520
+ done
6521
+ CERTIFICATE_PATH="\${{ runner.temp }}/absolute-signing.p12"
6522
+ PROFILE_PATH="\${{ runner.temp }}/absolute.mobileprovision"
6523
+ KEYCHAIN_PATH="\${{ runner.temp }}/absolute-signing.keychain-db"
6524
+ PROFILE_DESTINATION="$HOME/Library/MobileDevice/Provisioning Profiles/absolute.mobileprovision"
6525
+ printf '%s' "$ABSOLUTE_IOS_CERTIFICATE_BASE64" | base64 --decode > "$CERTIFICATE_PATH"
6526
+ printf '%s' "$ABSOLUTE_IOS_PROVISIONING_PROFILE_BASE64" | base64 --decode > "$PROFILE_PATH"
6527
+ security create-keychain -p "$ABSOLUTE_IOS_KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
6528
+ security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
6529
+ security unlock-keychain -p "$ABSOLUTE_IOS_KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
6530
+ security import "$CERTIFICATE_PATH" -P "$ABSOLUTE_IOS_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH"
6531
+ security set-key-partition-list -S apple-tool:,apple: -k "$ABSOLUTE_IOS_KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
6532
+ security list-keychain -d user -s "$KEYCHAIN_PATH"
6533
+ mkdir -p "$(dirname "$PROFILE_DESTINATION")"
6534
+ cp "$PROFILE_PATH" "$PROFILE_DESTINATION"${appStoreDecode}
6535
+ - name: Build or publish iOS
6536
+ shell: bash
6537
+ run: |
6538
+ ${publishCommand}
6539
+ ${appendConfigArgument}
6540
+ "\${args[@]}"
6541
+ ${releaseAuditSteps("ios")}
6542
+ - name: Attest iOS IPA
6543
+ if: inputs.attest
6544
+ uses: actions/attest@v4
6545
+ with:
6546
+ subject-path: .absolutejs/mobile/releases/ios/**/App.ipa
6547
+ - name: Upload iOS release
6548
+ uses: actions/upload-artifact@v7
6549
+ with:
6550
+ name: absolute-mobile-ios
6551
+ path: .absolutejs/mobile/releases/ios/
6552
+ if-no-files-found: error
6553
+ retention-days: 14
6554
+ include-hidden-files: true
6555
+ - name: Remove iOS credentials
6556
+ if: always()
6557
+ shell: bash
6558
+ run: |
6559
+ security delete-keychain "\${{ runner.temp }}/absolute-signing.keychain-db" 2>/dev/null || true
6560
+ rm -f "$HOME/Library/MobileDevice/Provisioning Profiles/absolute.mobileprovision"
6561
+ rm -f "\${{ runner.temp }}/absolute-signing.p12"
6562
+ rm -f "\${{ runner.temp }}/absolute.mobileprovision"
6563
+ rm -f "\${{ runner.temp }}/AuthKey_AbsoluteJS.p8"`;
6564
+ };
6565
+ var requiredSecrets = (platforms, includePublishing, custom) => [
6566
+ ...platforms.includes("android") ? [
6567
+ "ABSOLUTE_ANDROID_KEYSTORE_BASE64",
6568
+ "ABSOLUTE_ANDROID_KEYSTORE_PASSWORD",
6569
+ "ABSOLUTE_ANDROID_KEY_ALIAS",
6570
+ "ABSOLUTE_ANDROID_KEY_PASSWORD",
6571
+ ...includePublishing ? ["ABSOLUTE_GOOGLE_CREDENTIALS_BASE64"] : []
6572
+ ] : [],
6573
+ ...platforms.includes("ios") ? [
6574
+ "ABSOLUTE_IOS_CERTIFICATE_BASE64",
6575
+ "ABSOLUTE_IOS_CERTIFICATE_PASSWORD",
6576
+ "ABSOLUTE_IOS_PROVISIONING_PROFILE_BASE64",
6577
+ "ABSOLUTE_IOS_KEYCHAIN_PASSWORD",
6578
+ "ABSOLUTE_IOS_DEVELOPMENT_TEAM",
6579
+ ...includePublishing ? [
6580
+ "APP_STORE_CONNECT_ISSUER_ID",
6581
+ "APP_STORE_CONNECT_KEY_ID",
6582
+ "APP_STORE_CONNECT_PRIVATE_KEY_BASE64"
6583
+ ] : []
6584
+ ] : [],
6585
+ ...custom
6586
+ ];
6587
+ var createAbsoluteMobileGithubWorkflow = (options) => {
6588
+ const platforms = [
6589
+ ...options.config.platforms
6590
+ ].sort();
6591
+ const includePublishing = options.includePublishing === true;
6592
+ const customSecrets = normalizeSecretEnvironment(options.secretEnvironment);
6593
+ const serverEntry = projectPath(options.projectRoot, options.serverEntry ?? "server.ts", "mobile ci github server entry");
6594
+ const configPath = options.configPath ? projectPath(options.projectRoot, options.configPath, "mobile ci github --config") : undefined;
6595
+ const registryModule = projectPath(options.projectRoot, options.registryModule ?? "mobile.release.ts", "mobile ci github --registry", { allowMissing: !includePublishing });
6596
+ const environment = commandEnvironment({
6597
+ configPath,
6598
+ registryModule,
6599
+ serverEntry
6600
+ });
6601
+ let workflow = `# Generated by AbsoluteJS. Regenerate with: absolute mobile ci github${includePublishing ? " --publish" : ""}
6602
+ name: AbsoluteJS Mobile
6603
+
6604
+ on:
6605
+ pull_request:
6606
+ workflow_dispatch:
6607
+ inputs:
6608
+ ${platformInput(platforms)}
6609
+ attest:
6610
+ description: Generate GitHub artifact provenance attestations
6611
+ required: true
6612
+ type: boolean
6613
+ default: false${publishingInputs(platforms, includePublishing)}
6614
+
6615
+ concurrency:
6616
+ group: absolute-mobile-\${{ github.repository }}
6617
+ cancel-in-progress: false
6618
+
6619
+ jobs:
6620
+ validate:
6621
+ name: Validate mobile release inputs
6622
+ runs-on: ubuntu-latest
6623
+ permissions:
6624
+ contents: read
6625
+ env:
6626
+ ${environment}
6627
+ steps:
6628
+ ${installSteps}
6629
+ ${bundleAuditSteps}${platforms.includes("android") ? androidJob({ customSecrets, includePublishing }) : ""}${platforms.includes("ios") ? iosJob({ customSecrets, includePublishing }) : ""}
6630
+ `;
6631
+ const replacements = new Map([
6632
+ [
6633
+ "ABSOLUTE_CONFIG_PATH: ''",
6634
+ `ABSOLUTE_CONFIG_PATH: ${yamlString(configPath ?? "")}`
6635
+ ],
6636
+ [
6637
+ "ABSOLUTE_REGISTRY_MODULE: ''",
6638
+ `ABSOLUTE_REGISTRY_MODULE: ${yamlString(registryModule)}`
6639
+ ],
6640
+ [
6641
+ "ABSOLUTE_SERVER_ENTRY: ''",
6642
+ `ABSOLUTE_SERVER_ENTRY: ${yamlString(serverEntry)}`
6643
+ ]
6644
+ ]);
6645
+ for (const [placeholder, replacement] of replacements)
6646
+ workflow = workflow.replaceAll(placeholder, replacement);
6647
+ return {
6648
+ requiredSecrets: requiredSecrets(platforms, includePublishing, customSecrets),
6649
+ workflow
6650
+ };
6651
+ };
6652
+ var writeAbsoluteMobileGithubWorkflow = async (options) => {
6653
+ const path = workflowOutputPath(options.projectRoot, options.outputPath);
6654
+ const generated = createAbsoluteMobileGithubWorkflow(options);
6655
+ const previous = await exists3(path) ? await readFile15(path, "utf8") : undefined;
6656
+ if (previous !== undefined && previous !== generated.workflow && !options.force)
6657
+ throw new TypeError(`${relative10(options.projectRoot, path)} already exists and differs. Rerun with --force to replace the generated workflow.`);
6658
+ if (previous !== generated.workflow) {
6659
+ await mkdir11(dirname10(path), { recursive: true });
6660
+ await writeFile12(path, generated.workflow);
6661
+ }
6662
+ return {
6663
+ changed: previous !== generated.workflow,
6664
+ format: ABSOLUTE_MOBILE_CI_WORKFLOW_FORMAT,
6665
+ path,
6666
+ platforms: [...options.config.platforms].sort(),
6667
+ publishing: options.includePublishing === true,
6668
+ requiredSecrets: generated.requiredSecrets
6669
+ };
6670
+ };
6143
6671
  // src/mobile/compatibilityDispatcher.ts
6144
6672
  import { Elysia as Elysia2 } from "elysia";
6145
6673
 
@@ -6356,7 +6884,7 @@ var createAbsoluteMobilePreviewPlugin = (mobile) => {
6356
6884
  });
6357
6885
  };
6358
6886
  // src/mobile/nativeDeepLinks.ts
6359
- import { readFile as readFile15, rename as rename11, writeFile as writeFile12 } from "fs/promises";
6887
+ import { readFile as readFile16, rename as rename11, writeFile as writeFile13 } from "fs/promises";
6360
6888
  import { join as join17 } from "path";
6361
6889
  var START_MARKER = "<!-- absolutejs:deep-links:start -->";
6362
6890
  var END_MARKER = "<!-- absolutejs:deep-links:end -->";
@@ -6364,11 +6892,11 @@ var IOS_ENTITLEMENTS = "App/AbsoluteJS.entitlements";
6364
6892
  var NOT_FOUND = -1;
6365
6893
  var escapeXml = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&apos;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
6366
6894
  var writeChangedFile = async (path, source) => {
6367
- const current = await readFile15(path, "utf8");
6895
+ const current = await readFile16(path, "utf8");
6368
6896
  if (current === source)
6369
6897
  return false;
6370
6898
  const temporary = `${path}.${crypto.randomUUID()}.tmp`;
6371
- await writeFile12(temporary, source, { flag: "wx" });
6899
+ await writeFile13(temporary, source, { flag: "wx" });
6372
6900
  await rename11(temporary, path);
6373
6901
  return true;
6374
6902
  };
@@ -6415,7 +6943,7 @@ ${hosts}
6415
6943
  };
6416
6944
  var configureAndroid = async (config) => {
6417
6945
  const path = join17(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
6418
- const source = await readFile15(path, "utf8");
6946
+ const source = await readFile16(path, "utf8");
6419
6947
  const mainActivity = source.indexOf('android:name=".MainActivity"');
6420
6948
  if (mainActivity === NOT_FOUND) {
6421
6949
  throw new TypeError("Android MainActivity was not found.");
@@ -6441,7 +6969,7 @@ var iosSchemeRegion = (scheme) => ` ${START_MARKER}
6441
6969
  `;
6442
6970
  var configureIosInfo = async (config) => {
6443
6971
  const path = join17(config.nativeProjectDirectory, "ios/App/App/Info.plist");
6444
- const source = await readFile15(path, "utf8");
6972
+ const source = await readFile16(path, "utf8");
6445
6973
  const region = config.deepLinkScheme ? iosSchemeRegion(config.deepLinkScheme) : ` ${START_MARKER}
6446
6974
  ${END_MARKER}
6447
6975
  `;
@@ -6467,7 +6995,7 @@ var configureIosEntitlements = async (config) => {
6467
6995
  const path = join17(config.nativeProjectDirectory, "ios/App/AbsoluteJS.entitlements");
6468
6996
  let current = "";
6469
6997
  try {
6470
- current = await readFile15(path, "utf8");
6998
+ current = await readFile16(path, "utf8");
6471
6999
  } catch (error) {
6472
7000
  if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") {
6473
7001
  throw error;
@@ -6477,13 +7005,13 @@ var configureIosEntitlements = async (config) => {
6477
7005
  if (current === source)
6478
7006
  return false;
6479
7007
  const temporary = `${path}.${crypto.randomUUID()}.tmp`;
6480
- await writeFile12(temporary, source, { flag: "wx" });
7008
+ await writeFile13(temporary, source, { flag: "wx" });
6481
7009
  await rename11(temporary, path);
6482
7010
  return true;
6483
7011
  };
6484
7012
  var configureIosProject = async (config) => {
6485
7013
  const path = join17(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
6486
- const source = await readFile15(path, "utf8");
7014
+ const source = await readFile16(path, "utf8");
6487
7015
  const declarations = [
6488
7016
  ...source.matchAll(/CODE_SIGN_ENTITLEMENTS = ([^;]+);/g)
6489
7017
  ].map((match) => match[1]);
@@ -6522,7 +7050,7 @@ var applyAbsoluteNativeDeepLinks = async (config, platforms = config.platforms)
6522
7050
  };
6523
7051
  // src/mobile/nativeDeviceCapabilities.ts
6524
7052
  init_deviceCapabilities();
6525
- import { readFile as readFile16, rename as rename12, writeFile as writeFile13 } from "fs/promises";
7053
+ import { readFile as readFile17, rename as rename12, writeFile as writeFile14 } from "fs/promises";
6526
7054
  import { join as join18 } from "path";
6527
7055
  var START_MARKER2 = "<!-- absolutejs:device-capabilities:start -->";
6528
7056
  var END_MARKER2 = "<!-- absolutejs:device-capabilities:end -->";
@@ -6533,11 +7061,11 @@ var PUSH_START_MARKER = "absolutejs:push-notifications:start";
6533
7061
  var PUSH_END_MARKER = "absolutejs:push-notifications:end";
6534
7062
  var escapeXml2 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&apos;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
6535
7063
  var writeChangedFile2 = async (path, source) => {
6536
- const current = await readFile16(path, "utf8");
7064
+ const current = await readFile17(path, "utf8");
6537
7065
  if (current === source)
6538
7066
  return false;
6539
7067
  const temporary = `${path}.${crypto.randomUUID()}.tmp`;
6540
- await writeFile13(temporary, source, { flag: "wx" });
7068
+ await writeFile14(temporary, source, { flag: "wx" });
6541
7069
  await rename12(temporary, path);
6542
7070
  return true;
6543
7071
  };
@@ -6546,14 +7074,14 @@ var writeOptionalChangedFile = async (path, source) => {
6546
7074
  if (current === source)
6547
7075
  return false;
6548
7076
  if (current === null) {
6549
- await writeFile13(path, source, { flag: "wx" });
7077
+ await writeFile14(path, source, { flag: "wx" });
6550
7078
  return true;
6551
7079
  }
6552
7080
  return writeChangedFile2(path, source);
6553
7081
  };
6554
7082
  var optionalSource = async (path) => {
6555
7083
  try {
6556
- return await readFile16(path, "utf8");
7084
+ return await readFile17(path, "utf8");
6557
7085
  } catch (error) {
6558
7086
  if (typeof error === "object" && error !== null && Reflect.get(error, "code") === "ENOENT")
6559
7087
  return null;
@@ -6667,15 +7195,15 @@ var writeIosPrivacyManifest = async (path, current, source) => {
6667
7195
  return false;
6668
7196
  if (current !== null)
6669
7197
  return writeChangedFile2(path, source);
6670
- await writeFile13(path, source, { flag: "wx" });
7198
+ await writeFile14(path, source, { flag: "wx" });
6671
7199
  return true;
6672
7200
  };
6673
7201
  var configureIosPrivacyProject = async (config, requirements) => {
6674
7202
  if (requirements.iosPrivacyAccessedApis.length === 0)
6675
7203
  return false;
6676
- const projectPath = join18(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
6677
- const project = await readFile16(projectPath, "utf8");
6678
- return writeChangedFile2(projectPath, addIosPrivacyProjectReference(project));
7204
+ const projectPath2 = join18(config.nativeProjectDirectory, "ios/App/App.xcodeproj/project.pbxproj");
7205
+ const project = await readFile17(projectPath2, "utf8");
7206
+ return writeChangedFile2(projectPath2, addIosPrivacyProjectReference(project));
6679
7207
  };
6680
7208
  var addIosPrivacyProjectReference = (source) => {
6681
7209
  const fileMatch = source.match(/([A-F0-9]{24}) \/\* PrivacyInfo\.xcprivacy \*\/ = \{isa = PBXFileReference;/u);
@@ -6727,7 +7255,7 @@ ${next.slice(index)}`;
6727
7255
  };
6728
7256
  var configureIos2 = async (config, plan) => {
6729
7257
  const path = join18(config.nativeProjectDirectory, "ios/App/App/Info.plist");
6730
- const source = await readFile16(path, "utf8");
7258
+ const source = await readFile17(path, "utf8");
6731
7259
  const requirements = absoluteDeviceNativeRequirements(plan);
6732
7260
  const existingSystemBars = source.match(/<key>UIViewControllerBasedStatusBarAppearance<\/key>\s*<(true|false)\s*\/>/u);
6733
7261
  const ownedStart = source.indexOf(START_MARKER2);
@@ -6820,7 +7348,7 @@ var replacePushRegion = (source, region, insertion) => {
6820
7348
  };
6821
7349
  var configureAndroid2 = async (config, plan) => {
6822
7350
  const path = join18(config.nativeProjectDirectory, "android/app/src/main/AndroidManifest.xml");
6823
- const source = await readFile16(path, "utf8");
7351
+ const source = await readFile17(path, "utf8");
6824
7352
  const permissions = absoluteDeviceNativeRequirements(plan).androidPermissions;
6825
7353
  const content = permissions.map((permission) => ` <uses-permission android:name="${escapeXml2(permission)}" />`).join(`
6826
7354
  `);
@@ -6869,8 +7397,8 @@ var applyAbsoluteNativeDeviceCapabilities = async (projectRoot, config, platform
6869
7397
  };
6870
7398
  };
6871
7399
  // src/mobile/releasePublisher.ts
6872
- import { access as access9 } from "fs/promises";
6873
- import { isAbsolute as isAbsolute6, relative as relative10, resolve as resolve13, sep as sep6 } from "path";
7400
+ import { access as access10 } from "fs/promises";
7401
+ import { isAbsolute as isAbsolute6, relative as relative11, resolve as resolve14, sep as sep7 } from "path";
6874
7402
  import { pathToFileURL as pathToFileURL3 } from "url";
6875
7403
  var prepareAbsoluteIosRelease = async (publisher, options) => {
6876
7404
  if (typeof publisher.prepareIosRelease !== "function") {
@@ -6896,17 +7424,17 @@ var prepareAbsoluteAndroidRelease = async (publisher, options) => {
6896
7424
  var isRecord9 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
6897
7425
  var isPublisher = (value) => isRecord9(value) && typeof value.publish === "function";
6898
7426
  var publisherModulePath = (projectRoot, requested) => {
6899
- const root = resolve13(projectRoot);
6900
- const path = resolve13(root, requested);
6901
- const projectRelative = relative10(root, path);
6902
- if (projectRelative === ".." || projectRelative.startsWith(`..${sep6}`) || isAbsolute6(projectRelative)) {
7427
+ const root = resolve14(projectRoot);
7428
+ const path = resolve14(root, requested);
7429
+ const projectRelative = relative11(root, path);
7430
+ if (projectRelative === ".." || projectRelative.startsWith(`..${sep7}`) || isAbsolute6(projectRelative)) {
6903
7431
  throw new TypeError("mobile publish --registry must remain inside the project.");
6904
7432
  }
6905
7433
  return path;
6906
7434
  };
6907
7435
  var loadAbsoluteNativeReleasePublisher = async (projectRoot, requestedModulePath) => {
6908
7436
  const modulePath = publisherModulePath(projectRoot, requestedModulePath);
6909
- await access9(modulePath).catch(() => {
7437
+ await access10(modulePath).catch(() => {
6910
7438
  throw new TypeError(`Native release registry module does not exist: ${modulePath}`);
6911
7439
  });
6912
7440
  const loaded = await import(pathToFileURL3(modulePath).href);
@@ -6967,8 +7495,8 @@ var publishAbsoluteIosRelease = async (options) => {
6967
7495
  return publication;
6968
7496
  };
6969
7497
  // src/mobile/routeMetadataTransform.ts
6970
- import { existsSync as existsSync5, readFileSync as readFileSync7 } from "fs";
6971
- import { dirname as dirname11, extname as extname4, relative as relative11, resolve as resolve14 } from "path";
7498
+ import { existsSync as existsSync6, readFileSync as readFileSync7 } from "fs";
7499
+ import { dirname as dirname12, extname as extname5, relative as relative12, resolve as resolve15 } from "path";
6972
7500
  import ts2 from "typescript";
6973
7501
  var ROUTE_METHODS = new Set(["get", "head"]);
6974
7502
  var SOURCE_FILTER = /\.[cm]?[jt]sx?$/;
@@ -7019,7 +7547,7 @@ var PAGE_HANDLERS = new Map([
7019
7547
  ]
7020
7548
  ]);
7021
7549
  var posixPath = (value) => value.replace(/\\/g, "/");
7022
- var findTsconfig = (entry, projectRoot) => ts2.findConfigFile(dirname11(entry), existsSync5, "tsconfig.json") ?? ts2.findConfigFile(projectRoot, existsSync5, "tsconfig.json");
7550
+ var findTsconfig = (entry, projectRoot) => ts2.findConfigFile(dirname12(entry), existsSync6, "tsconfig.json") ?? ts2.findConfigFile(projectRoot, existsSync6, "tsconfig.json");
7023
7551
  var createProgram = (entry, projectRoot) => {
7024
7552
  const configPath2 = findTsconfig(entry, projectRoot);
7025
7553
  if (!configPath2) {
@@ -7031,7 +7559,7 @@ var createProgram = (entry, projectRoot) => {
7031
7559
  target: ts2.ScriptTarget.ESNext
7032
7560
  });
7033
7561
  }
7034
- const parsed = ts2.parseJsonConfigFileContent(ts2.readConfigFile(configPath2, (path) => readFileSync7(path, "utf8")).config, ts2.sys, dirname11(configPath2));
7562
+ const parsed = ts2.parseJsonConfigFileContent(ts2.readConfigFile(configPath2, (path) => readFileSync7(path, "utf8")).config, ts2.sys, dirname12(configPath2));
7035
7563
  if (!parsed.fileNames.includes(entry))
7036
7564
  parsed.fileNames.push(entry);
7037
7565
  return ts2.createProgram(parsed.fileNames, parsed.options);
@@ -7137,7 +7665,7 @@ var resolvePageIdentity = (expression, sourceFile, checker, projectRoot) => {
7137
7665
  const declaration = symbol?.declarations?.[0];
7138
7666
  const file = declaration?.getSourceFile().fileName ?? sourceFile.fileName;
7139
7667
  const exportedName = symbol?.name ?? expression.getText(sourceFile);
7140
- const source = posixPath(relative11(projectRoot, file));
7668
+ const source = posixPath(relative12(projectRoot, file));
7141
7669
  return `${source}#${exportedName}`;
7142
7670
  };
7143
7671
  var resolveAlias = (symbol, checker) => {
@@ -7376,7 +7904,7 @@ var analyzeProgram = (program, projectRoot) => {
7376
7904
  const checker = program.getTypeChecker();
7377
7905
  const analyzed = new Map;
7378
7906
  for (const sourceFile of program.getSourceFiles()) {
7379
- const resolvedFile = resolve14(sourceFile.fileName);
7907
+ const resolvedFile = resolve15(sourceFile.fileName);
7380
7908
  if (!isProjectSource(sourceFile, resolvedFile, projectRoot))
7381
7909
  continue;
7382
7910
  const analysis = analyzeSourceFile(sourceFile, checker, projectRoot);
@@ -7469,31 +7997,31 @@ var transformFile = (source, fileName, analysis) => {
7469
7997
  };
7470
7998
  var ABSOLUTE_MOBILE_TRANSFORM_PROTOCOL = ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION;
7471
7999
  var createAbsoluteMobileRouteMetadataPlugin = (options) => {
7472
- const projectRoot = resolve14(options.projectRoot ?? process.cwd());
7473
- const entry = resolve14(options.entry);
8000
+ const projectRoot = resolve15(options.projectRoot ?? process.cwd());
8001
+ const entry = resolve15(options.entry);
7474
8002
  const analyzed = analyzeProgram(createProgram(entry, projectRoot), projectRoot);
7475
8003
  return {
7476
8004
  name: "absolute-mobile-route-metadata",
7477
8005
  setup(build) {
7478
8006
  build.onLoad({ filter: SOURCE_FILTER }, async ({ path }) => {
7479
- const analysis = analyzed.get(resolve14(path));
8007
+ const analysis = analyzed.get(resolve15(path));
7480
8008
  if (!analysis)
7481
8009
  return;
7482
8010
  const source = await Bun.file(path).text();
7483
8011
  return {
7484
8012
  contents: transformFile(source, path, analysis),
7485
- loader: extname4(path).endsWith("x") ? "tsx" : "ts"
8013
+ loader: extname5(path).endsWith("x") ? "tsx" : "ts"
7486
8014
  };
7487
8015
  });
7488
8016
  }
7489
8017
  };
7490
8018
  };
7491
8019
  var inspectAbsoluteMobileRouteMetadata = (options) => {
7492
- const projectRoot = resolve14(options.projectRoot ?? process.cwd());
7493
- const entry = resolve14(options.entry);
8020
+ const projectRoot = resolve15(options.projectRoot ?? process.cwd());
8021
+ const entry = resolve15(options.entry);
7494
8022
  const analyzed = analyzeProgram(createProgram(entry, projectRoot), projectRoot);
7495
8023
  return [...analyzed.entries()].flatMap(([file, analysis]) => [...analysis.byRouteCall.values()].map(({ metadata }) => ({
7496
- file: posixPath(relative11(projectRoot, file)),
8024
+ file: posixPath(relative12(projectRoot, file)),
7497
8025
  metadata
7498
8026
  })));
7499
8027
  };
@@ -7701,6 +8229,7 @@ var http = createAbsoluteHttpClient();
7701
8229
  // src/mobile/shellHttp.ts
7702
8230
  var installAbsoluteMobileShellHttp = (origin, fetch2 = globalThis.fetch) => installAbsoluteHttpTransport(createAbsoluteHttpTransport({ fetch: fetch2, origin, runtime: "native" }));
7703
8231
  export {
8232
+ writeAbsoluteMobileGithubWorkflow,
7704
8233
  writeAbsoluteCapacitorConfig,
7705
8234
  waitForAbsoluteIosHmrLog,
7706
8235
  verifyAbsoluteMobileCompatibilityProducer,
@@ -7789,6 +8318,7 @@ export {
7789
8318
  createAbsoluteMobilePageRequest,
7790
8319
  createAbsoluteMobilePageErrorResponse,
7791
8320
  createAbsoluteMobileInvalidRequestResponse,
8321
+ createAbsoluteMobileGithubWorkflow,
7792
8322
  createAbsoluteMobileFileArtifactStore,
7793
8323
  createAbsoluteMobileCompatibilityDispatcher,
7794
8324
  createAbsoluteMobileCompatibilityArtifact,
@@ -7831,11 +8361,12 @@ export {
7831
8361
  ABSOLUTE_MOBILE_MATERIALIZED_BUNDLE_FORMAT,
7832
8362
  ABSOLUTE_MOBILE_COMPATIBILITY_FORMAT,
7833
8363
  ABSOLUTE_MOBILE_CLIENT_MANIFEST_FORMAT,
8364
+ ABSOLUTE_MOBILE_CI_WORKFLOW_FORMAT,
7834
8365
  ABSOLUTE_IOS_SIMULATOR_NAME,
7835
8366
  ABSOLUTE_IOS_RELEASE_FORMAT,
7836
8367
  ABSOLUTE_AUTH_PACKAGE,
7837
8368
  ABSOLUTE_ANDROID_RELEASE_FORMAT
7838
8369
  };
7839
8370
 
7840
- //# debugId=2B8EAAF79628B66764756E2164756E21
8371
+ //# debugId=1C9BEF9E4B461BFB64756E2164756E21
7841
8372
  //# sourceMappingURL=index.js.map