@upfluxhq/cli 1.1.0 → 1.2.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/README.md +117 -248
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.js +149 -0
- package/dist/commands/release.js +86 -29
- package/dist/index.js +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,35 +10,61 @@ npm install -g @upfluxhq/cli
|
|
|
10
10
|
pnpm add -g @upfluxhq/cli
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
+
---
|
|
14
|
+
|
|
13
15
|
## Quick Start
|
|
14
16
|
|
|
15
17
|
```bash
|
|
16
|
-
# 1.
|
|
17
|
-
upflux
|
|
18
|
-
|
|
18
|
+
# 1. Initialize project config (creates upflux.json)
|
|
19
|
+
upflux init
|
|
20
|
+
|
|
21
|
+
# 2. Authenticate with your publish key (from Upflux dashboard)
|
|
22
|
+
upflux login --key <publish-key>
|
|
19
23
|
|
|
20
|
-
#
|
|
21
|
-
upflux release
|
|
24
|
+
# 3. Publish a release (auto-increments buildNumber)
|
|
25
|
+
upflux release
|
|
22
26
|
|
|
23
|
-
#
|
|
27
|
+
# 4. Check deployment status
|
|
24
28
|
upflux status
|
|
25
29
|
```
|
|
26
30
|
|
|
31
|
+
---
|
|
32
|
+
|
|
27
33
|
## Commands
|
|
28
34
|
|
|
29
|
-
### `
|
|
35
|
+
### `init`
|
|
30
36
|
|
|
31
|
-
|
|
37
|
+
Interactive wizard to configure `upflux.json` in your project root. Replaces manual configuration in your app code with declarative deployment profiles.
|
|
32
38
|
|
|
33
39
|
```bash
|
|
34
|
-
upflux
|
|
40
|
+
upflux init [options]
|
|
35
41
|
```
|
|
36
42
|
|
|
37
43
|
| Option | Description |
|
|
38
44
|
|--------|-------------|
|
|
39
|
-
|
|
|
45
|
+
| `--force` | Overwrite existing `upflux.json` without prompting |
|
|
46
|
+
|
|
47
|
+
**What it sets up:**
|
|
48
|
+
- App ID & server URL
|
|
49
|
+
- Initial `buildNumber` (`0`) and `runtimeVersion` (e.g. `1.0.0`)
|
|
50
|
+
- Deployment profiles (`development`, `production`, etc.) with client keys (`upx_cli_*`)
|
|
51
|
+
- Safe to commit to git — client keys are read-only
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
### `login`
|
|
56
|
+
|
|
57
|
+
Authenticate with the Upflux server using your publish key. **Supports multiple credentials** — each login registers another deployment target.
|
|
40
58
|
|
|
41
|
-
|
|
59
|
+
```bash
|
|
60
|
+
upflux login --key <publishKey>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
| Option | Required | Description |
|
|
64
|
+
|--------|----------|-------------|
|
|
65
|
+
| `-k, --key <publishKey>` | ✓ | Publish key (`upx_pub_*`) from the dashboard |
|
|
66
|
+
|
|
67
|
+
**Example output with multiple credentials:**
|
|
42
68
|
```
|
|
43
69
|
🔐 Verifying with server...
|
|
44
70
|
✓ Login successful!
|
|
@@ -54,7 +80,7 @@ upflux login --key <publishKey>
|
|
|
54
80
|
|
|
55
81
|
### `logout`
|
|
56
82
|
|
|
57
|
-
Remove stored credentials.
|
|
83
|
+
Remove stored publish credentials.
|
|
58
84
|
|
|
59
85
|
```bash
|
|
60
86
|
upflux logout [options]
|
|
@@ -62,14 +88,14 @@ upflux logout [options]
|
|
|
62
88
|
|
|
63
89
|
| Option | Description |
|
|
64
90
|
|--------|-------------|
|
|
65
|
-
| `--all` | Remove all credentials |
|
|
91
|
+
| `--all` | Remove all stored credentials |
|
|
66
92
|
|
|
67
93
|
**Example:**
|
|
68
94
|
```bash
|
|
69
|
-
# Interactive selection
|
|
95
|
+
# Interactive selection:
|
|
70
96
|
upflux logout
|
|
71
97
|
|
|
72
|
-
#
|
|
98
|
+
# Clear all credentials:
|
|
73
99
|
upflux logout --all
|
|
74
100
|
```
|
|
75
101
|
|
|
@@ -77,159 +103,105 @@ upflux logout --all
|
|
|
77
103
|
|
|
78
104
|
### `release`
|
|
79
105
|
|
|
80
|
-
Bundle and upload a new release.
|
|
106
|
+
Bundle and upload a new OTA release. Prompts for target deployment if multiple are configured.
|
|
81
107
|
|
|
82
108
|
Automatically detects project type:
|
|
83
|
-
- **React Native**:
|
|
84
|
-
- **Capacitor**:
|
|
109
|
+
- **React Native**: Runs `react-native bundle` for iOS and Android
|
|
110
|
+
- **Capacitor**: Archives the web assets folder (detected from `capacitor.config.*`)
|
|
85
111
|
|
|
86
112
|
```bash
|
|
87
113
|
upflux release [options]
|
|
88
114
|
```
|
|
89
115
|
|
|
90
|
-
| Option |
|
|
91
|
-
|
|
92
|
-
| `-l, --label <label>` |
|
|
93
|
-
| `--platform <platform>` |
|
|
94
|
-
| `-a, --app <appId>` |
|
|
95
|
-
| `-d, --deployment <deploymentId>` |
|
|
96
|
-
| `-
|
|
97
|
-
| `-
|
|
98
|
-
| `-
|
|
99
|
-
| `--
|
|
100
|
-
|
|
|
101
|
-
|
|
|
102
|
-
| `-
|
|
103
|
-
|
|
|
104
|
-
|
|
|
105
|
-
| `--
|
|
106
|
-
| `--
|
|
107
|
-
| `--
|
|
108
|
-
| `--capacitor` |
|
|
109
|
-
| `--web-dir <path>` |
|
|
110
|
-
|
|
111
|
-
|
|
116
|
+
| Option | Description |
|
|
117
|
+
|--------|-------------|
|
|
118
|
+
| `-l, --label <label>` | Release label (e.g. `v1.0.0`). **Optional** — if omitted, auto-increments `buildNumber` in `upflux.json` (e.g. `1.0.0+1`) |
|
|
119
|
+
| `--platform <platform>` | Target platform: `all`, `ios`, or `android` (default: `all`) |
|
|
120
|
+
| `-a, --app <appId>` | Application ID (auto-detected from stored credentials) |
|
|
121
|
+
| `-d, --deployment <deploymentId>` | Target deployment ID (prompts if multiple exist) |
|
|
122
|
+
| `-m, --mandatory` | Mark update as mandatory |
|
|
123
|
+
| `-r, --rollout <number>` | Rollout percentage: `0`–`100` (default: `100`) |
|
|
124
|
+
| `-v, --version-range <range>` | Target binary version semver range (e.g. `>=1.0.0`) |
|
|
125
|
+
| `--min-binary-version <version>` | Minimum native binary version required. Devices below this receive store update prompts. |
|
|
126
|
+
| `--skip-native-check` | Skip automatic git native change inspection |
|
|
127
|
+
| `--schedule` | Create release as a draft to schedule release time via dashboard |
|
|
128
|
+
| `-e, --entry-file <path>` | React Native entry file (default: `index.js`) |
|
|
129
|
+
| `-o, --output-dir <path>` | Output directory for bundles (default: `./dist`) |
|
|
130
|
+
| `-b, --bundle <path>` | Skip bundler, upload prebuilt bundle file |
|
|
131
|
+
| `--assets <paths...>` | Explicit asset files or directories to include |
|
|
132
|
+
| `--dev` | Create development bundle |
|
|
133
|
+
| `--skip-bundle` | Skip bundling, reuse existing files in output directory |
|
|
134
|
+
| `--capacitor` | Force Capacitor bundling mode |
|
|
135
|
+
| `--web-dir <path>` | Custom web asset directory for Capacitor (default: from config or `www`) |
|
|
136
|
+
|
|
137
|
+
#### Examples
|
|
112
138
|
|
|
113
139
|
```bash
|
|
114
|
-
#
|
|
115
|
-
upflux release
|
|
140
|
+
# Recommended: Auto-increment buildNumber from upflux.json (e.g. 1.0.0+1 -> 1.0.0+2)
|
|
141
|
+
upflux release
|
|
116
142
|
|
|
117
|
-
#
|
|
118
|
-
upflux release --label v1.2.
|
|
119
|
-
|
|
120
|
-
# Android-only release with 50% rollout
|
|
121
|
-
upflux release --label v1.2.2 --platform android --rollout 50
|
|
143
|
+
# Release with explicit custom label
|
|
144
|
+
upflux release --label v1.2.0
|
|
122
145
|
|
|
123
|
-
# Mandatory
|
|
124
|
-
upflux release --
|
|
146
|
+
# Mandatory release with gradual 25% rollout
|
|
147
|
+
upflux release --mandatory --rollout 25
|
|
125
148
|
|
|
126
|
-
#
|
|
127
|
-
upflux release --
|
|
149
|
+
# iOS-only emergency hotfix
|
|
150
|
+
upflux release --platform ios
|
|
128
151
|
|
|
129
|
-
# Capacitor
|
|
130
|
-
upflux release --
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
**Example output:**
|
|
134
|
-
```
|
|
135
|
-
📦 Bundling for iOS...
|
|
136
|
-
✓ iOS bundle created
|
|
137
|
-
📦 Bundling for Android...
|
|
138
|
-
✓ Android bundle created
|
|
139
|
-
|
|
140
|
-
⬆ Uploading release...
|
|
141
|
-
App: app-970384d3
|
|
142
|
-
Deployment: 6933e683aa32fe18a1311bbb
|
|
143
|
-
Deployment Name: production
|
|
144
|
-
Label: v1.2.0
|
|
145
|
-
Platform: all
|
|
146
|
-
Bundle: ./dist/ios/index.ios.bundle
|
|
147
|
-
Assets: 24 file(s)
|
|
148
|
-
Rollout: 100%
|
|
149
|
-
Mandatory: No
|
|
150
|
-
|
|
151
|
-
📋 Step 1/3: Requesting upload URLs...
|
|
152
|
-
✓ Got 26 presigned URLs
|
|
153
|
-
📤 Step 2/3: Uploading files directly to storage...
|
|
154
|
-
[1/26] index.ios.bundle
|
|
155
|
-
...
|
|
156
|
-
✓ Uploaded 26 files
|
|
157
|
-
✅ Step 3/3: Confirming release...
|
|
158
|
-
|
|
159
|
-
✓ Release uploaded successfully!
|
|
160
|
-
──────────────────────────────────
|
|
161
|
-
ID: 693507a19f6d6a79267633e8
|
|
162
|
-
Label: v1.2.0
|
|
163
|
-
iOS Bundle: uploaded
|
|
164
|
-
Android Bundle: uploaded
|
|
165
|
-
Rollout: 100%
|
|
166
|
-
Mandatory: No
|
|
167
|
-
Status: active
|
|
168
|
-
──────────────────────────────────
|
|
152
|
+
# Capacitor release with custom build folder
|
|
153
|
+
upflux release --capacitor --web-dir build
|
|
169
154
|
```
|
|
170
155
|
|
|
171
156
|
---
|
|
172
157
|
|
|
173
|
-
##
|
|
174
|
-
|
|
175
|
-
The CLI automatically detects native code changes since your last release and warns you when a store update may be required. This helps prevent devices from receiving OTA updates that depend on native features not yet available in their installed binary.
|
|
176
|
-
|
|
177
|
-
### How It Works
|
|
158
|
+
## Auto-incrementing Build Numbers
|
|
178
159
|
|
|
179
|
-
|
|
180
|
-
2. On the next release, it runs `git diff <lastHash>..HEAD` against native files.
|
|
181
|
-
3. If changes are found, it warns you and offers to auto-set `--min-binary-version`.
|
|
160
|
+
When releasing without `--label`, the CLI reads `upflux.json` at your project root:
|
|
182
161
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|---|---|
|
|
189
|
-
| `android/app/build.gradle` | `versionName` bump, `minSdkVersion` change |
|
|
190
|
-
| `android/app/src/main/AndroidManifest.xml` | New permissions |
|
|
191
|
-
| `ios/Podfile` | New native pods |
|
|
192
|
-
| `ios/Podfile.lock` | Any pod version change |
|
|
193
|
-
| `package.json` | New native dependency packages |
|
|
194
|
-
|
|
195
|
-
### Example Interaction
|
|
162
|
+
1. Reads `runtimeVersion` (e.g., `"1.0.0"`) and current `buildNumber` (e.g., `0`)
|
|
163
|
+
2. Increments `buildNumber` by 1 (`1`)
|
|
164
|
+
3. Generates release label: `1.0.0+1`
|
|
165
|
+
4. Writes updated `buildNumber` back to `upflux.json`
|
|
166
|
+
5. Embeds updated `upflux.json` into the native assets directory
|
|
196
167
|
|
|
168
|
+
```json
|
|
169
|
+
{
|
|
170
|
+
"version": 1,
|
|
171
|
+
"app": {
|
|
172
|
+
"id": "app-970384d3",
|
|
173
|
+
"buildNumber": 1,
|
|
174
|
+
"runtimeVersion": "1.0.0"
|
|
175
|
+
},
|
|
176
|
+
"deployments": { ... }
|
|
177
|
+
}
|
|
197
178
|
```
|
|
198
|
-
⚠️ Native changes detected since last release:
|
|
199
179
|
|
|
200
|
-
|
|
201
|
-
• build.gradle: versionName → 2.0.0
|
|
202
|
-
• AndroidManifest.xml: New permission: android.permission.CAMERA
|
|
180
|
+
> 💡 **Best Practice:** Commit `upflux.json` to git after running `upflux release` so the build counter is synchronized across your team and CI/CD pipelines.
|
|
203
181
|
|
|
204
|
-
|
|
205
|
-
--min-binary-version 2.0.0
|
|
206
|
-
--version-range ">=2.0.0"
|
|
182
|
+
---
|
|
207
183
|
|
|
208
|
-
|
|
209
|
-
❯ Auto-apply suggested flags (--min-binary-version 2.0.0 --version-range ">=2.0.0")
|
|
210
|
-
Enter min-binary-version manually
|
|
211
|
-
Continue without (not recommended for native changes)
|
|
212
|
-
```
|
|
184
|
+
## Native Change Detection
|
|
213
185
|
|
|
214
|
-
|
|
186
|
+
The CLI automatically inspects native changes since your last release to prevent pushing OTA updates that depend on unreleased native code.
|
|
215
187
|
|
|
216
|
-
|
|
217
|
-
# Require devices to have at least v2.0.0 binary before receiving this OTA
|
|
218
|
-
upflux release --label v2.0.0-ota --min-binary-version 2.0.0 --version-range ">=2.0.0"
|
|
219
|
-
```
|
|
188
|
+
### Files Monitored
|
|
220
189
|
|
|
221
|
-
|
|
190
|
+
| File | Monitored Changes |
|
|
191
|
+
|---|---|
|
|
192
|
+
| `android/app/build.gradle` | `versionName` changes, `minSdkVersion` bumps |
|
|
193
|
+
| `android/app/src/main/AndroidManifest.xml` | Added/removed Android permissions |
|
|
194
|
+
| `ios/Podfile` | Added native CocoaPods |
|
|
195
|
+
| `ios/Podfile.lock` | Updated CocoaPod versions |
|
|
196
|
+
| `package.json` | Newly added native dependencies |
|
|
222
197
|
|
|
223
|
-
|
|
224
|
-
# In CI, skip interactive detection and pass flag explicitly
|
|
225
|
-
upflux release --label v2.0.0 --min-binary-version 2.0.0 --skip-native-check
|
|
226
|
-
```
|
|
198
|
+
If changes are detected, the CLI prompts you to automatically set `--min-binary-version`. In CI/CD environments, use `--skip-native-check` or specify `--min-binary-version` directly.
|
|
227
199
|
|
|
228
200
|
---
|
|
229
201
|
|
|
230
202
|
### `status`
|
|
231
203
|
|
|
232
|
-
|
|
204
|
+
View deployment status, active release, rollout percentage, and recent releases.
|
|
233
205
|
|
|
234
206
|
```bash
|
|
235
207
|
upflux status [options]
|
|
@@ -237,34 +209,26 @@ upflux status [options]
|
|
|
237
209
|
|
|
238
210
|
| Option | Description |
|
|
239
211
|
|--------|-------------|
|
|
240
|
-
| `-n, --limit <number>` | Number of releases to
|
|
212
|
+
| `-n, --limit <number>` | Number of recent releases to display (default: 5) |
|
|
241
213
|
|
|
242
|
-
**Example
|
|
214
|
+
**Example:**
|
|
243
215
|
```
|
|
244
216
|
⚡ Fetching deployment status...
|
|
245
217
|
|
|
246
218
|
╭────────────────────────────────────────────────╮
|
|
247
219
|
│ 📱 app-970384d3 → production │
|
|
248
220
|
│ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │
|
|
249
|
-
│ Current Release:
|
|
221
|
+
│ Current Release: 1.0.0+4 (iOS & Android) │
|
|
250
222
|
│ Status: ● active • 100% rollout │
|
|
251
|
-
│ Published:
|
|
223
|
+
│ Published: 15m ago │
|
|
252
224
|
╰────────────────────────────────────────────────╯
|
|
253
|
-
|
|
254
|
-
📦 Recent Releases (15 total)
|
|
255
|
-
|
|
256
|
-
Label Platform Status Rollout Published
|
|
257
|
-
────────────────────────────────────────────────────────
|
|
258
|
-
v1.2.0 all ● active 100% 2h ago
|
|
259
|
-
v1.1.0 all ○ expired 100% 3d ago
|
|
260
|
-
v1.0.0 ios ○ expired 100% 1w ago
|
|
261
225
|
```
|
|
262
226
|
|
|
263
227
|
---
|
|
264
228
|
|
|
265
229
|
### `generate-manifest`
|
|
266
230
|
|
|
267
|
-
Fetch and display the manifest for a specific release.
|
|
231
|
+
Fetch and display or export the update manifest for a specific release ID.
|
|
268
232
|
|
|
269
233
|
```bash
|
|
270
234
|
upflux generate-manifest [options]
|
|
@@ -273,51 +237,7 @@ upflux generate-manifest [options]
|
|
|
273
237
|
| Option | Required | Description |
|
|
274
238
|
|--------|----------|-------------|
|
|
275
239
|
| `-r, --release-id <id>` | ✓ | Release ID (MongoDB ObjectId) |
|
|
276
|
-
| `-o, --output <path>` | | Save manifest to file |
|
|
277
|
-
|
|
278
|
-
**Example:**
|
|
279
|
-
```bash
|
|
280
|
-
# Print manifest to stdout
|
|
281
|
-
upflux generate-manifest --release-id 693507a19f6d6a79267633e8
|
|
282
|
-
|
|
283
|
-
# Save to file
|
|
284
|
-
upflux generate-manifest --release-id 693507a19f6d6a79267633e8 --output manifest.json
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
---
|
|
288
|
-
|
|
289
|
-
## Scheduled Releases
|
|
290
|
-
|
|
291
|
-
Schedule releases to go live at a specific date and time. Perfect for coordinating updates with marketing campaigns, feature launches, or maintenance windows.
|
|
292
|
-
|
|
293
|
-
### How It Works
|
|
294
|
-
|
|
295
|
-
1. Create a release with the `--schedule` flag
|
|
296
|
-
2. The release is uploaded as a **Draft**
|
|
297
|
-
3. Set the scheduled time in the Upflux Dashboard
|
|
298
|
-
4. The release automatically goes live at the scheduled time
|
|
299
|
-
|
|
300
|
-
### Creating a Scheduled Release
|
|
301
|
-
|
|
302
|
-
```bash
|
|
303
|
-
# Create a draft release for scheduling
|
|
304
|
-
upflux release --label v2.0.0 --schedule
|
|
305
|
-
|
|
306
|
-
# Output:
|
|
307
|
-
# ✓ Release uploaded successfully!
|
|
308
|
-
# ...
|
|
309
|
-
# Status: DRAFT
|
|
310
|
-
# 📅 Set schedule time in dashboard
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
### Use Cases
|
|
314
|
-
|
|
315
|
-
- **Feature launches** - Coordinate with marketing announcements
|
|
316
|
-
- **Global releases** - Release at optimal times for different regions
|
|
317
|
-
- **Maintenance windows** - Deploy during low-traffic periods
|
|
318
|
-
- **Campaign coordination** - Sync with promotional events
|
|
319
|
-
|
|
320
|
-
> 💡 **Tip:** Combine scheduled releases with rollout percentages for safer deployments. For example, schedule a 10% rollout first, then manually increase after monitoring.
|
|
240
|
+
| `-o, --output <path>` | | Save manifest JSON to file |
|
|
321
241
|
|
|
322
242
|
---
|
|
323
243
|
|
|
@@ -327,67 +247,16 @@ upflux release --label v2.0.0 --schedule
|
|
|
327
247
|
|
|
328
248
|
| Variable | Description | Default |
|
|
329
249
|
|----------|-------------|---------|
|
|
330
|
-
| `UPFLUX_API_URL` | API server URL | `https://api.upflux.in/api` |
|
|
331
|
-
|
|
332
|
-
### Auth File
|
|
333
|
-
|
|
334
|
-
The CLI stores credentials in `.upflux` in the current directory:
|
|
335
|
-
|
|
336
|
-
```json
|
|
337
|
-
{
|
|
338
|
-
"credentials": [
|
|
339
|
-
{
|
|
340
|
-
"key": "upflux_pub_xxx...",
|
|
341
|
-
"appId": "app-970384d3",
|
|
342
|
-
"deploymentId": "6933e683aa32fe18a1311bbb",
|
|
343
|
-
"deploymentName": "production"
|
|
344
|
-
},
|
|
345
|
-
{
|
|
346
|
-
"key": "upflux_pub_yyy...",
|
|
347
|
-
"appId": "app-970384d3",
|
|
348
|
-
"deploymentId": "6933e683aa32fe18a1311ccc",
|
|
349
|
-
"deploymentName": "staging"
|
|
350
|
-
}
|
|
351
|
-
],
|
|
352
|
-
"activeIndex": 0,
|
|
353
|
-
"lastReleaseHash": "a3f8c12d...",
|
|
354
|
-
"lastReleaseLabel": "v1.5.0"
|
|
355
|
-
}
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
> ⚠️ **Important:** Never commit the `.upflux` file to version control. It contains your publish keys. Add it to your `.gitignore`.
|
|
250
|
+
| `UPFLUX_API_URL` | Upflux API server URL | `https://api.upflux.in/api` |
|
|
359
251
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
## Publish Keys
|
|
363
|
-
|
|
364
|
-
Publish keys are used to authenticate the CLI and can be found in the Upflux dashboard under **Settings → Keys**.
|
|
252
|
+
### Auth Storage (`.upflux`)
|
|
365
253
|
|
|
366
|
-
|
|
254
|
+
Stored credentials and release metadata are saved in `.upflux` in the current project directory.
|
|
367
255
|
|
|
368
|
-
|
|
256
|
+
> ⚠️ **Important:** Add `.upflux` to your `.gitignore`. It contains your publish keys (`upx_pub_*`).
|
|
369
257
|
|
|
370
258
|
---
|
|
371
259
|
|
|
372
|
-
## Development
|
|
373
|
-
|
|
374
|
-
```bash
|
|
375
|
-
# Install dependencies
|
|
376
|
-
pnpm install
|
|
377
|
-
|
|
378
|
-
# Build
|
|
379
|
-
pnpm run build
|
|
380
|
-
|
|
381
|
-
# Run locally
|
|
382
|
-
node dist/index.js --help
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
## Requirements
|
|
386
|
-
|
|
387
|
-
- Node.js >= 18.0.0
|
|
388
|
-
- For React Native projects: `react-native` CLI installed
|
|
389
|
-
- For Capacitor projects: Built web assets in configured `webDir`
|
|
390
|
-
|
|
391
260
|
## License
|
|
392
261
|
|
|
393
262
|
MIT
|
|
@@ -0,0 +1,149 @@
|
|
|
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
|
+
const commander_1 = require("commander");
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
11
|
+
const UPFLUX_JSON_FILE = path_1.default.join(process.cwd(), "upflux.json");
|
|
12
|
+
const DEFAULT_SERVER_URL = "https://api.upflux.in";
|
|
13
|
+
/**
|
|
14
|
+
* Build the upflux.json content from collected answers
|
|
15
|
+
*/
|
|
16
|
+
function buildUpfluxJson(appId, serverUrl, runtimeVersion, profiles) {
|
|
17
|
+
const deployments = {};
|
|
18
|
+
for (const profile of profiles) {
|
|
19
|
+
const entry = {
|
|
20
|
+
clientKey: profile.clientKey,
|
|
21
|
+
};
|
|
22
|
+
if (profile.extendsProfile) {
|
|
23
|
+
entry.extends = profile.extendsProfile;
|
|
24
|
+
}
|
|
25
|
+
// Set sensible defaults per profile name
|
|
26
|
+
if (profile.name === "development") {
|
|
27
|
+
entry.checkOnLaunch = "always";
|
|
28
|
+
entry.installMode = "on_next_restart";
|
|
29
|
+
}
|
|
30
|
+
else if (profile.name === "production") {
|
|
31
|
+
entry.checkOnLaunch = "always";
|
|
32
|
+
entry.installMode = "immediate";
|
|
33
|
+
}
|
|
34
|
+
deployments[profile.name] = entry;
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
version: 1,
|
|
38
|
+
app: Object.assign({ id: appId, buildNumber: 0, runtimeVersion }, (serverUrl !== DEFAULT_SERVER_URL ? { serverUrl } : {})),
|
|
39
|
+
deployments,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const init = new commander_1.Command("init")
|
|
43
|
+
.description("Scaffold upflux.json in your project root")
|
|
44
|
+
.option("--force", "Overwrite existing upflux.json")
|
|
45
|
+
.action(async (opts) => {
|
|
46
|
+
console.log(chalk_1.default.bold("\n🚀 Upflux Project Setup\n"));
|
|
47
|
+
// Check if upflux.json already exists
|
|
48
|
+
if (fs_1.default.existsSync(UPFLUX_JSON_FILE) && !opts.force) {
|
|
49
|
+
console.log(chalk_1.default.yellow("⚠️ upflux.json already exists."));
|
|
50
|
+
const { overwrite } = await inquirer_1.default.prompt([
|
|
51
|
+
{
|
|
52
|
+
type: "confirm",
|
|
53
|
+
name: "overwrite",
|
|
54
|
+
message: "Overwrite it?",
|
|
55
|
+
default: false,
|
|
56
|
+
},
|
|
57
|
+
]);
|
|
58
|
+
if (!overwrite) {
|
|
59
|
+
console.log(chalk_1.default.gray("Aborted."));
|
|
60
|
+
process.exit(0);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Step 1: App ID
|
|
64
|
+
const { appId } = await inquirer_1.default.prompt([
|
|
65
|
+
{
|
|
66
|
+
type: "input",
|
|
67
|
+
name: "appId",
|
|
68
|
+
message: "App ID:",
|
|
69
|
+
validate: (val) => val.trim() ? true : "App ID is required",
|
|
70
|
+
},
|
|
71
|
+
]);
|
|
72
|
+
// Step 2: Server URL
|
|
73
|
+
const { serverUrl } = await inquirer_1.default.prompt([
|
|
74
|
+
{
|
|
75
|
+
type: "input",
|
|
76
|
+
name: "serverUrl",
|
|
77
|
+
message: `Server URL (press Enter for ${DEFAULT_SERVER_URL}):`,
|
|
78
|
+
default: DEFAULT_SERVER_URL,
|
|
79
|
+
},
|
|
80
|
+
]);
|
|
81
|
+
// Step 3: Runtime version (semver, used to form auto release labels)
|
|
82
|
+
const { runtimeVersion } = await inquirer_1.default.prompt([
|
|
83
|
+
{
|
|
84
|
+
type: "input",
|
|
85
|
+
name: "runtimeVersion",
|
|
86
|
+
message: "Runtime version (e.g. 1.0.0 — update when shipping a new binary):",
|
|
87
|
+
default: "1.0.0",
|
|
88
|
+
validate: (val) => {
|
|
89
|
+
if (!val.trim())
|
|
90
|
+
return "Runtime version is required";
|
|
91
|
+
if (!/^\d+\.\d+\.\d+/.test(val.trim()))
|
|
92
|
+
return "Use semver format, e.g. 1.0.0";
|
|
93
|
+
return true;
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
]);
|
|
97
|
+
const { selectedProfiles } = await inquirer_1.default.prompt([
|
|
98
|
+
{
|
|
99
|
+
type: "checkbox",
|
|
100
|
+
name: "selectedProfiles",
|
|
101
|
+
message: "Deployment profiles to create:",
|
|
102
|
+
choices: [
|
|
103
|
+
{ name: "production", checked: true },
|
|
104
|
+
{ name: "staging", checked: true },
|
|
105
|
+
{ name: "development", checked: true },
|
|
106
|
+
],
|
|
107
|
+
validate: (selected) => selected.length > 0 ? true : "Select at least one profile",
|
|
108
|
+
},
|
|
109
|
+
]);
|
|
110
|
+
// Step 4: Client keys per profile
|
|
111
|
+
const profiles = [];
|
|
112
|
+
for (const profileName of selectedProfiles) {
|
|
113
|
+
const { clientKey } = await inquirer_1.default.prompt([
|
|
114
|
+
{
|
|
115
|
+
type: "input",
|
|
116
|
+
name: "clientKey",
|
|
117
|
+
message: `Client key for "${chalk_1.default.cyan(profileName)}" ${chalk_1.default.gray("(upx_cli_xxxxx)")}:`,
|
|
118
|
+
validate: (val) => {
|
|
119
|
+
if (!val.trim())
|
|
120
|
+
return "Client key is required";
|
|
121
|
+
if (val.trim().length < 10)
|
|
122
|
+
return "Client key looks too short";
|
|
123
|
+
return true;
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
]);
|
|
127
|
+
profiles.push({ name: profileName, clientKey: clientKey.trim() });
|
|
128
|
+
}
|
|
129
|
+
// Build and write upflux.json
|
|
130
|
+
const content = buildUpfluxJson(appId.trim(), serverUrl.trim(), runtimeVersion.trim(), profiles);
|
|
131
|
+
fs_1.default.writeFileSync(UPFLUX_JSON_FILE, JSON.stringify(content, null, 2));
|
|
132
|
+
console.log(chalk_1.default.green("\n✓ Created upflux.json\n"));
|
|
133
|
+
// Show what was created
|
|
134
|
+
console.log(chalk_1.default.gray("Preview:"));
|
|
135
|
+
console.log(chalk_1.default.gray(JSON.stringify(content, null, 2)));
|
|
136
|
+
// Usage hint
|
|
137
|
+
console.log(chalk_1.default.bold("\n📦 SDK Usage:\n"));
|
|
138
|
+
console.log(chalk_1.default.white(` import { Upflux } from '@upfluxhq/react-native';\n\n` +
|
|
139
|
+
` // Auto-selects 'development' in dev, 'production' in release\n` +
|
|
140
|
+
` // Auto-increments buildNumber on every release\n` +
|
|
141
|
+
` await Upflux.init();\n\n` +
|
|
142
|
+
` // Or specify a profile:\n` +
|
|
143
|
+
` await Upflux.init('production');`));
|
|
144
|
+
// Security note about committing the file
|
|
145
|
+
console.log(chalk_1.default.cyan("\n💡 Tip: upflux.json is safe to commit to git.\n" +
|
|
146
|
+
" upx_cli_* keys are read-only — they cannot publish releases.\n" +
|
|
147
|
+
" Only upx_pub_* publish keys should be kept secret.\n"));
|
|
148
|
+
});
|
|
149
|
+
exports.default = init;
|
package/dist/commands/release.js
CHANGED
|
@@ -135,11 +135,41 @@ function isValidAppId(appId) {
|
|
|
135
135
|
return /^[a-zA-Z0-9-_]+$/.test(appId) && appId.length >= 3;
|
|
136
136
|
}
|
|
137
137
|
/**
|
|
138
|
-
* Validate release label format (semver-like)
|
|
138
|
+
* Validate release label format (semver-like, allows + build metadata)
|
|
139
139
|
*/
|
|
140
140
|
function isValidReleaseLabel(label) {
|
|
141
|
-
// Allow v1.0.0, 1.0.0, v1.0.0-beta, etc.
|
|
142
|
-
return /^v?\d+\.\d+\.\d+(-[a-zA-Z0-9._-]+)?$/.test(label);
|
|
141
|
+
// Allow v1.0.0, 1.0.0, v1.0.0-beta, 1.0.0+5, 1.0.0-beta+5, etc.
|
|
142
|
+
return /^v?\d+\.\d+\.\d+(-[a-zA-Z0-9._-]+)?(\+[a-zA-Z0-9._-]+)?$/.test(label);
|
|
143
|
+
}
|
|
144
|
+
/** Read upflux.json from project root. Returns null if not found. */
|
|
145
|
+
function readRootUpfluxJson() {
|
|
146
|
+
const filePath = path.resolve('upflux.json');
|
|
147
|
+
if (!fs.existsSync(filePath))
|
|
148
|
+
return null;
|
|
149
|
+
try {
|
|
150
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
151
|
+
}
|
|
152
|
+
catch (_a) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/** Increment app.buildNumber, write back to upflux.json, return new value. */
|
|
157
|
+
function incrementBuildNumber(json) {
|
|
158
|
+
var _a;
|
|
159
|
+
const next = ((_a = json.app.buildNumber) !== null && _a !== void 0 ? _a : 0) + 1;
|
|
160
|
+
json.app.buildNumber = next;
|
|
161
|
+
fs.writeFileSync(path.resolve('upflux.json'), JSON.stringify(json, null, 2));
|
|
162
|
+
return next;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Generate an auto release label.
|
|
166
|
+
* With runtimeVersion: "1.0.0+6" (semver + build counter)
|
|
167
|
+
* Without: "v0.0.6" (bare semver fallback — passes validator)
|
|
168
|
+
*/
|
|
169
|
+
function generateReleaseLabel(buildNumber, runtimeVersion) {
|
|
170
|
+
return runtimeVersion
|
|
171
|
+
? `${runtimeVersion}+${buildNumber}`
|
|
172
|
+
: `v0.0.${buildNumber}`;
|
|
143
173
|
}
|
|
144
174
|
/**
|
|
145
175
|
* Validate version range format
|
|
@@ -256,28 +286,25 @@ function collectAssets(dir) {
|
|
|
256
286
|
return assets;
|
|
257
287
|
}
|
|
258
288
|
/**
|
|
259
|
-
* Write upflux.json config file to the bundle output directory
|
|
289
|
+
* Write upflux.json config file to the bundle output directory.
|
|
260
290
|
*
|
|
261
291
|
* This file embeds the OTA version into the app bundle at build time.
|
|
262
|
-
*
|
|
263
|
-
*
|
|
264
|
-
*
|
|
265
|
-
* @param outputDir - Directory to write upflux.json to
|
|
266
|
-
* @param releaseLabel - The OTA version (e.g., "v1.0.0")
|
|
267
|
-
* @param appId - The app ID
|
|
292
|
+
* `releaseLabel` is used by the SDK for identity check (am I running the latest?).
|
|
293
|
+
* `buildNumber` is stored as metadata for display/debugging.
|
|
268
294
|
*/
|
|
269
|
-
function writeUpfluxConfig(outputDir, releaseLabel, appId) {
|
|
295
|
+
function writeUpfluxConfig(outputDir, releaseLabel, appId, buildNumber) {
|
|
270
296
|
const config = {
|
|
271
297
|
releaseLabel,
|
|
272
298
|
appId,
|
|
273
299
|
createdAt: new Date().toISOString(),
|
|
274
300
|
};
|
|
301
|
+
if (buildNumber !== undefined) {
|
|
302
|
+
config.buildNumber = buildNumber;
|
|
303
|
+
}
|
|
275
304
|
const configContent = JSON.stringify(config, null, 2);
|
|
276
305
|
const configPath = path.join(outputDir, "upflux.json");
|
|
277
306
|
fs.writeFileSync(configPath, configContent);
|
|
278
|
-
console.log(chalk_1.default.gray(` Created upflux.json
|
|
279
|
-
// Also copy to native asset directories so the SDK can read the
|
|
280
|
-
// embedded version at runtime and skip unnecessary OTA downloads
|
|
307
|
+
console.log(chalk_1.default.gray(` Created upflux.json (label: ${releaseLabel}${buildNumber !== undefined ? `, build: ${buildNumber}` : ''})`));
|
|
281
308
|
copyUpfluxConfigToNativeAssets(configContent);
|
|
282
309
|
}
|
|
283
310
|
/**
|
|
@@ -317,7 +344,7 @@ const release = new commander_1.Command("release")
|
|
|
317
344
|
.description("Bundle and upload a new release to Upflux")
|
|
318
345
|
.option("-a, --app <appId>", "Application ID (uses stored value if not provided)")
|
|
319
346
|
.option("-d, --deployment <deploymentId>", "Deployment ID (uses stored value if not provided)")
|
|
320
|
-
.
|
|
347
|
+
.option("-l, --label <label>", "Release label (e.g., v1.0.0) — omit to auto-increment buildNumber from upflux.json")
|
|
321
348
|
.option("--platform <platform>", "Target platform for the release: all, ios, or android (defaults to all)", "all")
|
|
322
349
|
.option("-e, --entry-file <path>", "Entry file for bundler", DEFAULT_ENTRY_FILE)
|
|
323
350
|
.option("-o, --output-dir <path>", "Output directory for bundle", DEFAULT_OUTPUT_DIR)
|
|
@@ -405,11 +432,41 @@ const release = new commander_1.Command("release")
|
|
|
405
432
|
console.error(chalk_1.default.gray("Deployment ID should be a 24-character MongoDB ObjectId"));
|
|
406
433
|
process.exit(1);
|
|
407
434
|
}
|
|
408
|
-
//
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
435
|
+
// ── Label Resolution ─────────────────────────────────────────────
|
|
436
|
+
// Two paths: manual (--label provided) or auto (buildNumber from upflux.json)
|
|
437
|
+
let resolvedLabel;
|
|
438
|
+
const rootJson = readRootUpfluxJson();
|
|
439
|
+
const currentBuildNumber = rootJson === null || rootJson === void 0 ? void 0 : rootJson.app.buildNumber;
|
|
440
|
+
if (opts.label) {
|
|
441
|
+
// Manual mode: validate semver (now allows + notation), still increment buildNumber for tracking
|
|
442
|
+
if (!isValidReleaseLabel(opts.label)) {
|
|
443
|
+
console.error(chalk_1.default.red("✗ Invalid release label format"));
|
|
444
|
+
console.error(chalk_1.default.gray("Use semantic versioning: v1.0.0, 1.0.0-beta, 1.0.0+5, etc."));
|
|
445
|
+
process.exit(1);
|
|
446
|
+
}
|
|
447
|
+
resolvedLabel = opts.label;
|
|
448
|
+
if (rootJson && currentBuildNumber !== undefined) {
|
|
449
|
+
const tracked = incrementBuildNumber(rootJson);
|
|
450
|
+
console.log(chalk_1.default.gray(` buildNumber → ${tracked} (tracking)`));
|
|
451
|
+
}
|
|
452
|
+
console.log(chalk_1.default.gray(` Label: ${resolvedLabel} (manual)`));
|
|
453
|
+
}
|
|
454
|
+
else {
|
|
455
|
+
// Auto mode: require upflux.json with buildNumber field
|
|
456
|
+
if (!rootJson) {
|
|
457
|
+
console.error(chalk_1.default.red("✗ No upflux.json found and no --label provided"));
|
|
458
|
+
console.error(chalk_1.default.gray("Run: upflux init OR upflux release --label v1.0.0"));
|
|
459
|
+
process.exit(1);
|
|
460
|
+
}
|
|
461
|
+
if (rootJson.app.buildNumber === undefined) {
|
|
462
|
+
console.error(chalk_1.default.red("✗ upflux.json is missing app.buildNumber"));
|
|
463
|
+
console.error(chalk_1.default.gray('Add "buildNumber": 0 to the app section, or use --label'));
|
|
464
|
+
process.exit(1);
|
|
465
|
+
}
|
|
466
|
+
const nextBuild = incrementBuildNumber(rootJson);
|
|
467
|
+
resolvedLabel = generateReleaseLabel(nextBuild, rootJson.app.runtimeVersion);
|
|
468
|
+
console.log(chalk_1.default.green(` ✓ buildNumber: ${nextBuild - 1} → ${nextBuild}`));
|
|
469
|
+
console.log(chalk_1.default.gray(` Label: ${resolvedLabel} (auto)`));
|
|
413
470
|
}
|
|
414
471
|
// Validation 6: Rollout percentage
|
|
415
472
|
const rolloutValidation = isValidRollout(opts.rollout);
|
|
@@ -467,10 +524,10 @@ const release = new commander_1.Command("release")
|
|
|
467
524
|
}
|
|
468
525
|
// Write upflux.json to web directory BEFORE zipping
|
|
469
526
|
// This embeds the OTA version into the Capacitor app bundle
|
|
470
|
-
writeUpfluxConfig(webDirPath,
|
|
527
|
+
writeUpfluxConfig(webDirPath, resolvedLabel, appId, rootJson === null || rootJson === void 0 ? void 0 : rootJson.app.buildNumber);
|
|
471
528
|
// Zip the web directory
|
|
472
529
|
console.log(chalk_1.default.blue(`📦 Zipping ${webDir}/ directory...`));
|
|
473
|
-
const zipPath = path.join(outputDir, `bundle-${
|
|
530
|
+
const zipPath = path.join(outputDir, `bundle-${resolvedLabel}.zip`);
|
|
474
531
|
bundlePath = await zipDirectory(webDirPath, zipPath);
|
|
475
532
|
console.log(chalk_1.default.green(`✓ Bundle created: ${bundlePath}`));
|
|
476
533
|
// No separate assets for Capacitor - all in zip
|
|
@@ -572,8 +629,8 @@ const release = new commander_1.Command("release")
|
|
|
572
629
|
: collectAssets(androidAssetsPath);
|
|
573
630
|
// Write upflux.json to BOTH platform output directories
|
|
574
631
|
// React Native reads this from bundled assets to know embedded OTA version
|
|
575
|
-
writeUpfluxConfig(iosOutputDir,
|
|
576
|
-
writeUpfluxConfig(androidOutputDir,
|
|
632
|
+
writeUpfluxConfig(iosOutputDir, resolvedLabel, appId, rootJson === null || rootJson === void 0 ? void 0 : rootJson.app.buildNumber);
|
|
633
|
+
writeUpfluxConfig(androidOutputDir, resolvedLabel, appId, rootJson === null || rootJson === void 0 ? void 0 : rootJson.app.buildNumber);
|
|
577
634
|
// Set bundlePath and assetFiles for display (use iOS as primary for logging)
|
|
578
635
|
bundlePath = iosBundlePath;
|
|
579
636
|
assetFiles = [...iosAssetFiles, ...androidAssetFiles];
|
|
@@ -618,7 +675,7 @@ const release = new commander_1.Command("release")
|
|
|
618
675
|
}
|
|
619
676
|
// Write upflux.json to output directory
|
|
620
677
|
// React Native reads this from bundled assets to know embedded OTA version
|
|
621
|
-
writeUpfluxConfig(outputDir,
|
|
678
|
+
writeUpfluxConfig(outputDir, resolvedLabel, appId, rootJson === null || rootJson === void 0 ? void 0 : rootJson.app.buildNumber);
|
|
622
679
|
}
|
|
623
680
|
}
|
|
624
681
|
// ========================================
|
|
@@ -702,7 +759,7 @@ const release = new commander_1.Command("release")
|
|
|
702
759
|
console.log(` App: ${appId}`);
|
|
703
760
|
console.log(` Deployment: ${deploymentId}`);
|
|
704
761
|
console.log(` Deployment Name: ${deploymentName}`);
|
|
705
|
-
console.log(` Label: ${
|
|
762
|
+
console.log(` Label: ${resolvedLabel}`);
|
|
706
763
|
console.log(` Platform: ${platform}`);
|
|
707
764
|
console.log(` Bundle: ${bundlePath}`);
|
|
708
765
|
console.log(` Assets: ${assetFiles.length} file(s)`);
|
|
@@ -734,7 +791,7 @@ const release = new commander_1.Command("release")
|
|
|
734
791
|
const initResponse = await apiClient_1.apiClient.post("/cli/releases/upload/init", {
|
|
735
792
|
appId,
|
|
736
793
|
deploymentId,
|
|
737
|
-
releaseLabel:
|
|
794
|
+
releaseLabel: resolvedLabel,
|
|
738
795
|
platform,
|
|
739
796
|
files: fileManifest.map(f => ({
|
|
740
797
|
type: f.type,
|
|
@@ -781,7 +838,7 @@ const release = new commander_1.Command("release")
|
|
|
781
838
|
}
|
|
782
839
|
}
|
|
783
840
|
// Step 3: Complete upload and create release record
|
|
784
|
-
const completeResponse = await apiClient_1.apiClient.post("/cli/releases/upload/complete", Object.assign(Object.assign({ uploadId: initResponse.data.uploadId, releaseLabel:
|
|
841
|
+
const completeResponse = await apiClient_1.apiClient.post("/cli/releases/upload/complete", Object.assign(Object.assign({ uploadId: initResponse.data.uploadId, releaseLabel: resolvedLabel, mandatory: opts.mandatory, rolloutPercentage: rolloutValidation.value, binaryVersionRange: opts.versionRange }, (opts.minBinaryVersion ? { minBinaryVersion: opts.minBinaryVersion } : {})), { platform, isDraft: opts.schedule,
|
|
785
842
|
// Include bundle sizes
|
|
786
843
|
iosBundleSize: bundleSizes.ios, androidBundleSize: bundleSizes.android || bundleSizes.single }), {
|
|
787
844
|
headers: {
|
|
@@ -824,7 +881,7 @@ const release = new commander_1.Command("release")
|
|
|
824
881
|
// Save git hash after successful release for next detection run
|
|
825
882
|
const gitStatus = (0, native_detector_1.getGitRepoStatus)();
|
|
826
883
|
if (gitStatus) {
|
|
827
|
-
configStore_1.configStore.saveLastReleaseHash(gitStatus.currentHash,
|
|
884
|
+
configStore_1.configStore.saveLastReleaseHash(gitStatus.currentHash, resolvedLabel);
|
|
828
885
|
console.log(chalk_1.default.gray(` ⓘ Saved git snapshot for next release detection`));
|
|
829
886
|
}
|
|
830
887
|
}
|
package/dist/index.js
CHANGED
|
@@ -10,11 +10,13 @@ const logout_1 = __importDefault(require("./commands/logout"));
|
|
|
10
10
|
const release_1 = __importDefault(require("./commands/release"));
|
|
11
11
|
const status_1 = __importDefault(require("./commands/status"));
|
|
12
12
|
const generate_manifest_1 = __importDefault(require("./commands/generate-manifest"));
|
|
13
|
+
const init_1 = __importDefault(require("./commands/init"));
|
|
13
14
|
const program = new commander_1.Command();
|
|
14
15
|
program
|
|
15
16
|
.name("upflux")
|
|
16
17
|
.description("Upflux CLI for OTA updates")
|
|
17
18
|
.version("1.0.0");
|
|
19
|
+
program.addCommand(init_1.default);
|
|
18
20
|
program.addCommand(login_1.default);
|
|
19
21
|
program.addCommand(logout_1.default);
|
|
20
22
|
program.addCommand(release_1.default);
|