@applift/core 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +14 -10
- package/dist/index.mjs +205 -32
- package/dist/{plugin-T6zXsmt1.d.mts → plugin-DzhwzVfu.d.mts} +45 -2
- package/dist/plugins/index.d.mts +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as
|
|
1
|
+
import { $ as rnAdapter, A as StoreConfigSchema, B as StageResult, C as CredentialsProfile, D as ProjectConfig, E as GlobalConfigSchema, F as ChannelContext, G as detectBundleIds, H as BundleIds, I as ChannelEvent, J as findArtifacts, K as detectFramework, L as ChannelRegistry, M as StoresSchema, N as Channel, O as ProjectConfigSchema, P as ChannelCapabilities, Q as nativeIosAdapter, R as ReleasePlanEntry, S as CredentialsFileSchema, T as GlobalConfig, U as FrameworkAdapter, V as SubmitResult, W as Platform, X as nativeAndroidAdapter, Y as flutterAdapter, Z as nativeHarmonyAdapter, _ as appendEntry, a as QypubUserConfig, b as BetaConfigSchema, c as PipelineInput, d as runStage, et as tauriAdapter, f as runSubmit, g as HistoryQuery, h as HistoryEvent, i as QypubPlugin, j as Stores, k as StoreConfig, l as PipelineSummary, m as HistoryEntry, n as PluginHookName, o as defineConfig, p as HISTORY_PATH, q as electronAdapter, r as PluginHost, s as resolvePlugins, t as HookContext, u as PipelineSummaryEntry, v as readEntries, w as CredentialsProfileSchema, x as CredentialsFile, y as BetaConfig, z as ReviewStatus } from "./plugin-DzhwzVfu.mjs";
|
|
2
2
|
//#region src/registry.d.ts
|
|
3
3
|
export declare class DefaultChannelRegistry implements ChannelRegistry {
|
|
4
4
|
private readonly channels;
|
|
@@ -252,11 +252,9 @@ export declare class VivoChannel implements Channel {
|
|
|
252
252
|
stage(ctx: ChannelContext): Promise<StageResult>;
|
|
253
253
|
submit(ctx: ChannelContext): Promise<SubmitResult>;
|
|
254
254
|
/**
|
|
255
|
-
* 审核状态查询: 复用 app.query.details 的 data.
|
|
256
|
-
*
|
|
257
|
-
*
|
|
258
|
-
* 注意:该编号映射未在现行中国站文档成文(国际站同型接口字典编号整体错一位),需真机校准;
|
|
259
|
-
* 交叉见证:apkgo vivo.go 读 data.status 且编号不同(1草稿/2待审核/3通过/4不通过/5撤销),冲突以真机为准。
|
|
255
|
+
* 审核状态查询: 复用 app.query.details 的 data.status(apkgo vivo.go mapVivoAuditState 权威,
|
|
256
|
+
* 2026-10 源码仲裁:编号 1=草稿 2=待审核 3=审核通过 4=审核不通过 5=已撤销;
|
|
257
|
+
* 旧 auditStatus 字段与 0/1/2 编号表系 v1 python 误记,已弃用)。
|
|
260
258
|
*/
|
|
261
259
|
status(ctx: Pick<ChannelContext, "credentials" | "target">): Promise<ReviewStatus>;
|
|
262
260
|
/** 驳回原因字段名文档未明确,按常见命名兜底取(auditMessage/auditMsg) */
|
|
@@ -313,7 +311,7 @@ export declare function getHarmonyAppId(opts: {
|
|
|
313
311
|
bundleName: string;
|
|
314
312
|
}): Promise<string>;
|
|
315
313
|
export declare class AgcHarmonyChannel implements Channel {
|
|
316
|
-
readonly id = "agc
|
|
314
|
+
readonly id = "agc";
|
|
317
315
|
readonly label = "华为 AGC(鸿蒙)";
|
|
318
316
|
readonly capabilities: ChannelCapabilities;
|
|
319
317
|
readonly errorHints: {
|
|
@@ -340,10 +338,16 @@ export declare class AgcHarmonyChannel implements Channel {
|
|
|
340
338
|
/**
|
|
341
339
|
* 测试发布(releaseType=6,2026-10 起走 Testing API——旧 app-package-info 直绑链路已被华为下线,
|
|
342
340
|
* 其 releaseType 枚举仅剩 1=全网 / 7=企业非公开):
|
|
343
|
-
* 上传 .
|
|
344
|
-
*
|
|
341
|
+
* 上传 .app → 新建测试版本(testType 3=邀请测试 4=公开测试)→ 添加测试软件包 → 等云端编译 → 更新测试版本绑定;
|
|
342
|
+
* target.submitTest='true' 时:(可选按 testGroup 绑测试群组)自动提交测试版本审核;否则由控制台人工完成。
|
|
345
343
|
*/
|
|
346
344
|
private uploadBeta;
|
|
345
|
+
/**
|
|
346
|
+
* 按群组名查测试群组 groupId(AppTest API GET /test-group/list,appId 走 header,rtnCode 外壳)。
|
|
347
|
+
* 分页遍历;匹配不到报错提示到控制台建组。
|
|
348
|
+
* 文档: agc-help-test-api-get-test-grouplist-0000002271000717
|
|
349
|
+
*/
|
|
350
|
+
private resolveTestGroupId;
|
|
347
351
|
/** v1 更新文案段(releaseHarmonyApp step 4 / uploadToAgc 尾段):查默认语言 → 写 newFeatures,失败仅警告不阻断 */
|
|
348
352
|
private updateReleaseNotes;
|
|
349
353
|
}
|
|
@@ -407,4 +411,4 @@ export interface ArtifactVersion {
|
|
|
407
411
|
}
|
|
408
412
|
export declare function readArtifactVersion(artifactPath: string): ArtifactVersion | undefined;
|
|
409
413
|
//#endregion
|
|
410
|
-
export { BundleIds, Channel, ChannelCapabilities, ChannelContext, ChannelEvent, ChannelRegistry, CredentialsFile, CredentialsFileSchema, CredentialsProfile, CredentialsProfileSchema, FrameworkAdapter, GlobalConfig, GlobalConfigSchema, HISTORY_PATH, HistoryEntry, HistoryEvent, HistoryQuery, HookContext, PipelineInput, PipelineSummary, PipelineSummaryEntry, Platform, PluginHookName, PluginHost, ProjectConfig, ProjectConfigSchema, QypubPlugin, QypubUserConfig, ReleasePlanEntry, ReviewStatus, StageResult, StoreConfig, StoreConfigSchema, Stores, StoresSchema, SubmitResult, appendEntry, defineConfig, detectBundleIds, detectFramework, electronAdapter, findArtifacts, flutterAdapter, nativeAndroidAdapter, nativeHarmonyAdapter, nativeIosAdapter, readEntries, resolvePlugins, rnAdapter, runStage, runSubmit, tauriAdapter };
|
|
414
|
+
export { BetaConfig, BetaConfigSchema, BundleIds, Channel, ChannelCapabilities, ChannelContext, ChannelEvent, ChannelRegistry, CredentialsFile, CredentialsFileSchema, CredentialsProfile, CredentialsProfileSchema, FrameworkAdapter, GlobalConfig, GlobalConfigSchema, HISTORY_PATH, HistoryEntry, HistoryEvent, HistoryQuery, HookContext, PipelineInput, PipelineSummary, PipelineSummaryEntry, Platform, PluginHookName, PluginHost, ProjectConfig, ProjectConfigSchema, QypubPlugin, QypubUserConfig, ReleasePlanEntry, ReviewStatus, StageResult, StoreConfig, StoreConfigSchema, Stores, StoresSchema, SubmitResult, appendEntry, defineConfig, detectBundleIds, detectFramework, electronAdapter, findArtifacts, flutterAdapter, nativeAndroidAdapter, nativeHarmonyAdapter, nativeIosAdapter, readEntries, resolvePlugins, rnAdapter, runStage, runSubmit, tauriAdapter };
|
package/dist/index.mjs
CHANGED
|
@@ -47,7 +47,32 @@ const StoresSchema = z.union([z.record(z.string(), z.union([StoreConfigSchema, z
|
|
|
47
47
|
if (Array.isArray(stores)) return Object.fromEntries(stores.map((id) => [id, {}]));
|
|
48
48
|
return Object.fromEntries(Object.entries(stores).map(([id, cfg]) => [id, typeof cfg === "string" ? { appId: cfg } : cfg]));
|
|
49
49
|
}).default({});
|
|
50
|
-
/** 项目级配置(applift.config.ts
|
|
50
|
+
/** 项目级配置(applift.config.ts 的形状);beta 段见上方 BetaConfigSchema */
|
|
51
|
+
/**
|
|
52
|
+
* 内测分发配置(applift beta 无平台参数时并行发布的渠道开关):
|
|
53
|
+
* - pgyer: 蒲公英多平台上传(缺省只发 android)
|
|
54
|
+
* - agc: AGC 邀请测试(Testing API,submit=true 上传绑定后自动提审)
|
|
55
|
+
* - testflight: App Store Connect 上传(ipa 进 TestFlight)
|
|
56
|
+
*/
|
|
57
|
+
const BetaConfigSchema = z.object({
|
|
58
|
+
pgyer: z.object({
|
|
59
|
+
platforms: z.array(z.enum([
|
|
60
|
+
"android",
|
|
61
|
+
"harmony",
|
|
62
|
+
"ios"
|
|
63
|
+
])).default(["android"]),
|
|
64
|
+
installPassword: z.string().optional()
|
|
65
|
+
}).optional(),
|
|
66
|
+
agc: z.object({
|
|
67
|
+
/** 上传绑定后自动提交测试审核(默认 false:只到「已就绪」,群组/提审到控制台人工完成) */
|
|
68
|
+
submit: z.boolean().default(false),
|
|
69
|
+
/** 测试群组名(submit 时按名查 groupId 绑定;匹配不到报错提示到控制台建组) */
|
|
70
|
+
group: z.string().optional(),
|
|
71
|
+
/** 3=邀请测试(默认)4=公开测试 */
|
|
72
|
+
testType: z.union([z.literal(3), z.literal(4)]).default(3)
|
|
73
|
+
}).optional(),
|
|
74
|
+
testflight: z.object({ note: z.string().optional() }).optional()
|
|
75
|
+
});
|
|
51
76
|
const ProjectConfigSchema = z.object({
|
|
52
77
|
/** 项目显示名 */
|
|
53
78
|
name: z.string().optional(),
|
|
@@ -83,7 +108,9 @@ const ProjectConfigSchema = z.object({
|
|
|
83
108
|
windows: z.array(z.string()).optional(),
|
|
84
109
|
macos: z.array(z.string()).optional(),
|
|
85
110
|
linux: z.array(z.string()).optional()
|
|
86
|
-
}).catchall(z.array(z.string()).optional()).optional()
|
|
111
|
+
}).catchall(z.array(z.string()).optional()).optional(),
|
|
112
|
+
/** 内测分发(beta 无平台参数时的多渠道并行配置) */
|
|
113
|
+
beta: BetaConfigSchema.optional()
|
|
87
114
|
});
|
|
88
115
|
/** 全局行为配置(~/.applift/config.toml) */
|
|
89
116
|
const GlobalConfigSchema = z.object({
|
|
@@ -855,9 +882,9 @@ function required$5(ctx, key, where) {
|
|
|
855
882
|
* sig = RSA_encrypt(证书公钥, JSON({sig: [{name, hash: MD5}...], password}))
|
|
856
883
|
* 分段: 1024bit key → 每段 117 字节(128 - PKCS1 padding 11)
|
|
857
884
|
* 链路: /dev/query 校验账号对包名权限 + 提审前版本回归预检 → /dev/push 上传即提审(synchroType=1 更新包,
|
|
858
|
-
*
|
|
859
|
-
*
|
|
860
|
-
*
|
|
885
|
+
* icon 现行文档(pId=1134,2026-02)标必选,apkgo 同(每次 push 必带);旧官方 PDF(pId=33)标可选,
|
|
886
|
+
* 分歧按现行文档从严处理——applift 默认从工程 mipmap 自动发现(android.stores.xiaomi.icon 可覆盖),
|
|
887
|
+
* 未找到才中止;privacyUrl 是否强制仍待真机验证(apkgo 未传该字段)。
|
|
861
888
|
* 另 2026-02-04 起 testAccount 须用新结构化格式(如 {"zh_CN":{"accounts":[...]}}),当前未传暂不受影响。
|
|
862
889
|
* 移植自(MIT): AngChow/android-publish scripts/_mi_common.py + mi_submit.py
|
|
863
890
|
* 官方文档: https://dev.mi.com/xiaomihyperos/documentation/detail?pId=1134
|
|
@@ -959,6 +986,9 @@ var XiaomiChannel = class {
|
|
|
959
986
|
const localVc = Number(ctx.target.versionCode);
|
|
960
987
|
const liveVc = Number(query.packageInfo?.onlineVersionCode ?? query.packageInfo?.versionCode);
|
|
961
988
|
if (Number.isFinite(localVc) && Number.isFinite(liveVc) && localVc < liveVc) throw new Error(`小米提审中止:待提审 versionCode ${localVc} 低于线上 ${liveVc}(版本回退),请确认 APK 版本或项目配置`);
|
|
989
|
+
const iconPath = String(ctx.target.icon ?? "");
|
|
990
|
+
if (!iconPath) throw new Error("小米提审缺少 icon:applift.config.ts → android.stores.xiaomi.icon 配置图标路径(官方必选,apkgo 同)");
|
|
991
|
+
if (!fs.existsSync(iconPath)) throw new Error(`小米 icon 文件不存在: ${iconPath}`);
|
|
962
992
|
const appInfo = {
|
|
963
993
|
appName,
|
|
964
994
|
packageName: pkgName,
|
|
@@ -970,7 +1000,7 @@ var XiaomiChannel = class {
|
|
|
970
1000
|
synchroType: 1
|
|
971
1001
|
};
|
|
972
1002
|
const requestJson = JSON.stringify(request);
|
|
973
|
-
const sig = generateMiSig(requestJson, [["apk", ctx.artifactPath]], password, certPem);
|
|
1003
|
+
const sig = generateMiSig(requestJson, [["apk", ctx.artifactPath], ["icon", iconPath]], password, certPem);
|
|
974
1004
|
const fileName = path.basename(ctx.artifactPath);
|
|
975
1005
|
ctx.emit({
|
|
976
1006
|
type: "phase",
|
|
@@ -981,6 +1011,7 @@ var XiaomiChannel = class {
|
|
|
981
1011
|
form.append("RequestData", requestJson);
|
|
982
1012
|
form.append("SIG", sig);
|
|
983
1013
|
form.append("apk", new Blob([fs.readFileSync(ctx.artifactPath)]), fileName);
|
|
1014
|
+
form.append("icon", new Blob([fs.readFileSync(iconPath)]), path.basename(iconPath));
|
|
984
1015
|
const res = await fetch(`${MI_API_BASE}/dev/push`, {
|
|
985
1016
|
method: "POST",
|
|
986
1017
|
body: form,
|
|
@@ -1356,6 +1387,7 @@ var OppoChannel = class {
|
|
|
1356
1387
|
type: "warn",
|
|
1357
1388
|
message: inReview ? "errno=911215 应用审核中:该版本已在 OPPO 审核队列,本次未重复创建任务" : "errno=911216 版本更新任务处理中:上一提交任务仍在处理,本次未创建新任务,稍后可用 status 查询审核状态"
|
|
1358
1389
|
});
|
|
1390
|
+
if (!inReview) await this.pollTaskState(ctx, auth, versionCode);
|
|
1359
1391
|
ctx.emit({
|
|
1360
1392
|
type: "phase",
|
|
1361
1393
|
phase: "done",
|
|
@@ -1502,7 +1534,7 @@ function commonParams(accessKey, method) {
|
|
|
1502
1534
|
timestamp: tsMillis(),
|
|
1503
1535
|
format: "json",
|
|
1504
1536
|
v: "1.0",
|
|
1505
|
-
sign_method: "hmac",
|
|
1537
|
+
sign_method: "hmac-sha256",
|
|
1506
1538
|
target_app_key: "developer"
|
|
1507
1539
|
};
|
|
1508
1540
|
}
|
|
@@ -1661,38 +1693,44 @@ var VivoChannel = class {
|
|
|
1661
1693
|
};
|
|
1662
1694
|
}
|
|
1663
1695
|
/**
|
|
1664
|
-
* 审核状态查询: 复用 app.query.details 的 data.
|
|
1665
|
-
*
|
|
1666
|
-
*
|
|
1667
|
-
* 注意:该编号映射未在现行中国站文档成文(国际站同型接口字典编号整体错一位),需真机校准;
|
|
1668
|
-
* 交叉见证:apkgo vivo.go 读 data.status 且编号不同(1草稿/2待审核/3通过/4不通过/5撤销),冲突以真机为准。
|
|
1696
|
+
* 审核状态查询: 复用 app.query.details 的 data.status(apkgo vivo.go mapVivoAuditState 权威,
|
|
1697
|
+
* 2026-10 源码仲裁:编号 1=草稿 2=待审核 3=审核通过 4=审核不通过 5=已撤销;
|
|
1698
|
+
* 旧 auditStatus 字段与 0/1/2 编号表系 v1 python 误记,已弃用)。
|
|
1669
1699
|
*/
|
|
1670
1700
|
async status(ctx) {
|
|
1671
1701
|
required$3(ctx, "pkgName", "审核状态查询必需");
|
|
1672
1702
|
const data = await this.queryDetails(ctx);
|
|
1673
|
-
const
|
|
1674
|
-
if (
|
|
1703
|
+
const st = data.status ?? data.auditStatus ?? data.audit_status;
|
|
1704
|
+
if (st === void 0) return {
|
|
1675
1705
|
state: "unknown",
|
|
1676
|
-
raw: `app.query.details 无
|
|
1706
|
+
raw: `app.query.details 无 status: ${JSON.stringify(data).slice(0, 200)}`
|
|
1677
1707
|
};
|
|
1678
|
-
const num = Number(
|
|
1708
|
+
const num = Number(st);
|
|
1679
1709
|
if (!Number.isFinite(num)) return {
|
|
1680
1710
|
state: "unknown",
|
|
1681
|
-
raw: `
|
|
1711
|
+
raw: `status=${String(st)}`
|
|
1682
1712
|
};
|
|
1683
1713
|
switch (num) {
|
|
1684
|
-
case
|
|
1714
|
+
case 2: return { state: "reviewing" };
|
|
1715
|
+
case 3: return {
|
|
1685
1716
|
state: "approved",
|
|
1686
1717
|
live: true
|
|
1687
1718
|
};
|
|
1688
|
-
case
|
|
1689
|
-
case 2: return {
|
|
1719
|
+
case 4: return {
|
|
1690
1720
|
state: "rejected",
|
|
1691
1721
|
reason: this.auditReason(data)
|
|
1692
1722
|
};
|
|
1723
|
+
case 1: return {
|
|
1724
|
+
state: "unknown",
|
|
1725
|
+
raw: "status=1(草稿,未提交审核)"
|
|
1726
|
+
};
|
|
1727
|
+
case 5: return {
|
|
1728
|
+
state: "unknown",
|
|
1729
|
+
raw: "status=5(已撤销)"
|
|
1730
|
+
};
|
|
1693
1731
|
default: return {
|
|
1694
1732
|
state: "unknown",
|
|
1695
|
-
raw: `
|
|
1733
|
+
raw: `status=${num}(未验证编号)`
|
|
1696
1734
|
};
|
|
1697
1735
|
}
|
|
1698
1736
|
}
|
|
@@ -1952,6 +1990,55 @@ function required$2(ctx, key, where) {
|
|
|
1952
1990
|
return v;
|
|
1953
1991
|
}
|
|
1954
1992
|
//#endregion
|
|
1993
|
+
//#region src/channels/shared/apk-abi.ts
|
|
1994
|
+
/**
|
|
1995
|
+
* APK(zip)CPU ABI 探测——纯 Node 解析 zip 中央目录(零依赖、不解压内容)。
|
|
1996
|
+
* 用途:应用宝 update_app 的 apk32_flag/apk64_flag 分支(apkgo tencent.go isAPK64BitOnly 同构)。
|
|
1997
|
+
*/
|
|
1998
|
+
const EOCD_MAGIC = 101010256;
|
|
1999
|
+
const CEN_MAGIC = 33639248;
|
|
2000
|
+
/** 列出 APK 内 lib/<abi>/ 出现过的 ABI 名;非 zip/无 lib 段返回空数组(按 32/64 兼容处理) */
|
|
2001
|
+
function listApkLibAbis(apkPath) {
|
|
2002
|
+
const fd = fs.openSync(apkPath, "r");
|
|
2003
|
+
try {
|
|
2004
|
+
const size = fs.fstatSync(fd).size;
|
|
2005
|
+
const tailLen = Math.min(size, 65557);
|
|
2006
|
+
const tail = Buffer.alloc(tailLen);
|
|
2007
|
+
fs.readSync(fd, tail, 0, tailLen, size - tailLen);
|
|
2008
|
+
let eocd = -1;
|
|
2009
|
+
for (let i = tail.length - 22; i >= 0; i--) if (tail.readUInt32LE(i) === EOCD_MAGIC) {
|
|
2010
|
+
eocd = i;
|
|
2011
|
+
break;
|
|
2012
|
+
}
|
|
2013
|
+
if (eocd < 0) return [];
|
|
2014
|
+
const count = tail.readUInt16LE(eocd + 10);
|
|
2015
|
+
let offset = tail.readUInt32LE(eocd + 16);
|
|
2016
|
+
const abis = /* @__PURE__ */ new Set();
|
|
2017
|
+
for (let i = 0; i < count; i++) {
|
|
2018
|
+
const hdr = Buffer.alloc(46);
|
|
2019
|
+
if (fs.readSync(fd, hdr, 0, 46, offset) < 46) break;
|
|
2020
|
+
if (hdr.readUInt32LE(0) !== CEN_MAGIC) break;
|
|
2021
|
+
const nameLen = hdr.readUInt16LE(28);
|
|
2022
|
+
const extraLen = hdr.readUInt16LE(30);
|
|
2023
|
+
const commentLen = hdr.readUInt16LE(32);
|
|
2024
|
+
const nameBuf = Buffer.alloc(nameLen);
|
|
2025
|
+
if (fs.readSync(fd, nameBuf, 0, nameLen, offset + 46) < nameLen) break;
|
|
2026
|
+
const m = nameBuf.toString("utf8").match(/^lib\/([^/]+)\//);
|
|
2027
|
+
if (m?.[1]) abis.add(m[1]);
|
|
2028
|
+
offset += 46 + nameLen + extraLen + commentLen;
|
|
2029
|
+
}
|
|
2030
|
+
return [...abis];
|
|
2031
|
+
} finally {
|
|
2032
|
+
fs.closeSync(fd);
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
/** 是否 arm64-only 包:含 lib/ 且全部为 arm64-v8a(apkgo isAPK64BitOnly 同构;无 native 库返回 false) */
|
|
2036
|
+
function isApkArm64Only(apkPath) {
|
|
2037
|
+
const abis = listApkLibAbis(apkPath);
|
|
2038
|
+
if (abis.length === 0) return false;
|
|
2039
|
+
return abis.every((a) => a === "arm64-v8a");
|
|
2040
|
+
}
|
|
2041
|
+
//#endregion
|
|
1955
2042
|
//#region src/channels/yyb.ts
|
|
1956
2043
|
/**
|
|
1957
2044
|
* 腾讯应用宝(安卓 APK)渠道。
|
|
@@ -2086,9 +2173,16 @@ var YybChannel = class {
|
|
|
2086
2173
|
const businessParams = {
|
|
2087
2174
|
pkg_name: pkgName,
|
|
2088
2175
|
app_id: appId,
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2176
|
+
...isApkArm64Only(ctx.artifactPath) ? {
|
|
2177
|
+
apk32_flag: "2",
|
|
2178
|
+
apk64_flag: "1",
|
|
2179
|
+
apk64_file_serial_number: stagedInfo.serialNumber,
|
|
2180
|
+
apk64_file_md5: stagedInfo.md5
|
|
2181
|
+
} : {
|
|
2182
|
+
apk32_flag: "1",
|
|
2183
|
+
apk32_file_serial_number: stagedInfo.serialNumber,
|
|
2184
|
+
apk32_file_md5: stagedInfo.md5
|
|
2185
|
+
},
|
|
2092
2186
|
feature: ctx.updateDescription ?? ""
|
|
2093
2187
|
};
|
|
2094
2188
|
if (ctx.releaseTime) {
|
|
@@ -2180,6 +2274,8 @@ var YybChannel = class {
|
|
|
2180
2274
|
const BASE = "https://connect-api.cloud.huawei.com/api";
|
|
2181
2275
|
const COMPILE_TIMEOUT_MS = 9e5;
|
|
2182
2276
|
const COMPILE_POLL_MS = 15e3;
|
|
2277
|
+
/** AppTest 测试群组 API 前缀(与 publish API 同域不同路径段) */
|
|
2278
|
+
const APP_TEST_BASE = "https://connect-api.cloud.huawei.com/api/app-test/v1";
|
|
2183
2279
|
/** AGC JSON API 封装:判 ret.code !== 0 抛错 —— v1 agc.mjs agcJson 原样 */
|
|
2184
2280
|
async function agcJson(url, init, context) {
|
|
2185
2281
|
const res = await fetch(url, init);
|
|
@@ -2225,7 +2321,7 @@ async function getDefaultLang(headers, appId) {
|
|
|
2225
2321
|
return (await agcJson(`${BASE}/publish/v3/app-info?${qs}`, { headers }, "查询应用信息")).appInfo?.defaultLang || "zh-CN";
|
|
2226
2322
|
}
|
|
2227
2323
|
var AgcHarmonyChannel = class {
|
|
2228
|
-
id = "agc
|
|
2324
|
+
id = "agc";
|
|
2229
2325
|
label = "华为 AGC(鸿蒙)";
|
|
2230
2326
|
capabilities = {
|
|
2231
2327
|
stage: true,
|
|
@@ -2278,7 +2374,7 @@ var AgcHarmonyChannel = class {
|
|
|
2278
2374
|
artifactVersion: "",
|
|
2279
2375
|
action: "stage-only",
|
|
2280
2376
|
afterApproval: "none(beta)",
|
|
2281
|
-
notes: "Testing API 邀请测试:上传→新建测试版本→绑定软件包;提交审核与测试群组到控制台完成,不自动提审"
|
|
2377
|
+
notes: ctx.target.submitTest === "true" ? "Testing API 邀请测试:上传→新建测试版本→绑定软件包→(可选绑测试群组)自动提交测试审核" : "Testing API 邀请测试:上传→新建测试版本→绑定软件包;提交审核与测试群组到控制台完成,不自动提审"
|
|
2282
2378
|
};
|
|
2283
2379
|
return {
|
|
2284
2380
|
channel: this.id,
|
|
@@ -2309,7 +2405,7 @@ var AgcHarmonyChannel = class {
|
|
|
2309
2405
|
async submit(ctx) {
|
|
2310
2406
|
if (ctx.target.releaseType === "6") return {
|
|
2311
2407
|
ok: false,
|
|
2312
|
-
error: "AGC 测试发布(releaseType=6
|
|
2408
|
+
error: "AGC 测试发布(releaseType=6)的自动提审走 beta 配置 test['agc'].submit=true(上传绑定后自动提交测试版本审核)"
|
|
2313
2409
|
};
|
|
2314
2410
|
const { clientId, token, headers } = await this.authHeaders(ctx);
|
|
2315
2411
|
const appId = await this.resolveAppId(ctx, clientId, token);
|
|
@@ -2470,8 +2566,8 @@ var AgcHarmonyChannel = class {
|
|
|
2470
2566
|
/**
|
|
2471
2567
|
* 测试发布(releaseType=6,2026-10 起走 Testing API——旧 app-package-info 直绑链路已被华为下线,
|
|
2472
2568
|
* 其 releaseType 枚举仅剩 1=全网 / 7=企业非公开):
|
|
2473
|
-
* 上传 .
|
|
2474
|
-
*
|
|
2569
|
+
* 上传 .app → 新建测试版本(testType 3=邀请测试 4=公开测试)→ 添加测试软件包 → 等云端编译 → 更新测试版本绑定;
|
|
2570
|
+
* target.submitTest='true' 时:(可选按 testGroup 绑测试群组)自动提交测试版本审核;否则由控制台人工完成。
|
|
2475
2571
|
*/
|
|
2476
2572
|
async uploadBeta(ctx, appId, headers) {
|
|
2477
2573
|
const fileName = path.basename(ctx.artifactPath);
|
|
@@ -2518,6 +2614,7 @@ var AgcHarmonyChannel = class {
|
|
|
2518
2614
|
type: "progress",
|
|
2519
2615
|
detail: "文件上传完成"
|
|
2520
2616
|
});
|
|
2617
|
+
const testType = ctx.target.testType === "4" ? 4 : 3;
|
|
2521
2618
|
const versionId = (await agcJson(`${BASE}/publish/v2/test/app/version?appId=${encodeURIComponent(appId)}`, {
|
|
2522
2619
|
method: "POST",
|
|
2523
2620
|
headers: {
|
|
@@ -2526,7 +2623,7 @@ var AgcHarmonyChannel = class {
|
|
|
2526
2623
|
},
|
|
2527
2624
|
body: JSON.stringify({
|
|
2528
2625
|
releaseType: 6,
|
|
2529
|
-
testType
|
|
2626
|
+
testType,
|
|
2530
2627
|
testDesc: (ctx.updateDescription ?? "applift 测试发布").slice(0, 50)
|
|
2531
2628
|
})
|
|
2532
2629
|
}, "新建测试版本")).versionId ?? "";
|
|
@@ -2563,16 +2660,92 @@ var AgcHarmonyChannel = class {
|
|
|
2563
2660
|
pkgId
|
|
2564
2661
|
})
|
|
2565
2662
|
}, "绑定测试软件包");
|
|
2663
|
+
if (ctx.target.submitTest === "true") {
|
|
2664
|
+
const groupName = ctx.target.testGroup?.trim();
|
|
2665
|
+
if (groupName) {
|
|
2666
|
+
const groupId = await this.resolveTestGroupId(ctx, appId, groupName, headers);
|
|
2667
|
+
await agcJson(`${BASE}/publish/v2/test/app/version?appId=${encodeURIComponent(appId)}`, {
|
|
2668
|
+
method: "PUT",
|
|
2669
|
+
headers: {
|
|
2670
|
+
...headers,
|
|
2671
|
+
"Content-Type": "application/json"
|
|
2672
|
+
},
|
|
2673
|
+
body: JSON.stringify({
|
|
2674
|
+
versionId,
|
|
2675
|
+
pkgId,
|
|
2676
|
+
openTestInfo: { testTaskInfo: { groupInfos: [{
|
|
2677
|
+
groupId,
|
|
2678
|
+
groupName
|
|
2679
|
+
}] } }
|
|
2680
|
+
})
|
|
2681
|
+
}, "绑定测试群组");
|
|
2682
|
+
ctx.emit({
|
|
2683
|
+
type: "progress",
|
|
2684
|
+
detail: `测试群组「${groupName}」已绑定(groupId: ${groupId})`
|
|
2685
|
+
});
|
|
2686
|
+
}
|
|
2687
|
+
ctx.emit({
|
|
2688
|
+
type: "phase",
|
|
2689
|
+
phase: "submit",
|
|
2690
|
+
message: "提交测试版本审核…"
|
|
2691
|
+
});
|
|
2692
|
+
await agcJson(`${BASE}/publish/v2/test/app/version/submit?appId=${encodeURIComponent(appId)}`, {
|
|
2693
|
+
method: "POST",
|
|
2694
|
+
headers: {
|
|
2695
|
+
...headers,
|
|
2696
|
+
"Content-Type": "application/json"
|
|
2697
|
+
},
|
|
2698
|
+
body: JSON.stringify({ versionId })
|
|
2699
|
+
}, "提交测试审核");
|
|
2700
|
+
ctx.emit({
|
|
2701
|
+
type: "phase",
|
|
2702
|
+
phase: "done",
|
|
2703
|
+
message: `测试版本已提交审核(versionId: ${versionId})`
|
|
2704
|
+
});
|
|
2705
|
+
return {
|
|
2706
|
+
ok: true,
|
|
2707
|
+
ref: versionId
|
|
2708
|
+
};
|
|
2709
|
+
}
|
|
2566
2710
|
ctx.emit({
|
|
2567
2711
|
type: "phase",
|
|
2568
2712
|
phase: "done",
|
|
2569
|
-
message: "
|
|
2713
|
+
message: "测试版本已就绪(未提交审核);到控制台提交或配置 test['agc'].submit 自动提审"
|
|
2570
2714
|
});
|
|
2571
2715
|
return {
|
|
2572
2716
|
ok: true,
|
|
2573
2717
|
ref: versionId
|
|
2574
2718
|
};
|
|
2575
2719
|
}
|
|
2720
|
+
/**
|
|
2721
|
+
* 按群组名查测试群组 groupId(AppTest API GET /test-group/list,appId 走 header,rtnCode 外壳)。
|
|
2722
|
+
* 分页遍历;匹配不到报错提示到控制台建组。
|
|
2723
|
+
* 文档: agc-help-test-api-get-test-grouplist-0000002271000717
|
|
2724
|
+
*/
|
|
2725
|
+
async resolveTestGroupId(ctx, appId, groupName, headers) {
|
|
2726
|
+
ctx.emit({
|
|
2727
|
+
type: "progress",
|
|
2728
|
+
detail: `按群组名「${groupName}」查询 AGC 测试群组…`
|
|
2729
|
+
});
|
|
2730
|
+
for (let current = 1; current <= 50; current++) {
|
|
2731
|
+
const qs = new URLSearchParams({
|
|
2732
|
+
current: String(current),
|
|
2733
|
+
pageSize: "50"
|
|
2734
|
+
});
|
|
2735
|
+
const res = await fetch(`${APP_TEST_BASE}/test-group/list?${qs}`, { headers: {
|
|
2736
|
+
...headers,
|
|
2737
|
+
appId
|
|
2738
|
+
} });
|
|
2739
|
+
if (!res.ok) throw new Error(`AGC 查询测试群组失败 HTTP ${res.status}`);
|
|
2740
|
+
const json = await res.json();
|
|
2741
|
+
if (Number(json.rtnCode) !== 0) throw new Error(`AGC 查询测试群组失败: rtnCode=${json.rtnCode ?? "?"}${json.rtnDesc ? ` ${json.rtnDesc}` : ""}`);
|
|
2742
|
+
const hit = json.groups?.find((g) => g.groupName === groupName);
|
|
2743
|
+
if (hit?.groupId) return hit.groupId;
|
|
2744
|
+
const totalPage = json.pageInfo?.totalPage ?? current;
|
|
2745
|
+
if (current >= totalPage) break;
|
|
2746
|
+
}
|
|
2747
|
+
throw new Error(`AGC 未找到名为「${groupName}」的测试群组:到 AGC 控制台「测试 → 测试群组」创建后再试`);
|
|
2748
|
+
}
|
|
2576
2749
|
/** v1 更新文案段(releaseHarmonyApp step 4 / uploadToAgc 尾段):查默认语言 → 写 newFeatures,失败仅警告不阻断 */
|
|
2577
2750
|
async updateReleaseNotes(ctx, appId, headers, qs) {
|
|
2578
2751
|
if (!ctx.updateDescription) return;
|
|
@@ -3923,4 +4096,4 @@ function fromAapt(artifactPath) {
|
|
|
3923
4096
|
}
|
|
3924
4097
|
}
|
|
3925
4098
|
//#endregion
|
|
3926
|
-
export { APPLIFT_HOME, AgcHarmonyChannel, AscChannel, CREDENTIALS_PATH, CredentialsFileSchema, CredentialsProfileSchema, DefaultChannelRegistry, GLOBAL_CONFIG_PATH, GlobalConfigSchema, GooglePlayChannel, HISTORY_PATH, HonorChannel, HuaweiAndroidChannel, OppoChannel, PROJECTS_MAP_PATH, PgyerChannel, PluginHost, ProjectConfigSchema, StoreConfigSchema, StoresSchema, VivoChannel, WAIT_BEFORE_SUBMIT_MS, XiaomiChannel, YybChannel, appendEntry, assertListingFiles, defineConfig, detectBundleIds, detectFramework, electronAdapter, findArtifacts, findUp, flutterAdapter, formPost, getAgcToken, getHarmonyAppId, hmacSign, humanizeError, loadCredentials, loadCredentialsLayered, loadGlobalConfig, loadListingFile, loadProjectConfig, loadProjectProfileMap, md5File, md5String, nativeAndroidAdapter, nativeHarmonyAdapter, nativeIosAdapter, projectCredentialsPath, readArtifactVersion, readEntries, registry, resolveListing, resolvePlugins, resolveProfile, resolveProfileFor, rnAdapter, runStage, runSubmit, saveCredentials, saveProjectProfileMap, setProjectProfile, sha256File, sortedQueryString, tauriAdapter, tsMillis, tsSeconds };
|
|
4099
|
+
export { APPLIFT_HOME, AgcHarmonyChannel, AscChannel, BetaConfigSchema, CREDENTIALS_PATH, CredentialsFileSchema, CredentialsProfileSchema, DefaultChannelRegistry, GLOBAL_CONFIG_PATH, GlobalConfigSchema, GooglePlayChannel, HISTORY_PATH, HonorChannel, HuaweiAndroidChannel, OppoChannel, PROJECTS_MAP_PATH, PgyerChannel, PluginHost, ProjectConfigSchema, StoreConfigSchema, StoresSchema, VivoChannel, WAIT_BEFORE_SUBMIT_MS, XiaomiChannel, YybChannel, appendEntry, assertListingFiles, defineConfig, detectBundleIds, detectFramework, electronAdapter, findArtifacts, findUp, flutterAdapter, formPost, getAgcToken, getHarmonyAppId, hmacSign, humanizeError, loadCredentials, loadCredentialsLayered, loadGlobalConfig, loadListingFile, loadProjectConfig, loadProjectProfileMap, md5File, md5String, nativeAndroidAdapter, nativeHarmonyAdapter, nativeIosAdapter, projectCredentialsPath, readArtifactVersion, readEntries, registry, resolveListing, resolvePlugins, resolveProfile, resolveProfileFor, rnAdapter, runStage, runSubmit, saveCredentials, saveProjectProfileMap, setProjectProfile, sha256File, sortedQueryString, tauriAdapter, tsMillis, tsSeconds };
|
|
@@ -175,7 +175,31 @@ type StoreConfig = z.infer<typeof StoreConfigSchema>;
|
|
|
175
175
|
*/
|
|
176
176
|
declare const StoresSchema: z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodRecord<z.ZodString, z.ZodString>, z.ZodString]>>, z.ZodArray<z.ZodString>]>, z.ZodTransform<Record<string, Record<string, string>>, string[] | Record<string, string | Record<string, string>>>>>;
|
|
177
177
|
type Stores = z.infer<typeof StoresSchema>;
|
|
178
|
-
/** 项目级配置(applift.config.ts
|
|
178
|
+
/** 项目级配置(applift.config.ts 的形状);beta 段见上方 BetaConfigSchema */
|
|
179
|
+
/**
|
|
180
|
+
* 内测分发配置(applift beta 无平台参数时并行发布的渠道开关):
|
|
181
|
+
* - pgyer: 蒲公英多平台上传(缺省只发 android)
|
|
182
|
+
* - agc: AGC 邀请测试(Testing API,submit=true 上传绑定后自动提审)
|
|
183
|
+
* - testflight: App Store Connect 上传(ipa 进 TestFlight)
|
|
184
|
+
*/
|
|
185
|
+
declare const BetaConfigSchema: z.ZodObject<{
|
|
186
|
+
pgyer: z.ZodOptional<z.ZodObject<{
|
|
187
|
+
platforms: z.ZodDefault<z.ZodArray<z.ZodEnum<{
|
|
188
|
+
android: "android";
|
|
189
|
+
harmony: "harmony";
|
|
190
|
+
ios: "ios";
|
|
191
|
+
}>>>;
|
|
192
|
+
installPassword: z.ZodOptional<z.ZodString>;
|
|
193
|
+
}, z.core.$strip>>;
|
|
194
|
+
agc: z.ZodOptional<z.ZodObject<{
|
|
195
|
+
submit: z.ZodDefault<z.ZodBoolean>;
|
|
196
|
+
group: z.ZodOptional<z.ZodString>;
|
|
197
|
+
testType: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<3>, z.ZodLiteral<4>]>>;
|
|
198
|
+
}, z.core.$strip>>;
|
|
199
|
+
testflight: z.ZodOptional<z.ZodObject<{
|
|
200
|
+
note: z.ZodOptional<z.ZodString>;
|
|
201
|
+
}, z.core.$strip>>;
|
|
202
|
+
}, z.core.$strip>;
|
|
179
203
|
declare const ProjectConfigSchema: z.ZodObject<{
|
|
180
204
|
name: z.ZodOptional<z.ZodString>;
|
|
181
205
|
profile: z.ZodDefault<z.ZodString>;
|
|
@@ -206,7 +230,26 @@ declare const ProjectConfigSchema: z.ZodObject<{
|
|
|
206
230
|
macos: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
207
231
|
linux: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
208
232
|
}, z.core.$catchall<z.ZodOptional<z.ZodArray<z.ZodString>>>>>;
|
|
233
|
+
beta: z.ZodOptional<z.ZodObject<{
|
|
234
|
+
pgyer: z.ZodOptional<z.ZodObject<{
|
|
235
|
+
platforms: z.ZodDefault<z.ZodArray<z.ZodEnum<{
|
|
236
|
+
android: "android";
|
|
237
|
+
harmony: "harmony";
|
|
238
|
+
ios: "ios";
|
|
239
|
+
}>>>;
|
|
240
|
+
installPassword: z.ZodOptional<z.ZodString>;
|
|
241
|
+
}, z.core.$strip>>;
|
|
242
|
+
agc: z.ZodOptional<z.ZodObject<{
|
|
243
|
+
submit: z.ZodDefault<z.ZodBoolean>;
|
|
244
|
+
group: z.ZodOptional<z.ZodString>;
|
|
245
|
+
testType: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<3>, z.ZodLiteral<4>]>>;
|
|
246
|
+
}, z.core.$strip>>;
|
|
247
|
+
testflight: z.ZodOptional<z.ZodObject<{
|
|
248
|
+
note: z.ZodOptional<z.ZodString>;
|
|
249
|
+
}, z.core.$strip>>;
|
|
250
|
+
}, z.core.$strip>>;
|
|
209
251
|
}, z.core.$strip>;
|
|
252
|
+
type BetaConfig = z.infer<typeof BetaConfigSchema>;
|
|
210
253
|
type ProjectConfig = z.infer<typeof ProjectConfigSchema>;
|
|
211
254
|
/** 全局行为配置(~/.applift/config.toml) */
|
|
212
255
|
declare const GlobalConfigSchema: z.ZodObject<{
|
|
@@ -331,4 +374,4 @@ declare function defineConfig(config: QypubUserConfig): QypubUserConfig;
|
|
|
331
374
|
/** 解析用户配置中的插件(工厂惰性求值),供 PluginHost 构造 */
|
|
332
375
|
declare function resolvePlugins(userConfig: QypubUserConfig): QypubPlugin[];
|
|
333
376
|
//#endregion
|
|
334
|
-
export {
|
|
377
|
+
export { rnAdapter as $, StoreConfigSchema as A, StageResult as B, CredentialsProfile as C, ProjectConfig as D, GlobalConfigSchema as E, ChannelContext as F, detectBundleIds as G, BundleIds as H, ChannelEvent as I, findArtifacts as J, detectFramework as K, ChannelRegistry as L, StoresSchema as M, Channel as N, ProjectConfigSchema as O, ChannelCapabilities as P, nativeIosAdapter as Q, ReleasePlanEntry as R, CredentialsFileSchema as S, GlobalConfig as T, FrameworkAdapter as U, SubmitResult as V, Platform as W, nativeAndroidAdapter as X, flutterAdapter as Y, nativeHarmonyAdapter as Z, appendEntry as _, QypubUserConfig as a, BetaConfigSchema as b, PipelineInput as c, runStage as d, tauriAdapter as et, runSubmit as f, HistoryQuery as g, HistoryEvent as h, QypubPlugin as i, Stores as j, StoreConfig as k, PipelineSummary as l, HistoryEntry as m, PluginHookName as n, defineConfig as o, HISTORY_PATH as p, electronAdapter as q, PluginHost as r, resolvePlugins as s, HookContext as t, PipelineSummaryEntry as u, readEntries as v, CredentialsProfileSchema as w, CredentialsFile as x, BetaConfig as y, ReviewStatus as z };
|
package/dist/plugins/index.d.mts
CHANGED