expo-harmony-toolkit 1.7.0 → 1.7.1
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/README.en.md +32 -16
- package/README.md +37 -15
- package/build/core/build.js +1 -1
- package/build/core/constants.d.ts +2 -1
- package/build/core/constants.js +3 -2
- package/build/core/env.js +10 -12
- package/build/core/report.js +29 -1
- package/build/core/signing.d.ts +11 -0
- package/build/core/signing.js +113 -0
- package/build/core/template.js +2699 -193
- package/build/data/capabilities.js +28 -6
- package/build/types.d.ts +19 -1
- package/docs/cli-build.md +1 -1
- package/docs/npm-release.md +70 -23
- package/docs/official-app-shell-sample.md +33 -12
- package/docs/official-minimal-sample.md +43 -10
- package/docs/official-native-capabilities-sample.md +100 -24
- package/docs/official-ui-stack-sample.md +23 -18
- package/docs/roadmap.md +68 -40
- package/docs/support-matrix.md +78 -39
- package/docs/v1.7.0-acceptance.md +70 -101
- package/docs/v1.7.1-acceptance.md +111 -0
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
<p>
|
|
10
10
|
<a href="https://github.com/BlackishGreen33/Expo-Harmony-Toolkit/actions/workflows/ci.yml"><img alt="Checks" src="https://img.shields.io/badge/checks-passing-16a34a?style=flat-square&logo=githubactions&logoColor=white"></a>
|
|
11
11
|
<a href="./LICENSE"><img alt="License" src="https://img.shields.io/badge/license-MIT-0f766e?style=flat-square"></a>
|
|
12
|
-
<a href="https://github.com/BlackishGreen33/Expo-Harmony-Toolkit/releases"><img alt="Version" src="https://img.shields.io/badge/version-v1.7.
|
|
12
|
+
<a href="https://github.com/BlackishGreen33/Expo-Harmony-Toolkit/releases"><img alt="Version" src="https://img.shields.io/badge/version-v1.7.1-111827?style=flat-square"></a>
|
|
13
13
|
<a href="./docs/support-matrix.md"><img alt="Matrix" src="https://img.shields.io/badge/matrix-expo55--rnoh082--ui--stack-2563eb?style=flat-square"></a>
|
|
14
14
|
<img alt="Input" src="https://img.shields.io/badge/input-Managed%2FCNG-059669?style=flat-square">
|
|
15
15
|
</p>
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
</div>
|
|
25
25
|
|
|
26
26
|
> [!IMPORTANT]
|
|
27
|
-
> `v1.7` keeps the `verified + preview + experimental` model and moves `expo-location` and `expo-camera` into `preview`.
|
|
27
|
+
> `v1.7` keeps the `verified + preview + experimental` model and moves `expo-location` and `expo-camera` into `preview`. Starting with this documentation refresh, the public promise is tighter: `latest` only carries fully accepted `verified` capabilities, while `next` is reserved for preview fast-track work. The roadmap still targets `Managed/CNG Core Expo Coverage` first and long-tail extension coverage second.
|
|
28
28
|
|
|
29
29
|
> [!TIP]
|
|
30
30
|
> The two validated `@react-native-oh-tpl/*` adapters in the public matrix are currently consumed via exact Git URLs and commits. For repository development and the official UI-stack sample, prefer `pnpm install --ignore-scripts` so adapter prepare hooks do not fail on private upstream resources.
|
|
@@ -47,17 +47,19 @@
|
|
|
47
47
|
|
|
48
48
|
| Item | Status |
|
|
49
49
|
| --- | --- |
|
|
50
|
-
| Current version | `v1.7.
|
|
50
|
+
| Current version | `v1.7.1` |
|
|
51
51
|
| Support model | `verified + preview + experimental` |
|
|
52
52
|
| Public `verified` matrix | `expo55-rnoh082-ui-stack` |
|
|
53
53
|
| Supported input | Managed/CNG Expo projects |
|
|
54
54
|
| `verified` JS/UI capabilities | `expo-router`, `expo-linking`, `expo-constants`, `react-native-reanimated`, `react-native-svg` |
|
|
55
55
|
| `preview` native capabilities | `expo-file-system`, `expo-image-picker`, `expo-location`, `expo-camera` |
|
|
56
56
|
| `experimental` capabilities | `expo-notifications`, `react-native-gesture-handler` |
|
|
57
|
+
| Release tracks | `latest` = fully accepted `verified` only; `next` = preview fast track |
|
|
58
|
+
| Capability telemetry | `runtimeMode` + `evidence(bundle/debugBuild/device/release)` |
|
|
57
59
|
| Build path | `doctor -> init -> bundle -> build-hap` |
|
|
58
60
|
| Primary sample | `examples/official-ui-stack-sample` |
|
|
59
61
|
| Preview sample | `examples/official-native-capabilities-sample` |
|
|
60
|
-
|
|
|
62
|
+
| Supporting onboarding samples | `examples/official-app-shell-sample`, `examples/official-minimal-sample` |
|
|
61
63
|
|
|
62
64
|
<details>
|
|
63
65
|
<summary><strong>Still outside the verified public promise</strong></summary>
|
|
@@ -168,7 +170,7 @@ Common decision points:
|
|
|
168
170
|
|
|
169
171
|
## Support Matrix
|
|
170
172
|
|
|
171
|
-
`v1.7` keeps tiered support:
|
|
173
|
+
`v1.7` keeps tiered support and now exposes capability promotion distance in public reports:
|
|
172
174
|
|
|
173
175
|
- `verified`: the only public matrix remains `expo55-rnoh082-ui-stack`
|
|
174
176
|
- `preview`: `expo-file-system`, `expo-image-picker`, `expo-location`, `expo-camera`
|
|
@@ -176,18 +178,24 @@ Common decision points:
|
|
|
176
178
|
|
|
177
179
|
`doctor --strict` still means `verified` only. `doctor --target-tier preview` allows the same runtime matrix plus preview-tier capabilities, but that does not promote them into the formal public promise.
|
|
178
180
|
|
|
181
|
+
Starting in this refresh:
|
|
182
|
+
|
|
183
|
+
- `doctor-report.json` exposes `capabilities[].runtimeMode`
|
|
184
|
+
- `doctor-report.json` and `toolkit-config.json` expose `evidence.bundle`, `evidence.debugBuild`, `evidence.device`, and `evidence.release`
|
|
185
|
+
- `runtimeMode=shim` means the capability still has not reached a verified runtime path even if bundling and debug-build scaffolding already exist
|
|
186
|
+
|
|
179
187
|
See [docs/support-matrix.md](./docs/support-matrix.md) for the full allowlist, pairing rules, exact specifiers, issue codes, and release gates.
|
|
180
188
|
|
|
181
189
|
## Official Samples
|
|
182
190
|
|
|
183
191
|
- `examples/official-ui-stack-sample`
|
|
184
|
-
The
|
|
192
|
+
The current public main sample, covering router, linking, constants, SVG, reanimated, and the Harmony sidecar build flow.
|
|
185
193
|
- `examples/official-native-capabilities-sample`
|
|
186
|
-
The `v1.7` Batch A+B preview sample, covering `expo-file-system`, `expo-image-picker`, `expo-location`, and `expo-camera`
|
|
194
|
+
The `v1.7.x` Batch A+B preview walkthrough sample, covering the supported core subsets for `expo-file-system`, `expo-image-picker`, `expo-location`, and `expo-camera` plus permission, bundle, and debug-build validation.
|
|
187
195
|
- `examples/official-app-shell-sample`
|
|
188
|
-
The
|
|
196
|
+
The minimal App Shell onboarding sample that demonstrates router, linking, constants, pathname, observed URL, and a generated deep-link flow.
|
|
189
197
|
- `examples/official-minimal-sample`
|
|
190
|
-
The smallest
|
|
198
|
+
The smallest onboarding sample, explaining the shortest `doctor -> init -> bundle -> build-hap` chain and what it intentionally does not cover.
|
|
191
199
|
|
|
192
200
|
See:
|
|
193
201
|
|
|
@@ -230,14 +238,16 @@ Pre-publish checks:
|
|
|
230
238
|
- `pnpm build`
|
|
231
239
|
- `pnpm test`
|
|
232
240
|
- `npm pack --dry-run`
|
|
233
|
-
- tarball smoke:
|
|
241
|
+
- tarball smoke:
|
|
242
|
+
`latest` runs `doctor --strict`, `init --force`, `bundle`
|
|
243
|
+
`next` runs `doctor --target-tier preview`, `init --force`, `bundle`
|
|
234
244
|
|
|
235
|
-
Automatic publishing defaults to hosted CI only:
|
|
245
|
+
Automatic publishing still defaults to hosted CI only, but now splits into two tracks:
|
|
236
246
|
|
|
237
|
-
-
|
|
238
|
-
- `
|
|
239
|
-
- GitHub auto-publish
|
|
240
|
-
-
|
|
247
|
+
- `stable/latest`: only verified samples and fully accepted capabilities
|
|
248
|
+
- `fast-track/next`: preview sample smoke and preview capability validation
|
|
249
|
+
- GitHub auto-publish selects `latest` or `next` based on the tag and keeps provenance enabled
|
|
250
|
+
- `build-hap --mode debug` still does not block hosted npm publishing
|
|
241
251
|
|
|
242
252
|
Manual Harmony acceptance still requires:
|
|
243
253
|
|
|
@@ -248,6 +258,12 @@ Manual Harmony acceptance still requires:
|
|
|
248
258
|
- `Build Debug Hap(s)` succeeds
|
|
249
259
|
- `official-native-capabilities-sample` at least proves Batch A+B preview route bundling, generated Harmony permissions, and the debug build path
|
|
250
260
|
|
|
261
|
+
Verified promotion still additionally requires:
|
|
262
|
+
|
|
263
|
+
- device-side acceptance
|
|
264
|
+
- release signing plus `build-hap --mode release`
|
|
265
|
+
- roadmap, support matrix, README, and acceptance records updated in the same PR
|
|
266
|
+
|
|
251
267
|
See [docs/npm-release.md](./docs/npm-release.md) and [docs/signing-and-release.md](./docs/signing-and-release.md).
|
|
252
268
|
|
|
253
269
|
## Documentation
|
|
@@ -260,7 +276,7 @@ See [docs/npm-release.md](./docs/npm-release.md) and [docs/signing-and-release.m
|
|
|
260
276
|
- [Official Minimal Sample Guide](./docs/official-minimal-sample.md)
|
|
261
277
|
- [npm Release Notes](./docs/npm-release.md)
|
|
262
278
|
- [Signing and Release Notes](./docs/signing-and-release.md)
|
|
263
|
-
- [v1.7.
|
|
279
|
+
- [v1.7.1 Acceptance Log](./docs/v1.7.1-acceptance.md)
|
|
264
280
|
- [Roadmap](./docs/roadmap.md)
|
|
265
281
|
|
|
266
282
|
## License
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
<p>
|
|
10
10
|
<a href="https://github.com/BlackishGreen33/Expo-Harmony-Toolkit/actions/workflows/ci.yml"><img alt="Checks" src="https://img.shields.io/badge/checks-passing-16a34a?style=flat-square&logo=githubactions&logoColor=white"></a>
|
|
11
11
|
<a href="./LICENSE"><img alt="License" src="https://img.shields.io/badge/license-MIT-0f766e?style=flat-square"></a>
|
|
12
|
-
<a href="https://github.com/BlackishGreen33/Expo-Harmony-Toolkit/releases"><img alt="Version" src="https://img.shields.io/badge/version-v1.7.
|
|
12
|
+
<a href="https://github.com/BlackishGreen33/Expo-Harmony-Toolkit/releases"><img alt="Version" src="https://img.shields.io/badge/version-v1.7.1-111827?style=flat-square"></a>
|
|
13
13
|
<a href="./docs/support-matrix.md"><img alt="Matrix" src="https://img.shields.io/badge/matrix-expo55--rnoh082--ui--stack-2563eb?style=flat-square"></a>
|
|
14
14
|
<img alt="Input" src="https://img.shields.io/badge/input-Managed%2FCNG-059669?style=flat-square">
|
|
15
15
|
</p>
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
</div>
|
|
25
25
|
|
|
26
26
|
> [!IMPORTANT]
|
|
27
|
-
> `v1.7` 延续 `verified + preview + experimental` 三层支持模型,并把 `expo-location`、`expo-camera` 推进到 `preview
|
|
27
|
+
> `v1.7` 延续 `verified + preview + experimental` 三层支持模型,并把 `expo-location`、`expo-camera` 推进到 `preview`。从这版文档开始,对外承诺进一步收紧为:`latest` 只承诺完整验收的 `verified` 能力,`next` 用于 preview fast track;路线仍然是先做到 `Managed/CNG Core Expo Coverage`,再通过 extension model 逼近“任意 Expo 项目”。
|
|
28
28
|
|
|
29
29
|
> [!TIP]
|
|
30
30
|
> 由于当前公开矩阵内的两套 `@react-native-oh-tpl/*` adapter 依赖以 Git URL + exact commit 形式接入,仓库开发和官方 UI-stack sample 推荐使用 `pnpm install --ignore-scripts`,避免 Git adapter 在 prepare 阶段拉取私有资源而中断安装。
|
|
@@ -47,17 +47,19 @@
|
|
|
47
47
|
|
|
48
48
|
| 项目 | 说明 |
|
|
49
49
|
| --- | --- |
|
|
50
|
-
| 当前版本 | `v1.7.
|
|
50
|
+
| 当前版本 | `v1.7.1` |
|
|
51
51
|
| 支持模型 | `verified + preview + experimental` |
|
|
52
52
|
| 唯一 `verified` 公开矩阵 | `expo55-rnoh082-ui-stack` |
|
|
53
53
|
| 输入范围 | Managed/CNG Expo 项目 |
|
|
54
54
|
| `verified` JS/UI 能力 | `expo-router`、`expo-linking`、`expo-constants`、`react-native-reanimated`、`react-native-svg` |
|
|
55
55
|
| `preview` 原生能力 | `expo-file-system`、`expo-image-picker`、`expo-location`、`expo-camera` |
|
|
56
56
|
| `experimental` 能力 | `expo-notifications`、`react-native-gesture-handler` |
|
|
57
|
+
| 发布轨 | `latest` = fully accepted verified only;`next` = preview fast track |
|
|
58
|
+
| capability 遥测 | `runtimeMode` + `evidence(bundle/debugBuild/device/release)` |
|
|
57
59
|
| 构建链 | `doctor -> init -> bundle -> build-hap` |
|
|
58
60
|
| 主 sample | `examples/official-ui-stack-sample` |
|
|
59
61
|
| preview sample | `examples/official-native-capabilities-sample` |
|
|
60
|
-
|
|
|
62
|
+
| 辅助 onboarding samples | `examples/official-app-shell-sample`、`examples/official-minimal-sample` |
|
|
61
63
|
|
|
62
64
|
<details>
|
|
63
65
|
<summary><strong>当前仍不在 verified 正式承诺范围</strong></summary>
|
|
@@ -168,7 +170,7 @@ pnpm exec expo-harmony build-hap --mode release
|
|
|
168
170
|
|
|
169
171
|
## 支持矩阵
|
|
170
172
|
|
|
171
|
-
`v1.7`
|
|
173
|
+
`v1.7` 继续采用支持分层,并开始把 capability 晋升距离写进公开报告:
|
|
172
174
|
|
|
173
175
|
- `verified`:唯一公开矩阵仍是 `expo55-rnoh082-ui-stack`
|
|
174
176
|
- `preview`:`expo-file-system`、`expo-image-picker`、`expo-location`、`expo-camera`
|
|
@@ -176,6 +178,18 @@ pnpm exec expo-harmony build-hap --mode release
|
|
|
176
178
|
|
|
177
179
|
`doctor --strict` 继续只代表 `verified`。`doctor --target-tier preview` 会在同一 runtime matrix 下额外放行 preview 能力,但这不等于它们已经进入正式承诺。
|
|
178
180
|
|
|
181
|
+
从本版开始:
|
|
182
|
+
|
|
183
|
+
- `doctor-report.json` 的 `capabilities[]` 会带出 `runtimeMode`
|
|
184
|
+
- `doctor-report.json` 与 `toolkit-config.json` 会带出 `evidence.bundle`、`evidence.debugBuild`、`evidence.device`、`evidence.release`
|
|
185
|
+
- `runtimeMode=shim` 说明当前仍未进入 verified runtime path,即使 bundle / debug build 已经可走通
|
|
186
|
+
|
|
187
|
+
文档里的状态标记额外约定为:
|
|
188
|
+
|
|
189
|
+
- `🟡`:当前子集已经实现,主要只差真机 / release 证据
|
|
190
|
+
- `🟠`:包已经进入 `preview`,但这个具体子 API 还没到可信实现,不能简单理解成“只差真机”
|
|
191
|
+
- `⛔`:完全不在当前公开支持范围
|
|
192
|
+
|
|
179
193
|
完整白名单、配对规则、exact specifier、issue code 与 release gate 见 [docs/support-matrix.md](./docs/support-matrix.md)。
|
|
180
194
|
|
|
181
195
|
## 官方 Samples
|
|
@@ -183,11 +197,11 @@ pnpm exec expo-harmony build-hap --mode release
|
|
|
183
197
|
- `examples/official-ui-stack-sample`
|
|
184
198
|
当前唯一对外主 sample,同时覆盖 router、linking、constants、SVG、reanimated 和 Harmony sidecar 构建链。
|
|
185
199
|
- `examples/official-native-capabilities-sample`
|
|
186
|
-
`v1.7` 的 Batch A+B preview sample,用来承接 `expo-file-system`、`expo-image-picker`、`expo-location`、`expo-camera`
|
|
200
|
+
`v1.7.x` 的 Batch A+B preview walkthrough sample,用来承接 `expo-file-system`、`expo-image-picker`、`expo-location`、`expo-camera` 的核心支持子集、permission、bundle 与 debug build 验收。
|
|
187
201
|
- `examples/official-app-shell-sample`
|
|
188
|
-
|
|
202
|
+
最小可理解的 App Shell onboarding sample,用来展示 router、linking、constants、pathname、observed URL 与 generated deep link。
|
|
189
203
|
- `examples/official-minimal-sample`
|
|
190
|
-
最小
|
|
204
|
+
最小 onboarding sample,用来说明最短 `doctor -> init -> bundle -> build-hap` 链路,以及它故意不覆盖的范围。
|
|
191
205
|
|
|
192
206
|
详见:
|
|
193
207
|
|
|
@@ -230,14 +244,16 @@ pnpm exec expo-harmony build-hap --mode release
|
|
|
230
244
|
- `pnpm build`
|
|
231
245
|
- `pnpm test`
|
|
232
246
|
- `npm pack --dry-run`
|
|
233
|
-
- tarball 安装 smoke
|
|
247
|
+
- tarball 安装 smoke:
|
|
248
|
+
`latest` 走 `doctor --strict`、`init --force`、`bundle`
|
|
249
|
+
`next` 走 `doctor --target-tier preview`、`init --force`、`bundle`
|
|
234
250
|
|
|
235
|
-
自动发布默认走 hosted CI only
|
|
251
|
+
自动发布默认走 hosted CI only,并区分双轨:
|
|
236
252
|
|
|
237
|
-
-
|
|
238
|
-
- `
|
|
239
|
-
- GitHub
|
|
240
|
-
-
|
|
253
|
+
- `stable/latest`:只承接 verified sample 与完整验收能力
|
|
254
|
+
- `fast-track/next`:承接 preview sample 与 preview capability smoke
|
|
255
|
+
- GitHub 自动发布按 tag 选择 `latest` 或 `next` dist-tag,并保留 provenance
|
|
256
|
+
- `build-hap --mode debug` 继续不作为 hosted npm publish 的硬阻塞条件
|
|
241
257
|
|
|
242
258
|
手动 Harmony 验收继续要求:
|
|
243
259
|
|
|
@@ -248,6 +264,12 @@ pnpm exec expo-harmony build-hap --mode release
|
|
|
248
264
|
- `Build Debug Hap(s)` 成功
|
|
249
265
|
- `official-native-capabilities-sample` 至少完成 Batch A+B preview route 的 bundle、permission 与 debug build 检查
|
|
250
266
|
|
|
267
|
+
verified capability 晋升还必须补齐:
|
|
268
|
+
|
|
269
|
+
- device-side 验收
|
|
270
|
+
- release signing / `build-hap --mode release`
|
|
271
|
+
- roadmap、support matrix、README、acceptance 记录同 PR 更新
|
|
272
|
+
|
|
251
273
|
详见 [docs/npm-release.md](./docs/npm-release.md) 与 [docs/signing-and-release.md](./docs/signing-and-release.md)。
|
|
252
274
|
|
|
253
275
|
## 文档索引
|
|
@@ -260,7 +282,7 @@ pnpm exec expo-harmony build-hap --mode release
|
|
|
260
282
|
- [官方最小 sample 指南](./docs/official-minimal-sample.md)
|
|
261
283
|
- [npm 发布说明](./docs/npm-release.md)
|
|
262
284
|
- [签名与 Release 说明](./docs/signing-and-release.md)
|
|
263
|
-
- [v1.7.
|
|
285
|
+
- [v1.7.1 验收记录](./docs/v1.7.1-acceptance.md)
|
|
264
286
|
- [路线图](./docs/roadmap.md)
|
|
265
287
|
|
|
266
288
|
## License
|
package/build/core/build.js
CHANGED
|
@@ -200,7 +200,7 @@ async function buildHapProject(projectRoot, options) {
|
|
|
200
200
|
if (options.mode === 'release' && !envReport.signingConfigured) {
|
|
201
201
|
blockingIssues.push({
|
|
202
202
|
code: 'env.signing.missing',
|
|
203
|
-
message: 'Release HAP builds require signingConfigs
|
|
203
|
+
message: 'Release HAP builds require signingConfigs from .expo-harmony/signing.local.json or harmony/build-profile.json5.',
|
|
204
204
|
});
|
|
205
205
|
}
|
|
206
206
|
if (blockingIssues.length > 0) {
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
export declare const TOOLKIT_PACKAGE_NAME = "expo-harmony-toolkit";
|
|
2
2
|
export declare const CLI_NAME = "expo-harmony";
|
|
3
|
-
export declare const TOOLKIT_VERSION = "1.7.
|
|
3
|
+
export declare const TOOLKIT_VERSION = "1.7.1";
|
|
4
4
|
export declare const TEMPLATE_VERSION = "rnoh-0.82.18";
|
|
5
5
|
export declare const RNOH_VERSION = "0.82.18";
|
|
6
6
|
export declare const RNOH_CLI_VERSION = "0.82.18";
|
|
7
7
|
export declare const SUPPORTED_EXPO_SDKS: number[];
|
|
8
8
|
export declare const GENERATED_DIR = ".expo-harmony";
|
|
9
9
|
export declare const GENERATED_SHIMS_DIR = ".expo-harmony/shims";
|
|
10
|
+
export declare const SIGNING_LOCAL_FILENAME = "signing.local.json";
|
|
10
11
|
export declare const MANIFEST_FILENAME = "manifest.json";
|
|
11
12
|
export declare const DOCTOR_REPORT_FILENAME = "doctor-report.json";
|
|
12
13
|
export declare const ENV_REPORT_FILENAME = "env-report.json";
|
package/build/core/constants.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DESIRED_PACKAGE_SCRIPTS = exports.HARMONY_RUNTIME_PRELUDE_RELATIVE_PATH = exports.HARMONY_ROUTER_ENTRY_FILENAME = exports.STRICT_ENV_EXIT_CODE = exports.STRICT_DOCTOR_EXIT_CODE = exports.DEFAULT_HVIGOR_PLUGIN_FILENAME = exports.PREBUILD_METADATA_FILENAME = exports.TOOLKIT_CONFIG_FILENAME = exports.BUILD_REPORT_FILENAME = exports.ENV_REPORT_FILENAME = exports.DOCTOR_REPORT_FILENAME = exports.MANIFEST_FILENAME = exports.GENERATED_SHIMS_DIR = exports.GENERATED_DIR = exports.SUPPORTED_EXPO_SDKS = exports.RNOH_CLI_VERSION = exports.RNOH_VERSION = exports.TEMPLATE_VERSION = exports.TOOLKIT_VERSION = exports.CLI_NAME = exports.TOOLKIT_PACKAGE_NAME = void 0;
|
|
3
|
+
exports.DESIRED_PACKAGE_SCRIPTS = exports.HARMONY_RUNTIME_PRELUDE_RELATIVE_PATH = exports.HARMONY_ROUTER_ENTRY_FILENAME = exports.STRICT_ENV_EXIT_CODE = exports.STRICT_DOCTOR_EXIT_CODE = exports.DEFAULT_HVIGOR_PLUGIN_FILENAME = exports.PREBUILD_METADATA_FILENAME = exports.TOOLKIT_CONFIG_FILENAME = exports.BUILD_REPORT_FILENAME = exports.ENV_REPORT_FILENAME = exports.DOCTOR_REPORT_FILENAME = exports.MANIFEST_FILENAME = exports.SIGNING_LOCAL_FILENAME = exports.GENERATED_SHIMS_DIR = exports.GENERATED_DIR = exports.SUPPORTED_EXPO_SDKS = exports.RNOH_CLI_VERSION = exports.RNOH_VERSION = exports.TEMPLATE_VERSION = exports.TOOLKIT_VERSION = exports.CLI_NAME = exports.TOOLKIT_PACKAGE_NAME = void 0;
|
|
4
4
|
exports.TOOLKIT_PACKAGE_NAME = 'expo-harmony-toolkit';
|
|
5
5
|
exports.CLI_NAME = 'expo-harmony';
|
|
6
|
-
exports.TOOLKIT_VERSION = '1.7.
|
|
6
|
+
exports.TOOLKIT_VERSION = '1.7.1';
|
|
7
7
|
exports.TEMPLATE_VERSION = 'rnoh-0.82.18';
|
|
8
8
|
exports.RNOH_VERSION = '0.82.18';
|
|
9
9
|
exports.RNOH_CLI_VERSION = '0.82.18';
|
|
10
10
|
exports.SUPPORTED_EXPO_SDKS = [53, 55];
|
|
11
11
|
exports.GENERATED_DIR = '.expo-harmony';
|
|
12
12
|
exports.GENERATED_SHIMS_DIR = `${exports.GENERATED_DIR}/shims`;
|
|
13
|
+
exports.SIGNING_LOCAL_FILENAME = 'signing.local.json';
|
|
13
14
|
exports.MANIFEST_FILENAME = 'manifest.json';
|
|
14
15
|
exports.DOCTOR_REPORT_FILENAME = 'doctor-report.json';
|
|
15
16
|
exports.ENV_REPORT_FILENAME = 'env-report.json';
|
package/build/core/env.js
CHANGED
|
@@ -10,6 +10,7 @@ const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
|
10
10
|
const path_1 = __importDefault(require("path"));
|
|
11
11
|
const constants_1 = require("./constants");
|
|
12
12
|
const project_1 = require("./project");
|
|
13
|
+
const signing_1 = require("./signing");
|
|
13
14
|
const DEFAULT_DEVECO_STUDIO_CANDIDATES = [
|
|
14
15
|
'/Applications/DevEco-Studio.app',
|
|
15
16
|
path_1.default.join(process.env.HOME ?? '', 'Applications', 'DevEco-Studio.app'),
|
|
@@ -56,9 +57,11 @@ async function buildEnvReport(projectRoot, options = {}) {
|
|
|
56
57
|
const harmonyProjectRoot = (await fs_extra_1.default.pathExists(harmonyProjectRootCandidate))
|
|
57
58
|
? harmonyProjectRootCandidate
|
|
58
59
|
: null;
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
const signingLocalConfig = await (0, signing_1.readSigningLocalConfig)(resolvedProjectRoot);
|
|
61
|
+
const buildProfileContents = harmonyProjectRoot
|
|
62
|
+
? await readBuildProfileContents(path_1.default.join(harmonyProjectRoot, 'build-profile.json5'))
|
|
63
|
+
: null;
|
|
64
|
+
const signingConfigured = (0, signing_1.hasSigningConfiguration)(buildProfileContents, signingLocalConfig);
|
|
62
65
|
const blockingIssues = [];
|
|
63
66
|
const advisories = [];
|
|
64
67
|
const warnings = [];
|
|
@@ -92,7 +95,7 @@ async function buildEnvReport(projectRoot, options = {}) {
|
|
|
92
95
|
else if (!signingConfigured) {
|
|
93
96
|
advisories.push({
|
|
94
97
|
code: 'env.signing.missing',
|
|
95
|
-
message: '
|
|
98
|
+
message: 'Neither .expo-harmony/signing.local.json nor harmony/build-profile.json5 declares usable signingConfigs yet. Debug GUI flows may still work, but release builds require signing.',
|
|
96
99
|
});
|
|
97
100
|
}
|
|
98
101
|
return {
|
|
@@ -169,16 +172,11 @@ function findExecutableInPath(executableName, runtimeEnv) {
|
|
|
169
172
|
}
|
|
170
173
|
return null;
|
|
171
174
|
}
|
|
172
|
-
async function
|
|
175
|
+
async function readBuildProfileContents(buildProfilePath) {
|
|
173
176
|
if (!(await fs_extra_1.default.pathExists(buildProfilePath))) {
|
|
174
|
-
return
|
|
175
|
-
}
|
|
176
|
-
const contents = await fs_extra_1.default.readFile(buildProfilePath, 'utf8');
|
|
177
|
-
const signingConfigsMatch = contents.match(/signingConfigs\s*:\s*\[([\s\S]*?)\]/m);
|
|
178
|
-
if (!signingConfigsMatch) {
|
|
179
|
-
return false;
|
|
177
|
+
return null;
|
|
180
178
|
}
|
|
181
|
-
return
|
|
179
|
+
return fs_extra_1.default.readFile(buildProfilePath, 'utf8');
|
|
182
180
|
}
|
|
183
181
|
function renderIssueLine(issue) {
|
|
184
182
|
return `- ${issue.code}: ${issue.message}${issue.subject ? ` (${issue.subject})` : ''}`;
|
package/build/core/report.js
CHANGED
|
@@ -46,6 +46,8 @@ async function buildDoctorReport(projectRoot, options = {}) {
|
|
|
46
46
|
packageName: definition.packageName,
|
|
47
47
|
status: definition.status,
|
|
48
48
|
supportTier: definition.supportTier,
|
|
49
|
+
runtimeMode: definition.runtimeMode,
|
|
50
|
+
evidence: { ...definition.evidence },
|
|
49
51
|
note: definition.note,
|
|
50
52
|
docsUrl: definition.docsUrl,
|
|
51
53
|
nativePackageNames: [...definition.nativePackageNames],
|
|
@@ -135,7 +137,13 @@ function renderDoctorReport(report) {
|
|
|
135
137
|
const permissions = capability.harmonyPermissions.length > 0
|
|
136
138
|
? ` | permissions: ${capability.harmonyPermissions.join(', ')}`
|
|
137
139
|
: '';
|
|
138
|
-
|
|
140
|
+
const missingEvidence = getMissingCapabilityEvidence(capability.evidence);
|
|
141
|
+
const evidence = ` | evidence: ${renderCapabilityEvidence(capability.evidence)}`;
|
|
142
|
+
const promotionGaps = buildCapabilityPromotionGaps(capability.runtimeMode, missingEvidence);
|
|
143
|
+
const gapSuffix = promotionGaps.length > 0
|
|
144
|
+
? ` | verified gaps: ${promotionGaps.join(', ')}`
|
|
145
|
+
: '';
|
|
146
|
+
return `- [${capability.status}/${capability.supportTier}] ${capability.packageName} -> ${capability.nativePackageNames.join(', ') || 'toolkit-managed bridge'} | runtime: ${capability.runtimeMode} | sample: ${capability.sampleRoute}${permissions}${evidence}${gapSuffix}`;
|
|
139
147
|
}));
|
|
140
148
|
}
|
|
141
149
|
if (report.blockingIssues.length > 0) {
|
|
@@ -149,6 +157,26 @@ function renderDoctorReport(report) {
|
|
|
149
157
|
}
|
|
150
158
|
return sections.join('\n');
|
|
151
159
|
}
|
|
160
|
+
function renderCapabilityEvidence(evidence) {
|
|
161
|
+
return [
|
|
162
|
+
`bundle=${evidence.bundle ? 'yes' : 'no'}`,
|
|
163
|
+
`debugBuild=${evidence.debugBuild ? 'yes' : 'no'}`,
|
|
164
|
+
`device=${evidence.device ? 'yes' : 'no'}`,
|
|
165
|
+
`release=${evidence.release ? 'yes' : 'no'}`,
|
|
166
|
+
].join(', ');
|
|
167
|
+
}
|
|
168
|
+
function getMissingCapabilityEvidence(evidence) {
|
|
169
|
+
return Object.entries(evidence)
|
|
170
|
+
.filter(([, present]) => !present)
|
|
171
|
+
.map(([key]) => key);
|
|
172
|
+
}
|
|
173
|
+
function buildCapabilityPromotionGaps(runtimeMode, missingEvidence) {
|
|
174
|
+
const gaps = missingEvidence.map((entry) => String(entry));
|
|
175
|
+
if (runtimeMode !== 'verified') {
|
|
176
|
+
gaps.unshift(`runtimeMode:${runtimeMode}->verified`);
|
|
177
|
+
}
|
|
178
|
+
return gaps;
|
|
179
|
+
}
|
|
152
180
|
function createDependencyRecord(name, version, source) {
|
|
153
181
|
const matrixRecord = dependencyCatalog_1.DEPENDENCY_CATALOG[name] ?? DEFAULT_RECORD;
|
|
154
182
|
return {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type JsonRecord = Record<string, unknown>;
|
|
2
|
+
type SigningLocalAppFragment = {
|
|
3
|
+
signingConfigs?: JsonRecord[];
|
|
4
|
+
products?: JsonRecord[];
|
|
5
|
+
};
|
|
6
|
+
export declare function getSigningLocalPath(projectRoot: string): string;
|
|
7
|
+
export declare function readSigningLocalConfig(projectRoot: string): Promise<SigningLocalAppFragment | null>;
|
|
8
|
+
export declare function mergeSigningLocalConfigIntoBuildProfile(rawBuildProfileContents: string, signingLocalConfig: SigningLocalAppFragment | null): string;
|
|
9
|
+
export declare function hasSigningConfiguration(rawBuildProfileContents: string | null, signingLocalConfig?: SigningLocalAppFragment | null): boolean;
|
|
10
|
+
export declare function hasSigningLocalConfiguration(signingLocalConfig: SigningLocalAppFragment | null): boolean;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getSigningLocalPath = getSigningLocalPath;
|
|
7
|
+
exports.readSigningLocalConfig = readSigningLocalConfig;
|
|
8
|
+
exports.mergeSigningLocalConfigIntoBuildProfile = mergeSigningLocalConfigIntoBuildProfile;
|
|
9
|
+
exports.hasSigningConfiguration = hasSigningConfiguration;
|
|
10
|
+
exports.hasSigningLocalConfiguration = hasSigningLocalConfiguration;
|
|
11
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
12
|
+
const json5_1 = __importDefault(require("json5"));
|
|
13
|
+
const path_1 = __importDefault(require("path"));
|
|
14
|
+
const constants_1 = require("./constants");
|
|
15
|
+
function getSigningLocalPath(projectRoot) {
|
|
16
|
+
return path_1.default.join(projectRoot, constants_1.GENERATED_DIR, constants_1.SIGNING_LOCAL_FILENAME);
|
|
17
|
+
}
|
|
18
|
+
async function readSigningLocalConfig(projectRoot) {
|
|
19
|
+
const signingLocalPath = getSigningLocalPath(projectRoot);
|
|
20
|
+
if (!(await fs_extra_1.default.pathExists(signingLocalPath))) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
const rawConfig = (await fs_extra_1.default.readJson(signingLocalPath));
|
|
24
|
+
return normalizeSigningLocalConfig(rawConfig);
|
|
25
|
+
}
|
|
26
|
+
function mergeSigningLocalConfigIntoBuildProfile(rawBuildProfileContents, signingLocalConfig) {
|
|
27
|
+
if (!signingLocalConfig) {
|
|
28
|
+
return rawBuildProfileContents;
|
|
29
|
+
}
|
|
30
|
+
const parsed = json5_1.default.parse(rawBuildProfileContents);
|
|
31
|
+
const merged = mergeSigningLocalConfig(parsed, signingLocalConfig);
|
|
32
|
+
return JSON.stringify(merged, null, 2) + '\n';
|
|
33
|
+
}
|
|
34
|
+
function hasSigningConfiguration(rawBuildProfileContents, signingLocalConfig = null) {
|
|
35
|
+
if (hasSigningLocalConfiguration(signingLocalConfig)) {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
if (!rawBuildProfileContents) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const parsed = json5_1.default.parse(rawBuildProfileContents);
|
|
43
|
+
return hasNonEmptySigningConfigList(parsed.app?.signingConfigs);
|
|
44
|
+
}
|
|
45
|
+
catch (_error) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function hasSigningLocalConfiguration(signingLocalConfig) {
|
|
50
|
+
return hasNonEmptySigningConfigList(signingLocalConfig?.signingConfigs);
|
|
51
|
+
}
|
|
52
|
+
function normalizeSigningLocalConfig(rawConfig) {
|
|
53
|
+
const candidate = rawConfig && typeof rawConfig === 'object' && !Array.isArray(rawConfig)
|
|
54
|
+
? 'app' in rawConfig &&
|
|
55
|
+
rawConfig.app &&
|
|
56
|
+
typeof rawConfig.app === 'object' &&
|
|
57
|
+
!Array.isArray(rawConfig.app)
|
|
58
|
+
? rawConfig.app
|
|
59
|
+
: rawConfig
|
|
60
|
+
: {};
|
|
61
|
+
const signingConfigs = Array.isArray(candidate.signingConfigs)
|
|
62
|
+
? candidate.signingConfigs.filter(isJsonRecord)
|
|
63
|
+
: undefined;
|
|
64
|
+
const products = Array.isArray(candidate.products)
|
|
65
|
+
? candidate.products.filter(isJsonRecord)
|
|
66
|
+
: undefined;
|
|
67
|
+
return {
|
|
68
|
+
...(signingConfigs ? { signingConfigs } : {}),
|
|
69
|
+
...(products ? { products } : {}),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function mergeSigningLocalConfig(buildProfile, signingLocalConfig) {
|
|
73
|
+
const nextBuildProfile = {
|
|
74
|
+
...buildProfile,
|
|
75
|
+
app: isJsonRecord(buildProfile.app)
|
|
76
|
+
? {
|
|
77
|
+
...buildProfile.app,
|
|
78
|
+
}
|
|
79
|
+
: {},
|
|
80
|
+
};
|
|
81
|
+
if (Array.isArray(signingLocalConfig.signingConfigs)) {
|
|
82
|
+
nextBuildProfile.app.signingConfigs = signingLocalConfig.signingConfigs.map((entry) => ({ ...entry }));
|
|
83
|
+
}
|
|
84
|
+
if (Array.isArray(signingLocalConfig.products)) {
|
|
85
|
+
const currentProducts = Array.isArray(nextBuildProfile.app.products)
|
|
86
|
+
? nextBuildProfile.app.products.map((entry) => ({ ...entry }))
|
|
87
|
+
: [];
|
|
88
|
+
for (const incomingProduct of signingLocalConfig.products) {
|
|
89
|
+
const incomingName = typeof incomingProduct.name === 'string' && incomingProduct.name.length > 0
|
|
90
|
+
? incomingProduct.name
|
|
91
|
+
: null;
|
|
92
|
+
const existingIndex = incomingName === null
|
|
93
|
+
? -1
|
|
94
|
+
: currentProducts.findIndex((entry) => entry.name === incomingName);
|
|
95
|
+
if (existingIndex >= 0) {
|
|
96
|
+
currentProducts[existingIndex] = {
|
|
97
|
+
...currentProducts[existingIndex],
|
|
98
|
+
...incomingProduct,
|
|
99
|
+
};
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
currentProducts.push({ ...incomingProduct });
|
|
103
|
+
}
|
|
104
|
+
nextBuildProfile.app.products = currentProducts;
|
|
105
|
+
}
|
|
106
|
+
return nextBuildProfile;
|
|
107
|
+
}
|
|
108
|
+
function hasNonEmptySigningConfigList(signingConfigs) {
|
|
109
|
+
return Array.isArray(signingConfigs) && signingConfigs.some(isJsonRecord);
|
|
110
|
+
}
|
|
111
|
+
function isJsonRecord(value) {
|
|
112
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
113
|
+
}
|