@expo-up/cli 0.1.0 → 0.1.1

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 ADDED
@@ -0,0 +1,9 @@
1
+ # @expo-up/cli
2
+
3
+ ## 0.1.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 7115c93: chore: patch release across core, server, and cli
8
+ - Updated dependencies [7115c93]
9
+ - @expo-up/core@0.1.1
package/README.md ADDED
@@ -0,0 +1,161 @@
1
+ # @expo-up/cli
2
+
3
+ CLI package for managing self-hosted Expo OTA workflows.
4
+
5
+ > Current storage target is GitHub Repository storage.
6
+ > Additional providers (AWS S3, Firebase Storage, Google Cloud Storage, Azure Blob Storage, etc.) are planned.
7
+
8
+ ## Responsibilities
9
+
10
+ - Authenticate against GitHub for storage access.
11
+ - Export and release update bundles to storage.
12
+ - Inspect and manage build history.
13
+ - Roll back channels to embedded/previous builds.
14
+ - Bootstrap Expo code signing (generate/configure).
15
+
16
+ ## Global Option
17
+
18
+ - `--debug`: enable verbose logs for API calls, release diffing, and error context.
19
+
20
+ ## Command Reference
21
+
22
+ ### `expo-up login`
23
+
24
+ Authenticate and store local token/config for subsequent commands.
25
+
26
+ ### `expo-up logout`
27
+
28
+ Clear locally stored token/config session.
29
+
30
+ ### `expo-up whoami`
31
+
32
+ Print resolved project context:
33
+ - projectId from Expo config
34
+ - active channel
35
+ - server URL
36
+ - auth state (masked token)
37
+
38
+ ### `expo-up set-channel <name>`
39
+
40
+ Persist default channel used by release/history/rollback when `--channel` is not passed.
41
+ Default channel is `main`.
42
+
43
+ Example:
44
+
45
+ ```bash
46
+ expo-up set-channel main
47
+ expo-up set-channel staging
48
+ ```
49
+
50
+ ### `expo-up list-channels`
51
+
52
+ List available channels from the storage repository.
53
+
54
+ ### `expo-up release`
55
+
56
+ Build and upload a new OTA build for a channel/runtime.
57
+
58
+ Options:
59
+ - `--platform <ios|android|all>` default: `all`
60
+ - `--channel <name>` optional channel override
61
+ - channel defaults to `main` when no saved/override channel is provided
62
+
63
+ Behavior:
64
+ 1. Runs `expo export`.
65
+ 2. Reads local `dist/metadata.json`.
66
+ 3. Compares sorted metadata hash against latest remote build in the channel.
67
+ 4. Skips upload if no changes.
68
+ 5. Uploads new build and advances channel ref if changed.
69
+
70
+ Examples:
71
+
72
+ ```bash
73
+ expo-up release --platform all --channel main
74
+ expo-up --debug release --platform ios --channel feat/new-home
75
+ ```
76
+
77
+ ### `expo-up history`
78
+
79
+ Show release/rollback timeline for a channel.
80
+
81
+ Options:
82
+ - `--channel <name>` optional channel override
83
+ - `--delete <buildIds...>` non-interactive delete mode (CI friendly)
84
+ - `--yes` skip confirmation for delete mode
85
+ - `--no-interactive-delete` disable TUI selection mode
86
+ - channel defaults to `main` when no saved/override channel is provided
87
+
88
+ Examples:
89
+
90
+ ```bash
91
+ expo-up history --channel main
92
+ expo-up history --channel main --delete 10 11 --yes
93
+ ```
94
+
95
+ ### `expo-up rollback`
96
+
97
+ Rollback channel to previous build or embedded app update.
98
+
99
+ Options:
100
+ - `--channel <name>` optional channel override
101
+ - `--to <buildId>` rollback target build
102
+ - `--embedded` rollback to embedded/native update
103
+ - channel defaults to `main` when no saved/override channel is provided
104
+
105
+ Examples:
106
+
107
+ ```bash
108
+ expo-up rollback --channel main --to 10
109
+ expo-up rollback --channel main --embedded
110
+ ```
111
+
112
+ ### `expo-up codesigning:generate`
113
+
114
+ Generate keypair/certificate and update Expo config for signed updates.
115
+
116
+ Key options:
117
+ - `--organization <name>`
118
+ - `--certificate-validity-duration-years <years>`
119
+ - `--key-id <id>` default: `main`
120
+ - `--project-root <path>`
121
+ - `--key-output-directory <path>` default: `codesigning-keys`
122
+ - `--certificate-output-directory <path>` default: `certs`
123
+ - `--force`
124
+
125
+ ### `expo-up codesigning:configure`
126
+
127
+ Configure existing signing materials into Expo config.
128
+
129
+ ## Local Development
130
+
131
+ ```bash
132
+ bun install
133
+ bun run build
134
+ bun run test
135
+ bun run check-types
136
+ bun run lint
137
+ ```
138
+
139
+ ## End-to-End Test With Example Apps
140
+
141
+ 1. Start server app:
142
+
143
+ ```bash
144
+ cd ../../apps/example-hono-cf-worker
145
+ bun run dev
146
+ ```
147
+
148
+ 2. Use CLI from Expo app root:
149
+
150
+ ```bash
151
+ cd ../example-expo-app
152
+ bunx expo-up whoami
153
+ bunx expo-up release --channel main --platform all
154
+ bunx expo-up history --channel main
155
+ ```
156
+
157
+ 3. In mobile app, press `Fetch update` and verify logs/status.
158
+
159
+ ## Package
160
+
161
+ Published as `@expo-up/cli`.
package/dist/index.js CHANGED
@@ -77252,7 +77252,7 @@ var require_source_map_support = __commonJS((exports, module) => {
77252
77252
 
77253
77253
  // ../../node_modules/.bun/typescript@5.9.2/node_modules/typescript/lib/typescript.js
77254
77254
  var require_typescript4 = __commonJS((exports, module) => {
77255
- var __dirname = "/Users/glncy/codes/glncy/expo-up/node_modules/.bun/typescript@5.9.2/node_modules/typescript/lib", __filename = "/Users/glncy/codes/glncy/expo-up/node_modules/.bun/typescript@5.9.2/node_modules/typescript/lib/typescript.js";
77255
+ var __dirname = "/home/runner/work/expo-up/expo-up/node_modules/.bun/typescript@5.9.2/node_modules/typescript/lib", __filename = "/home/runner/work/expo-up/expo-up/node_modules/.bun/typescript@5.9.2/node_modules/typescript/lib/typescript.js";
77256
77256
  /*! *****************************************************************************
77257
77257
  Copyright (c) Microsoft Corporation. All rights reserved.
77258
77258
  Licensed under the Apache License, Version 2.0 (the "License"); you may not use
@@ -261315,7 +261315,7 @@ var require_dist3 = __commonJS((exports, module) => {
261315
261315
 
261316
261316
  // ../../node_modules/.bun/xcode@3.0.1/node_modules/xcode/lib/pbxProject.js
261317
261317
  var require_pbxProject = __commonJS((exports, module) => {
261318
- var __dirname = "/Users/glncy/codes/glncy/expo-up/node_modules/.bun/xcode@3.0.1/node_modules/xcode/lib";
261318
+ var __dirname = "/home/runner/work/expo-up/expo-up/node_modules/.bun/xcode@3.0.1/node_modules/xcode/lib";
261319
261319
  var util = __require("util");
261320
261320
  var f = util.format;
261321
261321
  var EventEmitter = __require("events").EventEmitter;
@@ -291301,7 +291301,6 @@ config(en_default());
291301
291301
  var DEFAULT_CHANNEL = "main";
291302
291302
  var INIT_CHANNEL = "__INIT__";
291303
291303
  var EMBEDDED_ROLLBACK_TARGET = "EMBEDDED";
291304
- var DEFAULT_EXPO_UP_BASE_PATH = "/api/expo-up";
291305
291304
  // ../core/src/project.ts
291306
291305
  function isRecord(value2) {
291307
291306
  return typeof value2 === "object" && value2 !== null;
@@ -291360,7 +291359,7 @@ async function resolveRollbackTarget(input) {
291360
291359
  throw new Error(`Rollback chain exceeded max depth (${maxDepth}).`);
291361
291360
  }
291362
291361
  // ../core/src/url.ts
291363
- function parseExpoUpUpdatesUrl(rawUpdatesUrl, basePath = DEFAULT_EXPO_UP_BASE_PATH) {
291362
+ function parseExpoUpUpdatesUrl(rawUpdatesUrl, basePath = "/api/expo-up") {
291364
291363
  if (!rawUpdatesUrl) {
291365
291364
  return { serverUrl: "", projectId: "" };
291366
291365
  }
package/package.json CHANGED
@@ -1,9 +1,13 @@
1
1
  {
2
2
  "name": "@expo-up/cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/glncy/expo-up"
8
+ },
5
9
  "bin": {
6
- "expo-up": "./dist/index.js"
10
+ "expo-up": "dist/index.js"
7
11
  },
8
12
  "scripts": {
9
13
  "build": "bun build ./src/index.tsx --outdir ./dist --target node --external react --external ink --external ink-spinner --external figlet",
package/src/index.tsx CHANGED
@@ -306,7 +306,9 @@ program
306
306
 
307
307
  program
308
308
  .command("codesigning:configure")
309
- .description("Configure Expo config codeSigning fields from existing cert/key")
309
+ .description(
310
+ "Configure Expo config codeSigning fields from existing cert/key",
311
+ )
310
312
  .option(
311
313
  "-p, --project-root <path>",
312
314
  "Expo app root containing app.json or app.config.* (defaults to auto-detect)",
@@ -193,7 +193,9 @@ describe("createSortedMetadataHash", () => {
193
193
  },
194
194
  };
195
195
 
196
- expect(createSortedMetadataHash(first)).toBe(createSortedMetadataHash(second));
196
+ expect(createSortedMetadataHash(first)).toBe(
197
+ createSortedMetadataHash(second),
198
+ );
197
199
  });
198
200
 
199
201
  it("changes when metadata content changes", () => {
package/src/release.tsx CHANGED
@@ -146,7 +146,8 @@ export const Release: React.FC<ReleaseProps> = ({
146
146
 
147
147
  const metadata = readJsonFile<unknown>(metadataPath);
148
148
  const sortedMetadataHash = createSortedMetadataHash(metadata);
149
- if (debug) appendDebug(`Local sorted metadata hash: ${sortedMetadataHash}`);
149
+ if (debug)
150
+ appendDebug(`Local sorted metadata hash: ${sortedMetadataHash}`);
150
151
 
151
152
  const appConfig = getConfig(process.cwd());
152
153
  fs.writeFileSync(