@sitepong/fastnode 0.1.0 → 0.1.2

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/index.d.cts CHANGED
@@ -4,7 +4,7 @@ export { i as cert } from './index-lt819Jgj.cjs';
4
4
  export { i as sigh } from './index-BFdNOmPJ.cjs';
5
5
  export { i as match } from './index-BQJIJlK7.cjs';
6
6
  export { i as produce } from './index-D5eihzwM.cjs';
7
- export { i as pilot } from './index-HRiaaX-Q.cjs';
7
+ export { i as pilot } from './index-D6zjGlPL.cjs';
8
8
  export { i as deliver } from './index-CWNLnSOL.cjs';
9
9
  export { i as pem } from './index-EcVvViW8.cjs';
10
10
  export { i as gym } from './index-DrUpRXRG.cjs';
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ export { i as cert } from './index-DfirmFbC.js';
4
4
  export { i as sigh } from './index-TfXqwuac.js';
5
5
  export { i as match } from './index-BN0ubxjZ.js';
6
6
  export { i as produce } from './index-B0yhu_LZ.js';
7
- export { i as pilot } from './index-DkvinY7_.js';
7
+ export { i as pilot } from './index-DHw08dUc.js';
8
8
  export { i as deliver } from './index-1Vu2cRQ2.js';
9
9
  export { i as pem } from './index-A5MimeQk.js';
10
10
  export { i as gym } from './index-DImN9PWc.js';
package/dist/index.mjs CHANGED
@@ -3004,8 +3004,8 @@ async function revokeExpiredCertificates(options) {
3004
3004
  return count;
3005
3005
  }
3006
3006
  async function importToKeychain(certData, keychainPath, keychainPassword) {
3007
- const { tmpdir: tmpdir9 } = await import('os');
3008
- const tempCertPath = join(tmpdir9(), `fastnode-cert-${Date.now()}.cer`);
3007
+ const { tmpdir: tmpdir10 } = await import('os');
3008
+ const tempCertPath = join(tmpdir10(), `fastnode-cert-${Date.now()}.cer`);
3009
3009
  await writeFile(tempCertPath, certData);
3010
3010
  try {
3011
3011
  const args = [
@@ -3994,23 +3994,13 @@ var init_produce = __esm({
3994
3994
  };
3995
3995
  }
3996
3996
  });
3997
-
3998
- // src/pilot/index.ts
3999
- var pilot_exports = {};
4000
- __export(pilot_exports, {
4001
- distributeToGroups: () => distributeToGroups,
4002
- expireBuild: () => expireBuild,
4003
- setChangelog: () => setChangelog,
4004
- uploadToTestFlight: () => uploadToTestFlight,
4005
- waitForProcessing: () => waitForProcessing
4006
- });
4007
- async function uploadToTestFlight(options) {
3997
+ async function uploadWithAltool(options) {
4008
3998
  if (!existsSync(options.ipaPath)) {
4009
3999
  throw new Error(`File not found: ${options.ipaPath}`);
4010
4000
  }
4011
4001
  const platform = options.platform ?? "ios";
4012
4002
  const timeout = options.timeout ?? 18e5;
4013
- const keyDir = await mkdtemp(join(tmpdir(), "fastnode-key-"));
4003
+ const keyDir = await mkdtemp(join(tmpdir(), "fastnode-altool-"));
4014
4004
  const keyPath = join(keyDir, `AuthKey_${options.apiKeyId}.p8`);
4015
4005
  await writeFile(keyPath, options.apiPrivateKey);
4016
4006
  return new Promise((resolve4) => {
@@ -4034,24 +4024,228 @@ async function uploadToTestFlight(options) {
4034
4024
  const timer = setTimeout(() => {
4035
4025
  child.kill("SIGTERM");
4036
4026
  }, timeout);
4037
- child.stdout.on("data", (data) => {
4027
+ const onData = (data) => {
4038
4028
  const chunk = data.toString();
4039
4029
  output += chunk;
4040
4030
  options.onOutput?.(chunk);
4031
+ };
4032
+ child.stdout.on("data", onData);
4033
+ child.stderr.on("data", onData);
4034
+ child.on("close", async (code) => {
4035
+ clearTimeout(timer);
4036
+ await unlink(keyPath).catch(() => {
4037
+ });
4038
+ await rm(keyDir, { recursive: true, force: true }).catch(() => {
4039
+ });
4040
+ resolve4({ success: code === 0, output, backend: "altool" });
4041
4041
  });
4042
- child.stderr.on("data", (data) => {
4042
+ });
4043
+ }
4044
+ var init_upload_altool = __esm({
4045
+ "src/pilot/upload-altool.ts"() {
4046
+ }
4047
+ });
4048
+ async function resolveTransporter() {
4049
+ const override = process.env.ITMSTRANSPORTER_BIN;
4050
+ if (override) {
4051
+ if (!existsSync(override)) {
4052
+ throw new Error(
4053
+ `ITMSTRANSPORTER_BIN is set to "${override}" but that path does not exist.`
4054
+ );
4055
+ }
4056
+ return override;
4057
+ }
4058
+ const candidates = process.platform === "darwin" ? [
4059
+ // Xcode 15+: Transporter.app bundled with Xcode
4060
+ "/Applications/Xcode.app/Contents/SharedFrameworks/ContentDeliveryServices.framework/Versions/A/itms/bin/iTMSTransporter",
4061
+ // Standalone Transporter.app from the Mac App Store
4062
+ "/Applications/Transporter.app/Contents/itms/bin/iTMSTransporter"
4063
+ ] : [
4064
+ "/usr/local/itms/bin/iTMSTransporter",
4065
+ "/opt/itms/bin/iTMSTransporter",
4066
+ "/usr/local/bin/iTMSTransporter"
4067
+ ];
4068
+ for (const path of candidates) {
4069
+ if (existsSync(path)) return path;
4070
+ }
4071
+ throw new Error(
4072
+ [
4073
+ "iTMSTransporter not found.",
4074
+ "",
4075
+ "Install options:",
4076
+ process.platform === "darwin" ? " - Install Xcode (includes Transporter)" : " - Download Apple's standalone iTMSTransporter package for Linux",
4077
+ " - Or set ITMSTRANSPORTER_BIN to the absolute path of the binary",
4078
+ "",
4079
+ `Searched: ${candidates.join(", ")}`
4080
+ ].join("\n")
4081
+ );
4082
+ }
4083
+ async function verifyJava() {
4084
+ return new Promise((resolve4, reject) => {
4085
+ const child = spawn("java", ["-version"], { stdio: ["ignore", "pipe", "pipe"] });
4086
+ let stderr = "";
4087
+ child.stderr.on("data", (d) => {
4088
+ stderr += d.toString();
4089
+ });
4090
+ child.on("error", (err) => {
4091
+ reject(
4092
+ new Error(
4093
+ `java not found on PATH (${err.message}). Install Java 17 LTS and ensure it is on PATH.`
4094
+ )
4095
+ );
4096
+ });
4097
+ child.on("close", (code) => {
4098
+ if (code !== 0) {
4099
+ reject(new Error(`java -version exited ${code}: ${stderr}`));
4100
+ return;
4101
+ }
4102
+ const match = stderr.match(/version "([^"]+)"/);
4103
+ resolve4({ version: match?.[1] ?? "unknown" });
4104
+ });
4105
+ });
4106
+ }
4107
+ var init_transporter_install = __esm({
4108
+ "src/pilot/transporter-install.ts"() {
4109
+ }
4110
+ });
4111
+ async function uploadWithTransporter(options) {
4112
+ if (!existsSync(options.ipaPath)) {
4113
+ throw new Error(`File not found: ${options.ipaPath}`);
4114
+ }
4115
+ await verifyJava();
4116
+ const transporterBin = await resolveTransporter();
4117
+ const platform = options.platform ?? "ios";
4118
+ const timeout = options.timeout ?? 18e5;
4119
+ const keyDir = await mkdtemp(join(tmpdir(), "fastnode-itms-"));
4120
+ const keyPath = join(keyDir, `AuthKey_${options.apiKeyId}.p8`);
4121
+ await writeFile(keyPath, options.apiPrivateKey);
4122
+ return new Promise((resolve4) => {
4123
+ const args = [
4124
+ "-m",
4125
+ "upload",
4126
+ "-assetFile",
4127
+ options.ipaPath,
4128
+ "-apiKey",
4129
+ options.apiKeyId,
4130
+ "-apiIssuer",
4131
+ options.apiIssuerId,
4132
+ // WONoPause prevents the JVM from waiting on stdin in non-TTY
4133
+ // environments (CI, LaunchAgent) where it would hang forever.
4134
+ "-WONoPause",
4135
+ "true"
4136
+ ];
4137
+ if (platform !== "ios") {
4138
+ args.push("-bundleType", platform);
4139
+ }
4140
+ const child = spawn(transporterBin, args, {
4141
+ env: {
4142
+ ...process.env,
4143
+ API_PRIVATE_KEYS_DIR: keyDir
4144
+ },
4145
+ stdio: ["ignore", "pipe", "pipe"]
4146
+ });
4147
+ let output = "";
4148
+ const timer = setTimeout(() => {
4149
+ child.kill("SIGTERM");
4150
+ }, timeout);
4151
+ const onData = (data) => {
4043
4152
  const chunk = data.toString();
4044
4153
  output += chunk;
4045
4154
  options.onOutput?.(chunk);
4046
- });
4155
+ };
4156
+ child.stdout.on("data", onData);
4157
+ child.stderr.on("data", onData);
4047
4158
  child.on("close", async (code) => {
4048
4159
  clearTimeout(timer);
4049
- await unlink(keyPath).catch(() => {
4160
+ await rm(keyDir, { recursive: true, force: true }).catch(() => {
4161
+ });
4162
+ resolve4({ success: code === 0, output, backend: "transporter" });
4163
+ });
4164
+ child.on("error", async (err) => {
4165
+ clearTimeout(timer);
4166
+ await rm(keyDir, { recursive: true, force: true }).catch(() => {
4167
+ });
4168
+ resolve4({
4169
+ success: false,
4170
+ output: output + `
4171
+ Process error: ${err.message}`,
4172
+ backend: "transporter"
4050
4173
  });
4051
- resolve4({ success: code === 0, output });
4052
4174
  });
4053
4175
  });
4054
4176
  }
4177
+ var init_upload_transporter = __esm({
4178
+ "src/pilot/upload-transporter.ts"() {
4179
+ init_transporter_install();
4180
+ }
4181
+ });
4182
+
4183
+ // src/pilot/classify.ts
4184
+ function classifyUploadError(output) {
4185
+ for (const { pattern, kind } of RULES) {
4186
+ if (pattern.test(output)) return kind;
4187
+ }
4188
+ return null;
4189
+ }
4190
+ function isTransientUploadError(output) {
4191
+ return classifyUploadError(output) !== null;
4192
+ }
4193
+ var RULES;
4194
+ var init_classify = __esm({
4195
+ "src/pilot/classify.ts"() {
4196
+ RULES = [
4197
+ // Apple's finalize-upload call returning 5xx — the most common transient
4198
+ // failure we see in practice. Example:
4199
+ // "CHANGE UPLOAD STATE TO COMPLETE (UPLOADING ASSET DESCRIPTION):
4200
+ // received status code 500; internal server error."
4201
+ { pattern: /CHANGE UPLOAD STATE TO COMPLETE/i, kind: "finalize_failed" },
4202
+ // Generic 5xx from ASC backend services
4203
+ { pattern: /status code 5\d\d/i, kind: "apple_5xx" },
4204
+ { pattern: /internal server error/i, kind: "apple_5xx" },
4205
+ { pattern: /Service Unavailable/i, kind: "apple_5xx" },
4206
+ { pattern: /Bad Gateway/i, kind: "apple_5xx" },
4207
+ // Network-level interruptions during the upload body transfer
4208
+ { pattern: /Connection reset/i, kind: "connection_reset" },
4209
+ { pattern: /SocketException/i, kind: "connection_reset" },
4210
+ { pattern: /Broken pipe/i, kind: "connection_reset" },
4211
+ // Timeouts — distinct from resets because the other side may have
4212
+ // actually processed the request, so dedupe logic may matter.
4213
+ { pattern: /Read timed out/i, kind: "network_timeout" },
4214
+ { pattern: /SocketTimeoutException/i, kind: "network_timeout" },
4215
+ { pattern: /Operation timed out/i, kind: "network_timeout" },
4216
+ // JVM-internal errors from iTMSTransporter (OOM, thread interruption, etc.)
4217
+ { pattern: /java\.lang\.OutOfMemoryError/i, kind: "transporter_jvm_error" },
4218
+ { pattern: /EOFException/i, kind: "transporter_jvm_error" }
4219
+ ];
4220
+ }
4221
+ });
4222
+
4223
+ // src/pilot/index.ts
4224
+ var pilot_exports = {};
4225
+ __export(pilot_exports, {
4226
+ classifyUploadError: () => classifyUploadError,
4227
+ distributeToGroups: () => distributeToGroups,
4228
+ expireBuild: () => expireBuild,
4229
+ isTransientUploadError: () => isTransientUploadError,
4230
+ resolveTransporter: () => resolveTransporter,
4231
+ setChangelog: () => setChangelog,
4232
+ uploadToTestFlight: () => uploadToTestFlight,
4233
+ uploadWithAltool: () => uploadWithAltool,
4234
+ uploadWithTransporter: () => uploadWithTransporter,
4235
+ verifyJava: () => verifyJava,
4236
+ waitForProcessing: () => waitForProcessing
4237
+ });
4238
+ async function uploadToTestFlight(options) {
4239
+ const backend = selectBackend(options.backend ?? "auto");
4240
+ if (backend === "altool") {
4241
+ return uploadWithAltool(options);
4242
+ }
4243
+ return uploadWithTransporter(options);
4244
+ }
4245
+ function selectBackend(pref) {
4246
+ if (pref !== "auto") return pref;
4247
+ return process.platform === "darwin" ? "altool" : "transporter";
4248
+ }
4055
4249
  async function waitForProcessing(client, params) {
4056
4250
  const timeout = params.timeout ?? 18e5;
4057
4251
  const pollInterval = params.pollInterval ?? 3e4;
@@ -4172,6 +4366,12 @@ function sleep2(ms) {
4172
4366
  var init_pilot = __esm({
4173
4367
  "src/pilot/index.ts"() {
4174
4368
  init_request();
4369
+ init_upload_altool();
4370
+ init_upload_transporter();
4371
+ init_upload_altool();
4372
+ init_upload_transporter();
4373
+ init_classify();
4374
+ init_transporter_install();
4175
4375
  }
4176
4376
  });
4177
4377
  async function loadMetadata(metadataPath) {
@@ -4275,9 +4475,9 @@ var init_platform = __esm({
4275
4475
  // src/xcode/upload.ts
4276
4476
  var upload_exports = {};
4277
4477
  __export(upload_exports, {
4278
- uploadWithAltool: () => uploadWithAltool
4478
+ uploadWithAltool: () => uploadWithAltool2
4279
4479
  });
4280
- async function uploadWithAltool(options) {
4480
+ async function uploadWithAltool2(options) {
4281
4481
  requireMacOS("altool upload");
4282
4482
  let keyDir;
4283
4483
  if (options.apiPrivateKey && !options.apiKeyPath) {
@@ -4386,8 +4586,8 @@ async function uploadToAppStore(options) {
4386
4586
  if (!options.skipBinaryUpload) {
4387
4587
  const binaryPath = options.ipaPath ?? options.pkgPath;
4388
4588
  if (binaryPath && options.apiKeyId && options.apiIssuerId) {
4389
- const { uploadWithAltool: uploadWithAltool2 } = await Promise.resolve().then(() => (init_upload(), upload_exports));
4390
- await uploadWithAltool2({
4589
+ const { uploadWithAltool: uploadWithAltool3 } = await Promise.resolve().then(() => (init_upload(), upload_exports));
4590
+ await uploadWithAltool3({
4391
4591
  filePath: binaryPath,
4392
4592
  apiKeyId: options.apiKeyId,
4393
4593
  apiIssuerId: options.apiIssuerId,
@@ -5363,8 +5563,8 @@ async function captureScreenshots(options) {
5363
5563
  const outputDir = options.outputDirectory ?? join(process.cwd(), "screenshots");
5364
5564
  const retries = options.numberOfRetries ?? 1;
5365
5565
  if (options.clearPreviousScreenshots && existsSync(outputDir)) {
5366
- const { rm: rm3 } = await import('fs/promises');
5367
- await rm3(outputDir, { recursive: true, force: true });
5566
+ const { rm: rm5 } = await import('fs/promises');
5567
+ await rm5(outputDir, { recursive: true, force: true });
5368
5568
  }
5369
5569
  mkdirSync(outputDir, { recursive: true });
5370
5570
  const screenshots = {};
@@ -6743,14 +6943,14 @@ var init_building = __esm({
6743
6943
  name: "clean_build_artifacts",
6744
6944
  description: "Remove build artifacts (IPA, dSYM, etc.)",
6745
6945
  async run(params, ctx) {
6746
- const { rm: rm3 } = await import('fs/promises');
6946
+ const { rm: rm5 } = await import('fs/promises');
6747
6947
  const paths = [
6748
6948
  ctx.get("IPA_OUTPUT_PATH"),
6749
6949
  ctx.get("PKG_OUTPUT_PATH"),
6750
6950
  ctx.get("DSYM_OUTPUT_PATH")
6751
6951
  ].filter(Boolean);
6752
6952
  for (const p of paths) {
6753
- await rm3(p, { force: true }).catch(() => {
6953
+ await rm5(p, { force: true }).catch(() => {
6754
6954
  });
6755
6955
  }
6756
6956
  return { cleaned: paths };
@@ -7787,7 +7987,7 @@ __export(xcode_exports, {
7787
7987
  setBuildNumber: () => setBuildNumber,
7788
7988
  setVersionNumber: () => setVersionNumber,
7789
7989
  updateSigningSettings: () => updateSigningSettings,
7790
- uploadWithAltool: () => uploadWithAltool
7990
+ uploadWithAltool: () => uploadWithAltool2
7791
7991
  });
7792
7992
  init_platform();
7793
7993