@jtl-software/create-cloud-app 0.0.22 → 0.0.24
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 +120 -14
- package/dist/index.js +10 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,42 +1,148 @@
|
|
|
1
1
|
# @jtl-software/create-cloud-app
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
CLI for [JTL Platform](https://www.jtl-software.com/) cloud apps. Scaffolds a new app project and registers/updates its manifest against the cloud.
|
|
4
4
|
|
|
5
5
|
## Requirements
|
|
6
6
|
|
|
7
7
|
Node.js **24** (current LTS) or newer. The scaffolded project sets the same floor via `engines.node`.
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## Commands
|
|
10
|
+
|
|
11
|
+
The CLI has two entry points:
|
|
12
|
+
|
|
13
|
+
- The default invocation (no arguments) scaffolds a new project.
|
|
14
|
+
- `register` registers or updates a manifest against the JTL Cloud.
|
|
15
|
+
|
|
16
|
+
### `npm create @jtl-software/cloud-app@latest`
|
|
17
|
+
|
|
18
|
+
Scaffold a new app interactively.
|
|
10
19
|
|
|
11
20
|
```bash
|
|
12
21
|
npm create @jtl-software/cloud-app@latest
|
|
13
22
|
```
|
|
14
23
|
|
|
15
|
-
|
|
24
|
+
You'll be prompted for:
|
|
16
25
|
|
|
17
|
-
- **App name
|
|
18
|
-
- **Description
|
|
19
|
-
- **Backend
|
|
20
|
-
- **Frontend
|
|
26
|
+
- **App name**: directory name, package name, and manifest identifier
|
|
27
|
+
- **Description**: placed in the app manifest
|
|
28
|
+
- **Backend**: Node.js (Express + TypeScript) or .NET (ASP.NET Core + FastEndpoints)
|
|
29
|
+
- **Frontend**: React (Vite + Tailwind + JTL Platform UI)
|
|
21
30
|
|
|
22
|
-
Then
|
|
31
|
+
Then:
|
|
23
32
|
|
|
24
33
|
```bash
|
|
25
34
|
cd my-app
|
|
26
35
|
npm install
|
|
36
|
+
npm run register
|
|
27
37
|
npm run dev
|
|
28
38
|
```
|
|
29
39
|
|
|
30
|
-
|
|
40
|
+
The generated project includes:
|
|
41
|
+
|
|
42
|
+
- A monorepo wired up with [Turborepo](https://turbo.build/)
|
|
43
|
+
- A frontend with welcome pages explaining each app mode and manifest mapping
|
|
44
|
+
- A backend with JWT verification, tenant connection, and ERP API proxy
|
|
45
|
+
- A ready-to-register `manifest.json`
|
|
46
|
+
- An `npm run register` script that delegates to `npx -y @jtl-software/create-cloud-app@latest register`
|
|
47
|
+
|
|
48
|
+
### `register`
|
|
49
|
+
|
|
50
|
+
Register a new app or update an existing app's manifest. Reads `manifest.json` from the current working directory and pushes it to the App Service.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npx @jtl-software/create-cloud-app register
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
By default the command is interactive: it opens a browser for OAuth login, then prompts for tenant and whether to update an existing app or create a new one.
|
|
57
|
+
|
|
58
|
+
Flags:
|
|
59
|
+
|
|
60
|
+
| Flag | Description |
|
|
61
|
+
| ------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
62
|
+
| `--api-host <url>` | API host. Default `https://api.jtl-cloud.com`. |
|
|
63
|
+
| `--auth-host <url>` | OAuth host. Default `https://auth.jtl-cloud.com`. The CLI picks the matching client ID for the known prod/QA/dev hosts. |
|
|
64
|
+
| `--hub-host <url>` | Hub host (used in printed links). Default `https://hub.jtl-cloud.com`. |
|
|
65
|
+
| `--client-id <id>` | Override the OAuth client ID. Only needed for custom auth hosts. |
|
|
66
|
+
| `--scope <scope>` | OAuth scope. Default `openid offline_access`. |
|
|
67
|
+
| `--reauth` | Skip the cached token and open the browser again. Useful after switching accounts. |
|
|
68
|
+
| `--yes`, `-y` | Non-interactive mode. Auto-confirms prompts and fails if any choice is ambiguous (e.g. multiple tenants match). Required for CI. |
|
|
69
|
+
| `--tenant <id-or-slug>` | Select a tenant by ID or slug (case-insensitive). |
|
|
70
|
+
| `--existing-app-id <id>` | Update the app with this ID instead of prompting. Errors if it doesn't match this manifest's technical name. |
|
|
71
|
+
| `--new` | Force-create a new app even if a matching one exists. Mutually exclusive with `--existing-app-id`. |
|
|
72
|
+
| `--on-collision <overwrite\|print\|cancel>` | What to do when an existing credentials file would be overwritten during provisioning. `print` writes the secret to stdout instead of the file. Required in `--yes` mode if a collision is possible. |
|
|
73
|
+
|
|
74
|
+
Tokens are cached under `~/.config/jtl-cli/tokens.json` (mode `0600`). Override the path with the `JTL_CLI_TOKEN_CACHE_FILE` environment variable.
|
|
75
|
+
|
|
76
|
+
## CI usage: keep your deployed manifest in sync with the repo
|
|
77
|
+
|
|
78
|
+
A common setup is to commit `manifest.json` to source control and have CI push it to the cloud whenever it changes, so the deployed app always matches what's on `main`.
|
|
79
|
+
|
|
80
|
+
The `register` command supports this. You need three things:
|
|
81
|
+
|
|
82
|
+
1. **Pin the tenant and app ID** so the run is deterministic.
|
|
83
|
+
2. **Run with `--yes`** so prompts don't block.
|
|
84
|
+
3. **Seed the OAuth token cache** so login doesn't open a browser.
|
|
85
|
+
|
|
86
|
+
### Step 1: capture a refresh token locally
|
|
87
|
+
|
|
88
|
+
Run `register` once on your machine while signed in as the user (or service account) you want CI to act as:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
cd path/to/your/app
|
|
92
|
+
npx @jtl-software/create-cloud-app register --scope "openid offline_access"
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
After it completes, `~/.config/jtl-cli/tokens.json` contains an entry with a `refresh_token`. Copy that file's contents and store it as a CI secret (e.g. `JTL_CLI_TOKENS`).
|
|
96
|
+
|
|
97
|
+
The cached token will be silently refreshed on every CI run, so it stays valid as long as CI runs often enough that the refresh token doesn't expire.
|
|
98
|
+
|
|
99
|
+
### Step 2: look up your tenant and app ID
|
|
100
|
+
|
|
101
|
+
You can read them off the previous interactive run (the CLI prints both). The tenant slug is the stable, human-friendly identifier. The app ID is a UUID printed in the "Review" section.
|
|
102
|
+
|
|
103
|
+
### Step 3: CI workflow
|
|
104
|
+
|
|
105
|
+
GitHub Actions example:
|
|
106
|
+
|
|
107
|
+
```yaml
|
|
108
|
+
name: Update manifest
|
|
109
|
+
|
|
110
|
+
on:
|
|
111
|
+
push:
|
|
112
|
+
branches: [main]
|
|
113
|
+
paths:
|
|
114
|
+
- manifest.json
|
|
115
|
+
|
|
116
|
+
jobs:
|
|
117
|
+
register:
|
|
118
|
+
runs-on: ubuntu-latest
|
|
119
|
+
steps:
|
|
120
|
+
- uses: actions/checkout@v4
|
|
121
|
+
- uses: actions/setup-node@v4
|
|
122
|
+
with:
|
|
123
|
+
node-version: 24
|
|
124
|
+
- name: Write token cache
|
|
125
|
+
env:
|
|
126
|
+
JTL_CLI_TOKENS: ${{ secrets.JTL_CLI_TOKENS }}
|
|
127
|
+
run: |
|
|
128
|
+
mkdir -p "$RUNNER_TEMP/jtl-cli"
|
|
129
|
+
printf '%s' "$JTL_CLI_TOKENS" > "$RUNNER_TEMP/jtl-cli/tokens.json"
|
|
130
|
+
chmod 600 "$RUNNER_TEMP/jtl-cli/tokens.json"
|
|
131
|
+
- name: Update manifest
|
|
132
|
+
env:
|
|
133
|
+
JTL_CLI_TOKEN_CACHE_FILE: ${{ runner.temp }}/jtl-cli/tokens.json
|
|
134
|
+
run: |
|
|
135
|
+
npx -y @jtl-software/create-cloud-app@latest register \
|
|
136
|
+
--yes \
|
|
137
|
+
--tenant my-tenant-slug \
|
|
138
|
+
--existing-app-id 00000000-0000-0000-0000-000000000000
|
|
139
|
+
```
|
|
31
140
|
|
|
32
|
-
-
|
|
33
|
-
- Frontend with welcome pages explaining each app mode and manifest mapping
|
|
34
|
-
- Backend with JWT verification, tenant connection, and ERP API proxy
|
|
35
|
-
- Ready-to-register `manifest.json`
|
|
141
|
+
`--yes` keeps the run non-interactive. `--tenant` and `--existing-app-id` pin the target so the command can't accidentally touch a different tenant or app. The job only runs when `manifest.json` changes, so the deployed manifest tracks `main`.
|
|
36
142
|
|
|
37
143
|
## After scaffolding
|
|
38
144
|
|
|
39
|
-
1. Register your manifest in the [Partner Portal](https://partner.jtl-cloud.com/)
|
|
145
|
+
1. Register your manifest in the [Partner Portal](https://partner.jtl-cloud.com/) or with `npm run register`
|
|
40
146
|
2. Add your Client ID and Secret to the backend config
|
|
41
147
|
3. Install the app from [JTL-Cloud Hub](https://hub.jtl-cloud.com/) under "Apps in development"
|
|
42
148
|
|
package/dist/index.js
CHANGED
|
@@ -237,14 +237,17 @@ function makeCachedToken(clientId, tokens, fallbackRefreshToken, scope) {
|
|
|
237
237
|
}
|
|
238
238
|
var defaultOpener = (url) => {
|
|
239
239
|
const platform = process.platform;
|
|
240
|
-
const cmd = platform === "darwin" ? "open" : platform === "win32" ? "start" : "xdg-open";
|
|
241
|
-
const args = platform === "win32" ? ["", url] : [url];
|
|
242
240
|
try {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
241
|
+
if (platform === "win32") {
|
|
242
|
+
spawn("cmd.exe", ["/c", `start "" "${url}"`], {
|
|
243
|
+
stdio: "ignore",
|
|
244
|
+
detached: true,
|
|
245
|
+
windowsVerbatimArguments: true
|
|
246
|
+
}).unref();
|
|
247
|
+
} else {
|
|
248
|
+
const cmd = platform === "darwin" ? "open" : "xdg-open";
|
|
249
|
+
spawn(cmd, [url], { stdio: "ignore", detached: true }).unref();
|
|
250
|
+
}
|
|
248
251
|
} catch {
|
|
249
252
|
}
|
|
250
253
|
};
|