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.
- package/CHANGELOG.md +15 -0
- package/LICENSE +21 -0
- package/README.md +48 -0
- package/dist/arguments.d.ts +54 -0
- package/dist/arguments.d.ts.map +1 -0
- package/dist/arguments.js +68 -0
- package/dist/arguments.js.map +1 -0
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +140 -0
- package/dist/bin.js.map +1 -0
- package/dist/checks.d.ts +35 -0
- package/dist/checks.d.ts.map +1 -0
- package/dist/checks.js +206 -0
- package/dist/checks.js.map +1 -0
- package/dist/create.d.ts +42 -0
- package/dist/create.d.ts.map +1 -0
- package/dist/create.js +82 -0
- package/dist/create.js.map +1 -0
- package/dist/dependencies.d.ts +59 -0
- package/dist/dependencies.d.ts.map +1 -0
- package/dist/dependencies.js +100 -0
- package/dist/dependencies.js.map +1 -0
- package/dist/destination.d.ts +16 -0
- package/dist/destination.d.ts.map +1 -0
- package/dist/destination.js +39 -0
- package/dist/destination.js.map +1 -0
- package/dist/dev-channel.d.ts +40 -0
- package/dist/dev-channel.d.ts.map +1 -0
- package/dist/dev-channel.js +192 -0
- package/dist/dev-channel.js.map +1 -0
- package/dist/dev.d.ts +3 -0
- package/dist/dev.d.ts.map +1 -0
- package/dist/dev.js +12 -0
- package/dist/dev.js.map +1 -0
- package/dist/doctor.d.ts +46 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +52 -0
- package/dist/doctor.js.map +1 -0
- package/dist/edits.d.ts +26 -0
- package/dist/edits.d.ts.map +1 -0
- package/dist/edits.js +101 -0
- package/dist/edits.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +62 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +275 -0
- package/dist/init.js.map +1 -0
- package/dist/keys.d.ts +14 -0
- package/dist/keys.d.ts.map +1 -0
- package/dist/keys.js +66 -0
- package/dist/keys.js.map +1 -0
- package/dist/package-manager.d.ts +40 -0
- package/dist/package-manager.d.ts.map +1 -0
- package/dist/package-manager.js +98 -0
- package/dist/package-manager.js.map +1 -0
- package/dist/process.d.ts +33 -0
- package/dist/process.d.ts.map +1 -0
- package/dist/process.js +95 -0
- package/dist/process.js.map +1 -0
- package/dist/project-name.d.ts +30 -0
- package/dist/project-name.d.ts.map +1 -0
- package/dist/project-name.js +73 -0
- package/dist/project-name.js.map +1 -0
- package/dist/reporter.d.ts +12 -0
- package/dist/reporter.d.ts.map +1 -0
- package/dist/reporter.js +11 -0
- package/dist/reporter.js.map +1 -0
- package/dist/rewrite.d.ts +54 -0
- package/dist/rewrite.d.ts.map +1 -0
- package/dist/rewrite.js +262 -0
- package/dist/rewrite.js.map +1 -0
- package/dist/shutdown.d.ts +24 -0
- package/dist/shutdown.d.ts.map +1 -0
- package/dist/shutdown.js +67 -0
- package/dist/shutdown.js.map +1 -0
- package/dist/survey.d.ts +33 -0
- package/dist/survey.d.ts.map +1 -0
- package/dist/survey.js +94 -0
- package/dist/survey.js.map +1 -0
- package/dist/template.d.ts +29 -0
- package/dist/template.d.ts.map +1 -0
- package/dist/template.js +77 -0
- package/dist/template.js.map +1 -0
- package/dist/ui.d.ts +14 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +50 -0
- package/dist/ui.js.map +1 -0
- package/package.json +65 -0
- package/templates/adjacent/app/manifest.ts +5 -0
- package/templates/adjacent/app/sw.js/route.ts +5 -0
- package/templates/adjacent/app.config.ts +21 -0
- package/templates/adjacent/components/navigation.tsx +46 -0
- package/templates/adjacent/public/apple-touch-icon.png +0 -0
- package/templates/adjacent/public/favicon-96x96.png +0 -0
- package/templates/adjacent/public/favicon.ico +0 -0
- package/templates/adjacent/public/favicon.svg +4 -0
- package/templates/adjacent/public/web-app-manifest-192x192.png +0 -0
- package/templates/adjacent/public/web-app-manifest-512x512.png +0 -0
- package/templates/adjacent/public/web-app-manifest-maskable-192x192.png +0 -0
- package/templates/adjacent/public/web-app-manifest-maskable-512x512.png +0 -0
- package/templates/starter/app/(app)/layout.tsx +12 -0
- package/templates/starter/app/(app)/page.tsx +75 -0
- package/templates/starter/app/(app)/settings/page.tsx +24 -0
- package/templates/starter/app/(app)/settings/settings-panel.tsx +54 -0
package/CHANGELOG.md
ADDED
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 @@
|
|
|
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
|
package/dist/bin.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":"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"}
|
package/dist/checks.d.ts
ADDED
|
@@ -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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"}
|