deeplink-parity 0.6.3 → 0.6.4

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.md CHANGED
@@ -13,7 +13,8 @@ npx deeplink-parity .
13
13
  ```
14
14
 
15
15
  ```
16
- deeplink-parity · 3 domain(s) checked
16
+ deeplink-parity v0.6.4 · 3 domain(s) checked
17
+ routes: deeplink-parity.yml (iOS 74 · Android 73)
17
18
 
18
19
  ERROR links.example.com
19
20
  AASA responded with 404
@@ -24,7 +25,11 @@ WARN promo.example.com
24
25
  Declared on iOS but not on Android
25
26
  The same link opens the app on iOS and the browser on Android
26
27
 
27
- 1 error, 1 warn, 0 info
28
+ WARN route-gap
29
+ /events is in the Android route table but not iOS's
30
+ A /events link navigates on Android and goes nowhere on iOS.
31
+
32
+ 1 error, 2 warn, 0 info
28
33
  ```
29
34
 
30
35
  <br>
@@ -57,6 +62,9 @@ Findings show up as annotations on the run. Add `sha256` to include the Android
57
62
  key in the check, and `fail-on: never` to report without failing while an existing backlog
58
63
  is cleared.
59
64
 
65
+ Domains are checked with zero setup. To also compare the **screens behind the links**,
66
+ run `npx deeplink-parity init` once — see [Route parity](#route-parity).
67
+
60
68
  <br>
61
69
 
62
70
  ## Contents
@@ -111,6 +119,7 @@ No configuration file. Domains are discovered from your app, then the matching w
111
119
  **Warnings** — one platform works and the other does not
112
120
 
113
121
  - **A domain is declared on iOS but not Android, or the reverse**
122
+ - **A route is in one platform's route table but not the other's** (with [route parity](#route-parity) set up)
114
123
  - An `https` intent-filter has no `autoVerify`
115
124
  - A manifest host reference could not be resolved
116
125
 
@@ -135,6 +144,7 @@ npx deeplink-parity init [path...] # interactive setup for route com
135
144
  --output <file> Also write the JSON result to a file
136
145
  --format github GitHub Actions annotations (auto-detected on Actions)
137
146
  --yes init only: accept the top suggestion without prompting
147
+ -v, --version Print the version
138
148
  -h, --help Show this message
139
149
  ```
140
150
 
@@ -274,6 +284,8 @@ The **check never writes to the repositories it scans** — it reads files and G
274
284
  public well-known files per domain, nothing else. `init` writes exactly one file,
275
285
  `deeplink-parity.yml`, in your working directory, after printing its content and asking.
276
286
 
287
+ <br>
288
+
277
289
  ## Native, Flutter and React Native
278
290
 
279
291
  Whatever the app is written in, deep links are declared in the same two native files and
@@ -316,7 +328,9 @@ read as browser registration rather than deep links.
316
328
 
317
329
  - **Deferred deep links are out of scope.** Install-then-open attribution is decided at runtime by your attribution SDK's servers. No static check can confirm it, and reporting a pass would be worse than saying nothing.
318
330
  - **It does not prove path equivalence.** iOS and Android use different path-matching engines. Differing path sets are reported as `info` with both sides shown, for a human to judge — not asserted as a bug.
319
- - **It does not run your app.** Route handling inside the app is not inspected.
331
+ - **It does not run your app.** Route parity compares the declared tables; whether a
332
+ handler behind a route actually works, or a dynamically-matched route resolves, only
333
+ shows up on a device.
320
334
 
321
335
  <br>
322
336
 
@@ -330,7 +344,7 @@ npm run typecheck
330
344
 
331
345
  `fixtures/` holds synthetic iOS and Android projects covering literal hosts, chained
332
346
  `@string` references resolved through gradle `resValue` and `.properties`, flavor-specific
333
- values, and unresolvable references.
347
+ values, unresolvable references, and route tables in both platforms' shapes.
334
348
 
335
349
  <br>
336
350
 
@@ -33,9 +33,11 @@ export async function extractRoutes(platform, config, roots) {
33
33
  const findings = [];
34
34
  const files = [];
35
35
  const paths = new Set();
36
+ let unresolved = false;
36
37
  for (const file of config.files) {
37
38
  const hits = await resolveInRoots(file, roots);
38
39
  if (hits.length === 0) {
40
+ unresolved = true;
39
41
  findings.push({
40
42
  severity: 'error',
41
43
  rule: 'routes-file-missing',
@@ -45,6 +47,7 @@ export async function extractRoutes(platform, config, roots) {
45
47
  continue;
46
48
  }
47
49
  if (hits.length > 1) {
50
+ unresolved = true;
48
51
  findings.push({
49
52
  severity: 'error',
50
53
  rule: 'routes-file-ambiguous',
@@ -59,6 +62,9 @@ export async function extractRoutes(platform, config, roots) {
59
62
  paths.add(m[1] ?? m[0]);
60
63
  }
61
64
  }
65
+ // a table missing any of its files is incomplete; diffing it would manufacture gaps
66
+ if (unresolved)
67
+ return { findings };
62
68
  if (files.length > 0 && paths.size === 0) {
63
69
  // matching nothing is a broken config, never a clean pass
64
70
  findings.push({
@@ -35,7 +35,17 @@ async function pickFiles(rl, platform, candidates, yes) {
35
35
  return [];
36
36
  if (answer === 'm') {
37
37
  const manual = (await rl.question('path: ')).trim();
38
- return manual ? [manual] : [];
38
+ if (!manual)
39
+ return [];
40
+ // a mistyped path written into the config would only surface at check time
41
+ try {
42
+ await access(manual);
43
+ return [manual];
44
+ }
45
+ catch {
46
+ console.log(` Not found: ${manual}`);
47
+ continue;
48
+ }
39
49
  }
40
50
  const tokens = answer.split(/[,\s]+/);
41
51
  const indexes = tokens.map((t) => Number.parseInt(t, 10));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deeplink-parity",
3
- "version": "0.6.3",
3
+ "version": "0.6.4",
4
4
  "description": "Checks that what your mobile app declares about deep links matches what is actually hosted — across iOS and Android.",
5
5
  "type": "module",
6
6
  "bin": {