adjacent-cli 0.1.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.
Files changed (108) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/LICENSE +21 -0
  3. package/README.md +48 -0
  4. package/dist/arguments.d.ts +54 -0
  5. package/dist/arguments.d.ts.map +1 -0
  6. package/dist/arguments.js +68 -0
  7. package/dist/arguments.js.map +1 -0
  8. package/dist/bin.d.ts +3 -0
  9. package/dist/bin.d.ts.map +1 -0
  10. package/dist/bin.js +140 -0
  11. package/dist/bin.js.map +1 -0
  12. package/dist/checks.d.ts +35 -0
  13. package/dist/checks.d.ts.map +1 -0
  14. package/dist/checks.js +206 -0
  15. package/dist/checks.js.map +1 -0
  16. package/dist/create.d.ts +42 -0
  17. package/dist/create.d.ts.map +1 -0
  18. package/dist/create.js +82 -0
  19. package/dist/create.js.map +1 -0
  20. package/dist/dependencies.d.ts +59 -0
  21. package/dist/dependencies.d.ts.map +1 -0
  22. package/dist/dependencies.js +100 -0
  23. package/dist/dependencies.js.map +1 -0
  24. package/dist/destination.d.ts +16 -0
  25. package/dist/destination.d.ts.map +1 -0
  26. package/dist/destination.js +39 -0
  27. package/dist/destination.js.map +1 -0
  28. package/dist/dev-channel.d.ts +40 -0
  29. package/dist/dev-channel.d.ts.map +1 -0
  30. package/dist/dev-channel.js +192 -0
  31. package/dist/dev-channel.js.map +1 -0
  32. package/dist/dev.d.ts +3 -0
  33. package/dist/dev.d.ts.map +1 -0
  34. package/dist/dev.js +12 -0
  35. package/dist/dev.js.map +1 -0
  36. package/dist/doctor.d.ts +46 -0
  37. package/dist/doctor.d.ts.map +1 -0
  38. package/dist/doctor.js +52 -0
  39. package/dist/doctor.js.map +1 -0
  40. package/dist/edits.d.ts +26 -0
  41. package/dist/edits.d.ts.map +1 -0
  42. package/dist/edits.js +101 -0
  43. package/dist/edits.js.map +1 -0
  44. package/dist/index.d.ts +13 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.js +18 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/init.d.ts +62 -0
  49. package/dist/init.d.ts.map +1 -0
  50. package/dist/init.js +275 -0
  51. package/dist/init.js.map +1 -0
  52. package/dist/keys.d.ts +14 -0
  53. package/dist/keys.d.ts.map +1 -0
  54. package/dist/keys.js +66 -0
  55. package/dist/keys.js.map +1 -0
  56. package/dist/package-manager.d.ts +40 -0
  57. package/dist/package-manager.d.ts.map +1 -0
  58. package/dist/package-manager.js +98 -0
  59. package/dist/package-manager.js.map +1 -0
  60. package/dist/process.d.ts +33 -0
  61. package/dist/process.d.ts.map +1 -0
  62. package/dist/process.js +95 -0
  63. package/dist/process.js.map +1 -0
  64. package/dist/project-name.d.ts +30 -0
  65. package/dist/project-name.d.ts.map +1 -0
  66. package/dist/project-name.js +73 -0
  67. package/dist/project-name.js.map +1 -0
  68. package/dist/reporter.d.ts +12 -0
  69. package/dist/reporter.d.ts.map +1 -0
  70. package/dist/reporter.js +11 -0
  71. package/dist/reporter.js.map +1 -0
  72. package/dist/rewrite.d.ts +54 -0
  73. package/dist/rewrite.d.ts.map +1 -0
  74. package/dist/rewrite.js +262 -0
  75. package/dist/rewrite.js.map +1 -0
  76. package/dist/shutdown.d.ts +24 -0
  77. package/dist/shutdown.d.ts.map +1 -0
  78. package/dist/shutdown.js +67 -0
  79. package/dist/shutdown.js.map +1 -0
  80. package/dist/survey.d.ts +33 -0
  81. package/dist/survey.d.ts.map +1 -0
  82. package/dist/survey.js +94 -0
  83. package/dist/survey.js.map +1 -0
  84. package/dist/template.d.ts +29 -0
  85. package/dist/template.d.ts.map +1 -0
  86. package/dist/template.js +77 -0
  87. package/dist/template.js.map +1 -0
  88. package/dist/ui.d.ts +14 -0
  89. package/dist/ui.d.ts.map +1 -0
  90. package/dist/ui.js +50 -0
  91. package/dist/ui.js.map +1 -0
  92. package/package.json +65 -0
  93. package/templates/adjacent/app/manifest.ts +5 -0
  94. package/templates/adjacent/app/sw.js/route.ts +5 -0
  95. package/templates/adjacent/app.config.ts +21 -0
  96. package/templates/adjacent/components/navigation.tsx +46 -0
  97. package/templates/adjacent/public/apple-touch-icon.png +0 -0
  98. package/templates/adjacent/public/favicon-96x96.png +0 -0
  99. package/templates/adjacent/public/favicon.ico +0 -0
  100. package/templates/adjacent/public/favicon.svg +4 -0
  101. package/templates/adjacent/public/web-app-manifest-192x192.png +0 -0
  102. package/templates/adjacent/public/web-app-manifest-512x512.png +0 -0
  103. package/templates/adjacent/public/web-app-manifest-maskable-192x192.png +0 -0
  104. package/templates/adjacent/public/web-app-manifest-maskable-512x512.png +0 -0
  105. package/templates/starter/app/(app)/layout.tsx +12 -0
  106. package/templates/starter/app/(app)/page.tsx +75 -0
  107. package/templates/starter/app/(app)/settings/page.tsx +24 -0
  108. package/templates/starter/app/(app)/settings/settings-panel.tsx +54 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,15 @@
1
+ # Changelog
2
+
3
+ ## Unpublished
4
+
5
+ ### 🛠 Breaking changes
6
+
7
+ ### 🎉 New features
8
+
9
+ ### 🐛 Bug fixes
10
+
11
+ ### 💡 Others
12
+
13
+ ## 0.1.0 - 2026-08-29
14
+
15
+ _This version does not introduce any user-facing changes._
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Eric Kweyunga
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # adjacent-cli
2
+
3
+ The adj command: create and convert Adjacent apps, and run them on Android over a trusted tunnel.
4
+
5
+ ## Documentation
6
+
7
+ - [Creating an application](https://github.com/erickweyunga/adjacent-framework/blob/main/docs/create.md)
8
+ - [Adding Adjacent to an existing application](https://github.com/erickweyunga/adjacent-framework/blob/main/docs/init.md)
9
+ - [Development commands](https://github.com/erickweyunga/adjacent-framework/blob/main/docs/cli.md)
10
+ - [All the documentation](https://github.com/erickweyunga/adjacent-framework/blob/main/docs/README.md)
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ npm install --save-dev adjacent-cli
16
+ ```
17
+
18
+ Or run it without installing anything:
19
+
20
+ ```bash
21
+ npx adjacent-cli@latest create my-app
22
+ ```
23
+
24
+ Running on a device needs
25
+ [`adjacent-dev-client`](https://www.npmjs.com/package/adjacent-dev-client),
26
+ which carries the Android toolchain and is loaded only when a command asks for
27
+ one.
28
+
29
+ `adj create` scaffolds with `create-next-app` and adds Adjacent to the
30
+ result; `adj init` does the same to an application that already exists. `adj dev
31
+ --android` serves it over a trusted HTTPS tunnel and launches it fullscreen as a
32
+ Trusted Web Activity. Runs on Node and on Bun, and shells out to whichever
33
+ package manager the project already uses.
34
+
35
+ ## Issues
36
+
37
+ If you hit a problem using this package, please
38
+ [report it here](https://github.com/erickweyunga/adjacent-framework/issues/new).
39
+
40
+ ## Contributing
41
+
42
+ Issues and pull requests are welcome. Please read the
43
+ [contributing guide](https://github.com/erickweyunga/adjacent-framework/blob/main/CONTRIBUTING.md)
44
+ first.
45
+
46
+ ## License
47
+
48
+ MIT
@@ -0,0 +1,54 @@
1
+ export interface AndroidDevOptions {
2
+ readonly device?: string;
3
+ readonly platform: "android";
4
+ readonly port: number;
5
+ readonly projectRoot: string;
6
+ readonly standalone: boolean;
7
+ readonly verbose: boolean;
8
+ }
9
+ export interface AndroidInstallOptions {
10
+ readonly command: "install";
11
+ readonly device?: string;
12
+ readonly platform: "android";
13
+ readonly port: number;
14
+ readonly projectRoot: string;
15
+ readonly verbose: boolean;
16
+ }
17
+ export interface AndroidCliOptions {
18
+ readonly android?: boolean;
19
+ readonly browser?: boolean;
20
+ readonly device?: string;
21
+ readonly port?: string | number;
22
+ readonly project?: string;
23
+ readonly standalone?: boolean;
24
+ readonly verbose?: boolean;
25
+ }
26
+ export declare function resolveAndroidDevOptions(options: AndroidCliOptions): AndroidDevOptions;
27
+ export declare function resolveAndroidInstallOptions(options: AndroidCliOptions): AndroidInstallOptions;
28
+ export interface DevCommandCliOptions {
29
+ readonly project?: string;
30
+ }
31
+ export declare function resolveDevCommandProject(options: DevCommandCliOptions): string;
32
+ export declare function resolveNavigatePath(path: string | undefined): string;
33
+ export interface CreateCliOptions {
34
+ readonly directory?: string;
35
+ /** cac maps `--no-install` onto this, defaulting to true. */
36
+ readonly install?: boolean;
37
+ }
38
+ export interface CreateOptionsInput {
39
+ readonly directory?: string;
40
+ readonly install: boolean;
41
+ readonly projectName: string;
42
+ }
43
+ export declare function resolveCreateOptions(projectName: string | undefined, options: CreateCliOptions): CreateOptionsInput;
44
+ export interface InitCliOptions {
45
+ /** cac maps `--no-install` onto this, defaulting to true. */
46
+ readonly install?: boolean;
47
+ readonly project?: string;
48
+ }
49
+ export interface InitOptionsInput {
50
+ readonly install: boolean;
51
+ readonly projectRoot: string;
52
+ }
53
+ export declare function resolveInitOptions(options: InitCliOptions): InitOptionsInput;
54
+ //# sourceMappingURL=arguments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arguments.d.ts","sourceRoot":"","sources":["../src/arguments.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAiBD,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,iBAAiB,GACzB,iBAAiB,CAcnB;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,iBAAiB,GACzB,qBAAqB,CAUvB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,oBAAoB,GAC5B,MAAM,CAER;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAQpE;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,6DAA6D;IAC7D,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,OAAO,EAAE,gBAAgB,GACxB,kBAAkB,CAapB;AAED,MAAM,WAAW,cAAc;IAC7B,6DAA6D;IAC7D,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,cAAc,GAAG,gBAAgB,CAO5E"}
@@ -0,0 +1,68 @@
1
+ function resolvePort(value) {
2
+ const supplied = value ?? 3000;
3
+ const port = Number(supplied);
4
+ if (!Number.isInteger(port) || port < 1 || port > 65_535) {
5
+ throw new Error(`Invalid port: ${supplied}`);
6
+ }
7
+ return port;
8
+ }
9
+ function assertAndroid(options) {
10
+ if (!options.android) {
11
+ throw new Error("Choose the Android platform with --android.");
12
+ }
13
+ }
14
+ export function resolveAndroidDevOptions(options) {
15
+ assertAndroid(options);
16
+ if (options.browser && options.standalone) {
17
+ throw new Error("--browser and --standalone cannot be used together.");
18
+ }
19
+ return {
20
+ device: options.device,
21
+ platform: "android",
22
+ port: resolvePort(options.port),
23
+ projectRoot: options.project ?? process.cwd(),
24
+ standalone: !options.browser,
25
+ verbose: options.verbose ?? false,
26
+ };
27
+ }
28
+ export function resolveAndroidInstallOptions(options) {
29
+ assertAndroid(options);
30
+ return {
31
+ command: "install",
32
+ device: options.device,
33
+ platform: "android",
34
+ port: resolvePort(options.port),
35
+ projectRoot: options.project ?? process.cwd(),
36
+ verbose: options.verbose ?? false,
37
+ };
38
+ }
39
+ export function resolveDevCommandProject(options) {
40
+ return options.project ?? process.cwd();
41
+ }
42
+ export function resolveNavigatePath(path) {
43
+ const value = (path ?? "").trim();
44
+ if (!value.startsWith("/") || value[1] === "/" || value[1] === "\\") {
45
+ throw new Error(`Invalid path: ${path ?? "(none)"}. Pass a same-origin path such as /orders.`);
46
+ }
47
+ return value;
48
+ }
49
+ export function resolveCreateOptions(projectName, options) {
50
+ const name = (projectName ?? "").trim();
51
+ if (name.length === 0) {
52
+ throw new Error("A project name is required, for example: adj create my-app");
53
+ }
54
+ const directory = options.directory?.trim();
55
+ return {
56
+ ...(directory === undefined || directory.length === 0 ? null : { directory }),
57
+ install: options.install ?? true,
58
+ projectName: name,
59
+ };
60
+ }
61
+ export function resolveInitOptions(options) {
62
+ const project = options.project?.trim();
63
+ return {
64
+ install: options.install ?? true,
65
+ projectRoot: project === undefined || project.length === 0 ? process.cwd() : project,
66
+ };
67
+ }
68
+ //# sourceMappingURL=arguments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arguments.js","sourceRoot":"","sources":["../src/arguments.ts"],"names":[],"mappings":"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"}
package/dist/bin.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}
package/dist/bin.js ADDED
@@ -0,0 +1,140 @@
1
+ #!/usr/bin/env node
2
+ import { cac } from "cac";
3
+ import { resolveAndroidDevOptions, resolveAndroidInstallOptions, resolveCreateOptions, resolveDevCommandProject, resolveInitOptions, resolveNavigatePath, } from "./arguments.js";
4
+ import { runCreate } from "./create.js";
5
+ import { ADJACENT_VERSION } from "./dependencies.js";
6
+ import { runInitCommand } from "./init.js";
7
+ import { DEV_COMMAND } from "./dev-channel.js";
8
+ import { PROJECT_CHECKS } from "./checks.js";
9
+ import { runDevCommand } from "./dev.js";
10
+ import { runDoctor } from "./doctor.js";
11
+ /*
12
+ * Named through a variable so this stays a runtime lookup. The CLI does not
13
+ * depend on the development client in either direction: the client is built on
14
+ * the CLI, and depending back on it would be a cycle.
15
+ */
16
+ const DEV_CLIENT = "adjacent-dev-client";
17
+ /**
18
+ * Reaching a real device needs the Android toolchain, which is most of what
19
+ * installing Adjacent would otherwise cost. It lives in its own package, loaded
20
+ * only when a command asks for a device, so everything else stays light.
21
+ */
22
+ async function devClient() {
23
+ try {
24
+ return (await import(DEV_CLIENT));
25
+ }
26
+ catch {
27
+ throw new Error("This needs the Adjacent development client, which carries the Android " +
28
+ "toolchain:\n\n npm install --save-dev adjacent-dev-client\n\n" +
29
+ "Everything else works without it.");
30
+ }
31
+ }
32
+ const cli = cac("adj");
33
+ function addAndroidTargetOptions(command) {
34
+ return command
35
+ .option("--android", "Target Android")
36
+ .option("--project <path>", "Use an Adjacent project at this path")
37
+ .option("--port <port>", "Run the Next.js server on this port", {
38
+ default: 3000,
39
+ })
40
+ .option("--device <serial>", "Use a specific ADB device")
41
+ .option("--verbose", "Show infrastructure logs");
42
+ }
43
+ cli
44
+ .command("create <project-name>", "Create a new Adjacent application")
45
+ .option("--directory <path>", "Write the project here instead of ./<project-name>")
46
+ .option("--no-install", "Skip installing dependencies")
47
+ .example("adj create my-app")
48
+ .example("adj create my-app --directory apps/my-app --no-install")
49
+ .action(async (projectName, options) => {
50
+ await runCreate(resolveCreateOptions(projectName, options));
51
+ });
52
+ cli
53
+ .command("init", "Add Adjacent to an existing Next.js application")
54
+ .option("--project <path>", "Use an Adjacent project at this path")
55
+ .option("--no-install", "Skip installing dependencies")
56
+ .example("adj init")
57
+ .example("adj init --project apps/web")
58
+ .action(async (options) => {
59
+ await runInitCommand(resolveInitOptions(options));
60
+ });
61
+ addAndroidTargetOptions(cli.command("dev", "Run an Adjacent app on a development device"))
62
+ .option("--browser", "Open in Chrome instead of the standalone wrapper")
63
+ .option("--standalone", "Open in the standalone Android wrapper")
64
+ .example("adj dev --android")
65
+ .example("adj dev --android --device emulator-5554")
66
+ .action(async (options) => {
67
+ const { runAndroidDev } = await devClient();
68
+ await runAndroidDev(resolveAndroidDevOptions(options));
69
+ });
70
+ addAndroidTargetOptions(cli.command("install", "Build and install the Android development wrapper"))
71
+ .example("adj install --android")
72
+ .action(async (options) => {
73
+ const { runAndroidInstall } = await devClient();
74
+ await runAndroidInstall(resolveAndroidInstallOptions(options));
75
+ });
76
+ cli
77
+ .command("reload", "Reload the running app on every connected device")
78
+ .option("--project <path>", "Use an Adjacent project at this path")
79
+ .example("adj reload")
80
+ .action(async (options) => {
81
+ await runDevCommand(resolveDevCommandProject(options), {
82
+ type: DEV_COMMAND.reload,
83
+ });
84
+ });
85
+ cli
86
+ .command("clear-cache", "Clear Adjacent caches and workers, then reload")
87
+ .option("--project <path>", "Use an Adjacent project at this path")
88
+ .example("adj clear-cache")
89
+ .action(async (options) => {
90
+ await runDevCommand(resolveDevCommandProject(options), {
91
+ type: DEV_COMMAND.clearCache,
92
+ });
93
+ });
94
+ cli
95
+ .command("navigate <path>", "Send the running app to a route")
96
+ .option("--project <path>", "Use an Adjacent project at this path")
97
+ .example("adj navigate /admin/orders")
98
+ .action(async (path, options) => {
99
+ await runDevCommand(resolveDevCommandProject(options), {
100
+ path: resolveNavigatePath(path),
101
+ type: DEV_COMMAND.navigate,
102
+ });
103
+ });
104
+ cli
105
+ .command("doctor", "Check the project, and the Android toolchain when present")
106
+ .option("--project <path>", "Check an Adjacent project at this path")
107
+ .option("--url <url>", "Validate a deployed URL against the quality criteria")
108
+ .example("adj doctor")
109
+ .example("adj doctor --url https://example.com")
110
+ .action(async (options) => {
111
+ // Most of what doctor checks has nothing to do with Android, so it runs
112
+ // whether or not the client is installed and says what it could not check.
113
+ const client = await devClient().catch(() => undefined);
114
+ await runDoctor({
115
+ ...(client === undefined ? null : { androidChecks: client.ANDROID_CHECKS }),
116
+ checks: PROJECT_CHECKS,
117
+ projectRoot: resolveDevCommandProject(options),
118
+ ...(options.url === undefined ? null : { url: options.url }),
119
+ });
120
+ });
121
+ cli.help();
122
+ // Read from the manifest, so a published CLI reports the version it actually
123
+ // is rather than the one somebody last typed here.
124
+ cli.version(ADJACENT_VERSION);
125
+ async function main() {
126
+ cli.parse(process.argv, { run: false });
127
+ if (cli.options.help || cli.options.version)
128
+ return;
129
+ if (!cli.matchedCommand) {
130
+ cli.outputHelp();
131
+ return;
132
+ }
133
+ await cli.runMatchedCommand();
134
+ }
135
+ main().catch((error) => {
136
+ const message = error instanceof Error ? error.message : String(error);
137
+ console.error(`Adjacent failed: ${message}`);
138
+ process.exitCode = 1;
139
+ });
140
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import { type DoctorCheck } from "./doctor.js";
2
+ /**
3
+ * The assets a manifest points at unless the configuration names its own. A
4
+ * manifest referring to an icon that is not there installs an app with no icon,
5
+ * and nothing fails until someone tries to install it.
6
+ */
7
+ declare const CONVENTIONAL_ICONS: readonly ["apple-touch-icon.png", "favicon.ico", "favicon-96x96.png", "favicon.svg", "web-app-manifest-192x192.png", "web-app-manifest-512x512.png", "web-app-manifest-maskable-192x192.png", "web-app-manifest-maskable-512x512.png"];
8
+ /**
9
+ * What each conventional icon has to measure. The names carry it, apart from
10
+ * the Apple one, which the metadata declares as 180.
11
+ */
12
+ declare const ICON_SIZES: Readonly<Record<string, number>>;
13
+ /**
14
+ * The pixel dimensions of a PNG, or undefined when it is not one.
15
+ *
16
+ * Read here rather than through an image library: the size lives in the IHDR
17
+ * chunk at a fixed offset, so a dependency that decodes the whole image would
18
+ * be carried for twenty-four bytes.
19
+ */
20
+ export declare function readPngSize(bytes: Uint8Array): {
21
+ readonly height: number;
22
+ readonly width: number;
23
+ } | undefined;
24
+ /**
25
+ * Why an icon is unusable, or undefined when it is fine.
26
+ *
27
+ * A browser measures the file rather than trusting the manifest, so an icon
28
+ * that does not match what was declared is dropped: the application installs
29
+ * with a blank tile, and nothing fails until somebody installs it.
30
+ */
31
+ export declare function describeIconProblem(file: string, bytes: Uint8Array): string | undefined;
32
+ /** Everything checkable without the Android toolchain, which is most of it. */
33
+ export declare const PROJECT_CHECKS: readonly DoctorCheck[];
34
+ export { CONVENTIONAL_ICONS, ICON_SIZES };
35
+ //# sourceMappingURL=checks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checks.d.ts","sourceRoot":"","sources":["../src/checks.ts"],"names":[],"mappings":"AAIA,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/D;;;;GAIG;AACH,QAAA,MAAM,kBAAkB,wOASd,CAAC;AAyFX;;;GAGG;AACH,QAAA,MAAM,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAOhD,CAAC;AAIF;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,UAAU,GAChB;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAKjE;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,UAAU,GAChB,MAAM,GAAG,SAAS,CAepB;AA0ED,+EAA+E;AAC/E,eAAO,MAAM,cAAc,EAAE,SAAS,WAAW,EAQhD,CAAC;AAEF,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,CAAC"}
package/dist/checks.js ADDED
@@ -0,0 +1,206 @@
1
+ import { readFile, stat } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { ADJACENT_PACKAGES } from "./dependencies.js";
4
+ import { failed, passed } from "./doctor.js";
5
+ /**
6
+ * The assets a manifest points at unless the configuration names its own. A
7
+ * manifest referring to an icon that is not there installs an app with no icon,
8
+ * and nothing fails until someone tries to install it.
9
+ */
10
+ const CONVENTIONAL_ICONS = [
11
+ "apple-touch-icon.png",
12
+ "favicon.ico",
13
+ "favicon-96x96.png",
14
+ "favicon.svg",
15
+ "web-app-manifest-192x192.png",
16
+ "web-app-manifest-512x512.png",
17
+ "web-app-manifest-maskable-192x192.png",
18
+ "web-app-manifest-maskable-512x512.png",
19
+ ];
20
+ async function missingFiles(root, files) {
21
+ const absent = [];
22
+ for (const file of files) {
23
+ const found = await stat(join(root, file)).catch(() => undefined);
24
+ if (!found?.isFile())
25
+ absent.push(file);
26
+ }
27
+ return absent;
28
+ }
29
+ const configuration = {
30
+ description: "Adjacent is configured",
31
+ async run({ read }) {
32
+ const source = await read("app.config.ts");
33
+ if (source === undefined) {
34
+ return failed(["app.config.ts is missing."], "Run `adj init` to add it, or write one with defineConfig from adjacent-core.");
35
+ }
36
+ return source.includes("defineConfig")
37
+ ? passed
38
+ : failed(["app.config.ts does not call defineConfig."], "Its default export has to be defineConfig(...) so the configuration is validated.");
39
+ },
40
+ };
41
+ const nextConfig = {
42
+ description: "next.config.ts is wrapped",
43
+ async run({ read, survey }) {
44
+ const file = survey.nextConfigFile ?? "next.config.ts";
45
+ const source = await read(file);
46
+ if (source === undefined) {
47
+ return failed([`${file} is missing.`], "Run `adj init` to add it.");
48
+ }
49
+ return source.includes("withAdjacent")
50
+ ? passed
51
+ : failed([`${file} does not call withAdjacent().`], "Without it the development origins, headers and rewrites are not configured.");
52
+ },
53
+ };
54
+ const rootLayout = {
55
+ description: "The root layout is wrapped",
56
+ async run({ read, survey }) {
57
+ const source = await read(survey.layoutFile);
58
+ if (source === undefined) {
59
+ return failed([`${survey.layoutFile} could not be read.`]);
60
+ }
61
+ const issues = [
62
+ ...(source.includes("withAdjacentLayout")
63
+ ? []
64
+ : ["It is not wrapped with withAdjacentLayout()."]),
65
+ ...(source.includes("createAdjacent") ? [] : ["It does not create the runtime."]),
66
+ ];
67
+ return issues.length === 0
68
+ ? passed
69
+ : failed(issues.map((issue) => `${survey.layoutFile}: ${issue}`), "Without both, no metadata is derived and the browser runtime is never injected.");
70
+ },
71
+ };
72
+ const routeBridges = {
73
+ description: "The manifest and service worker routes exist",
74
+ async run({ projectRoot, survey }) {
75
+ // Next.js finds these by their place on disk, so they have to be real files.
76
+ const absent = await missingFiles(projectRoot, [
77
+ join(survey.appDirectory, "manifest.ts"),
78
+ join(survey.appDirectory, "sw.js", "route.ts"),
79
+ ]);
80
+ return absent.length === 0
81
+ ? passed
82
+ : failed(absent.map((file) => `${file} is missing.`), "Next.js discovers these by filename, so they cannot be generated at runtime.");
83
+ },
84
+ };
85
+ /**
86
+ * What each conventional icon has to measure. The names carry it, apart from
87
+ * the Apple one, which the metadata declares as 180.
88
+ */
89
+ const ICON_SIZES = {
90
+ "apple-touch-icon.png": 180,
91
+ "favicon-96x96.png": 96,
92
+ "web-app-manifest-192x192.png": 192,
93
+ "web-app-manifest-512x512.png": 512,
94
+ "web-app-manifest-maskable-192x192.png": 192,
95
+ "web-app-manifest-maskable-512x512.png": 512,
96
+ };
97
+ const PNG_SIGNATURE = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
98
+ /**
99
+ * The pixel dimensions of a PNG, or undefined when it is not one.
100
+ *
101
+ * Read here rather than through an image library: the size lives in the IHDR
102
+ * chunk at a fixed offset, so a dependency that decodes the whole image would
103
+ * be carried for twenty-four bytes.
104
+ */
105
+ export function readPngSize(bytes) {
106
+ const buffer = Buffer.from(bytes);
107
+ if (buffer.length < 24 || !buffer.subarray(0, 8).equals(PNG_SIGNATURE))
108
+ return undefined;
109
+ if (buffer.subarray(12, 16).toString("ascii") !== "IHDR")
110
+ return undefined;
111
+ return { height: buffer.readUInt32BE(20), width: buffer.readUInt32BE(16) };
112
+ }
113
+ /**
114
+ * Why an icon is unusable, or undefined when it is fine.
115
+ *
116
+ * A browser measures the file rather than trusting the manifest, so an icon
117
+ * that does not match what was declared is dropped: the application installs
118
+ * with a blank tile, and nothing fails until somebody installs it.
119
+ */
120
+ export function describeIconProblem(file, bytes) {
121
+ if (bytes.length === 0)
122
+ return `public/${file} is empty.`;
123
+ const expected = ICON_SIZES[file];
124
+ if (expected === undefined)
125
+ return undefined;
126
+ const size = readPngSize(bytes);
127
+ if (!size)
128
+ return `public/${file} is not a PNG.`;
129
+ if (size.width !== size.height) {
130
+ return `public/${file} is ${size.width}x${size.height}, and an icon has to be square.`;
131
+ }
132
+ if (size.width !== expected) {
133
+ return `public/${file} is ${size.width}x${size.width}, but it is declared as ${expected}x${expected}.`;
134
+ }
135
+ return undefined;
136
+ }
137
+ const icons = {
138
+ description: "The manifest icons are present",
139
+ async run({ projectRoot }) {
140
+ const root = join(projectRoot, "public");
141
+ const absent = await missingFiles(root, [...CONVENTIONAL_ICONS]);
142
+ const problems = [...absent.map((file) => `public/${file} is missing.`)];
143
+ for (const file of CONVENTIONAL_ICONS) {
144
+ if (absent.includes(file))
145
+ continue;
146
+ const bytes = await readFile(join(root, file)).catch(() => undefined);
147
+ const problem = bytes && describeIconProblem(file, bytes);
148
+ if (problem)
149
+ problems.push(problem);
150
+ }
151
+ return problems.length === 0
152
+ ? passed
153
+ : failed(problems, "An installed app shows a blank icon, and nothing fails until someone installs it.");
154
+ },
155
+ };
156
+ /**
157
+ * Stores are stricter than the web standard about the short name. Nothing fails
158
+ * until a package is submitted and rejected, which is late, so this reports it
159
+ * rather than the build refusing a name the web itself accepts.
160
+ */
161
+ const SHORT_NAME_FLOOR = 3;
162
+ const shortName = {
163
+ description: "The short name can be packaged for a store",
164
+ async run({ read }) {
165
+ const source = await read("app.config.ts");
166
+ if (source === undefined)
167
+ return passed;
168
+ const declared = /shortName\s*:\s*"([^"]*)"/.exec(source)?.[1];
169
+ if (declared === undefined || declared.length >= SHORT_NAME_FLOOR)
170
+ return passed;
171
+ return failed([`shortName is ${declared.length} character${declared.length === 1 ? "" : "s"}: "${declared}".`], `Stores require at least ${SHORT_NAME_FLOOR}. A web manifest accepts it, so nothing fails until a package is submitted.`);
172
+ },
173
+ };
174
+ const versionsAgree = {
175
+ description: "The Adjacent packages agree on a version",
176
+ async run({ survey }) {
177
+ const dependencies = {
178
+ ...survey.packageJson.dependencies,
179
+ ...survey.packageJson.devDependencies,
180
+ };
181
+ const installed = ADJACENT_PACKAGES.flatMap(({ name }) => {
182
+ const range = dependencies[name];
183
+ // A local link has no version to compare, and is deliberate.
184
+ if (range === undefined || range.startsWith("file:") || range.startsWith("workspace:")) {
185
+ return [];
186
+ }
187
+ return [[name, range]];
188
+ });
189
+ const ranges = new Set(installed.map(([, range]) => range));
190
+ return ranges.size <= 1
191
+ ? passed
192
+ : failed(installed.map(([name, range]) => `${name} is ${range}`), "These are released together, so mixing versions can install two copies of one package.");
193
+ },
194
+ };
195
+ /** Everything checkable without the Android toolchain, which is most of it. */
196
+ export const PROJECT_CHECKS = [
197
+ configuration,
198
+ nextConfig,
199
+ rootLayout,
200
+ routeBridges,
201
+ icons,
202
+ shortName,
203
+ versionsAgree,
204
+ ];
205
+ export { CONVENTIONAL_ICONS, ICON_SIZES };
206
+ //# sourceMappingURL=checks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checks.js","sourceRoot":"","sources":["../src/checks.ts"],"names":[],"mappings":"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"}