@ramonclaudio/vexpo 0.1.4 → 0.1.5
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/LICENSE +21 -0
- package/README.md +5 -0
- package/dist/{chunk-W6O77AAZ.js → chunk-5BTLX335.js} +5 -1
- package/dist/{chunk-6O5TB4L4.js → chunk-BRSFTWP2.js} +1 -1
- package/dist/cli.js +50 -26
- package/dist/eas-integrations-ZULIUD4T.js +4 -0
- package/dist/proc-L3ORJMPB.js +2 -0
- package/package.json +1 -1
- package/dist/eas-integrations-5FVP7DI6.js +0 -4
- package/dist/proc-QPMIGTW6.js +0 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ramon Claudio
|
|
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
CHANGED
|
@@ -7,6 +7,10 @@ The setup CLI for [vexpo](https://github.com/ramonclaudio/vexpo) projects (Expo
|
|
|
7
7
|
|
|
8
8
|
Scaffolded by [`create-vexpo`](https://www.npmjs.com/package/@ramonclaudio/create-vexpo) into your devDependencies. Run it with `npx vexpo`.
|
|
9
9
|
|
|
10
|
+
<p align="center">
|
|
11
|
+
<img src="https://raw.githubusercontent.com/ramonclaudio/vexpo/main/docs/assets/demo-doctor.gif" width="720" alt="vexpo doctor auth-checking every credential against the live services">
|
|
12
|
+
</p>
|
|
13
|
+
|
|
10
14
|
## Setup
|
|
11
15
|
|
|
12
16
|
```
|
|
@@ -19,6 +23,7 @@ vexpo full --skip-rebrand full setup, skip the rebrand wizard
|
|
|
19
23
|
vexpo doctor cross-source drift detection
|
|
20
24
|
vexpo doctor --json machine-readable output
|
|
21
25
|
vexpo doctor --strict exit non-zero on any warn
|
|
26
|
+
vexpo doctor --redact mask identifying values (screenshots, issue reports)
|
|
22
27
|
|
|
23
28
|
vexpo accounts walk Apple/Expo/Convex/Resend signups (standalone)
|
|
24
29
|
vexpo rebrand replace template defaults with your identity
|
|
@@ -38,7 +38,11 @@ async function run(argv, opts = {}) {
|
|
|
38
38
|
stdin: opts.stdin ?? "ignore",
|
|
39
39
|
stdout: "pipe",
|
|
40
40
|
stderr: "pipe",
|
|
41
|
-
|
|
41
|
+
// run() exists to PARSE output. A FORCE_COLOR=1 in the caller's shell
|
|
42
|
+
// (CI, recordings) makes child CLIs wrap fields in ANSI codes and every
|
|
43
|
+
// regex parser downstream silently misses. Force color off; an explicit
|
|
44
|
+
// opts.env can still override.
|
|
45
|
+
env: { FORCE_COLOR: "0", NO_COLOR: "1", ...opts.env },
|
|
42
46
|
cwd: opts.cwd
|
|
43
47
|
});
|
|
44
48
|
const [code, stdout, stderr] = await Promise.all([
|
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { ensureLine, readOne, readAll, removeLines, ENV_FILE } from './chunk-3TT4CDAJ.js';
|
|
3
|
-
import { ascStatus } from './chunk-
|
|
3
|
+
import { ascStatus } from './chunk-BRSFTWP2.js';
|
|
4
4
|
import { dlx, detectPackageManager, installCmdFor } from './chunk-3RDUQUJW.js';
|
|
5
|
-
import { run, spawn } from './chunk-
|
|
5
|
+
import { run, spawn } from './chunk-5BTLX335.js';
|
|
6
6
|
import { Command } from 'commander';
|
|
7
|
-
import { readFile, access,
|
|
7
|
+
import { readFile, access, unlink, stat, mkdir, writeFile, rename } from 'fs/promises';
|
|
8
8
|
import { createInterface } from 'readline/promises';
|
|
9
9
|
import { homedir } from 'os';
|
|
10
10
|
import { join } from 'path';
|
|
@@ -13,7 +13,7 @@ import { createSign } from 'crypto';
|
|
|
13
13
|
|
|
14
14
|
// package.json
|
|
15
15
|
var package_default = {
|
|
16
|
-
version: "0.1.
|
|
16
|
+
version: "0.1.5"};
|
|
17
17
|
function deploymentName(value) {
|
|
18
18
|
if (!value) return void 0;
|
|
19
19
|
const m = /^(?:dev|prod|preview):(.+)$/.exec(value);
|
|
@@ -470,7 +470,7 @@ async function askYesNo(question, defaultYes) {
|
|
|
470
470
|
return raw === "y" || raw === "yes";
|
|
471
471
|
}
|
|
472
472
|
async function openUrlExternal(url) {
|
|
473
|
-
const { spawn: spawn2 } = await import('./proc-
|
|
473
|
+
const { spawn: spawn2 } = await import('./proc-L3ORJMPB.js');
|
|
474
474
|
const cmd = process.platform === "darwin" ? ["open", url] : process.platform === "win32" ? ["cmd", "/c", "start", "", url] : ["xdg-open", url];
|
|
475
475
|
spawn2(cmd, { stdin: "ignore", stdout: "ignore", stderr: "ignore" });
|
|
476
476
|
}
|
|
@@ -2385,6 +2385,23 @@ async function loadAscFromState2() {
|
|
|
2385
2385
|
if (!existsSync(p8Path)) return null;
|
|
2386
2386
|
return { issuerId, keyId, p8Path };
|
|
2387
2387
|
}
|
|
2388
|
+
async function syncAscAppIdToEasJson(ascAppId) {
|
|
2389
|
+
if (!ascAppId || !existsSync("eas.json")) return;
|
|
2390
|
+
try {
|
|
2391
|
+
const before = await readFile("eas.json", "utf8");
|
|
2392
|
+
const after = withAscAppId(before, ascAppId);
|
|
2393
|
+
if (after !== before) {
|
|
2394
|
+
await writeFile("eas.json", after);
|
|
2395
|
+
ok(`wrote ascAppId ${BOLD}${ascAppId}${RESET} to eas.json submit profiles`);
|
|
2396
|
+
note("commit this in your fork: non-interactive `eas submit` (CI) needs it");
|
|
2397
|
+
} else {
|
|
2398
|
+
nop("eas.json submit profiles already carry ascAppId");
|
|
2399
|
+
}
|
|
2400
|
+
} catch (err) {
|
|
2401
|
+
yep(`couldn't write ascAppId to eas.json: ${err instanceof Error ? err.message : err}`);
|
|
2402
|
+
note("non-interactive submit will need `ascAppId` set manually in eas.json");
|
|
2403
|
+
}
|
|
2404
|
+
}
|
|
2388
2405
|
async function runAscConnect(opts = {}) {
|
|
2389
2406
|
section("ASC connect");
|
|
2390
2407
|
if (!opts.force) {
|
|
@@ -2399,6 +2416,7 @@ async function runAscConnect(opts = {}) {
|
|
|
2399
2416
|
bundleId: status.appStoreConnectApp.bundleIdentifier,
|
|
2400
2417
|
connectedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2401
2418
|
});
|
|
2419
|
+
await syncAscAppIdToEasJson(status.appStoreConnectApp.ascAppIdentifier);
|
|
2402
2420
|
return 0;
|
|
2403
2421
|
}
|
|
2404
2422
|
} catch {
|
|
@@ -2464,23 +2482,13 @@ async function runAscConnect(opts = {}) {
|
|
|
2464
2482
|
connectedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2465
2483
|
});
|
|
2466
2484
|
if (existsSync("eas.json")) {
|
|
2485
|
+
let postStatus = null;
|
|
2467
2486
|
try {
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
const after = withAscAppId(before, ascAppId);
|
|
2472
|
-
if (after !== before) {
|
|
2473
|
-
await writeFile("eas.json", after);
|
|
2474
|
-
ok(`wrote ascAppId ${BOLD}${ascAppId}${RESET} to eas.json submit profiles`);
|
|
2475
|
-
note("commit this in your fork: non-interactive `eas submit` (CI) needs it");
|
|
2476
|
-
} else {
|
|
2477
|
-
nop("eas.json submit profiles already carry ascAppId");
|
|
2478
|
-
}
|
|
2479
|
-
}
|
|
2480
|
-
} catch (err) {
|
|
2481
|
-
yep(`couldn't write ascAppId to eas.json: ${err instanceof Error ? err.message : err}`);
|
|
2482
|
-
note("non-interactive submit will need `ascAppId` set manually in eas.json");
|
|
2487
|
+
postStatus = await ascStatus();
|
|
2488
|
+
} catch {
|
|
2489
|
+
postStatus = null;
|
|
2483
2490
|
}
|
|
2491
|
+
await syncAscAppIdToEasJson(postStatus?.appStoreConnectApp?.ascAppIdentifier);
|
|
2484
2492
|
}
|
|
2485
2493
|
return 0;
|
|
2486
2494
|
}
|
|
@@ -4107,10 +4115,25 @@ function icon(severity) {
|
|
|
4107
4115
|
return `${DIM}-${RESET}`;
|
|
4108
4116
|
}
|
|
4109
4117
|
}
|
|
4118
|
+
var REDACTIONS = [
|
|
4119
|
+
[/https?:\/\/[a-z0-9-]+\.convex\.(cloud|site)[^\s]*/g, "https://<deployment>.convex.$1"],
|
|
4120
|
+
[/\b[a-z]+-[a-z]+-\d{3}\b/g, "<deployment>"],
|
|
4121
|
+
[/\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi, "<project-id>"],
|
|
4122
|
+
[/\b[\w.+-]+@[\w-]+\.[\w.]+\b/g, "<email>"],
|
|
4123
|
+
[/\b(?:[a-z0-9-]+\.){1,}[a-z]{2,}\b(?= verified)/g, "<domain>"],
|
|
4124
|
+
[/\b(?:com|io|dev|app|net|org)(?:\.[a-z0-9-]+){2,}\b/gi, "<bundle-id>"],
|
|
4125
|
+
[/\b[A-Z0-9]{10}\b/g, "<id>"],
|
|
4126
|
+
[/(@)[\w-]+(\/)/g, "$1<owner>$2"]
|
|
4127
|
+
];
|
|
4128
|
+
function redactValue(text) {
|
|
4129
|
+
let out = text;
|
|
4130
|
+
for (const [re, sub] of REDACTIONS) out = out.replace(re, sub);
|
|
4131
|
+
return out;
|
|
4132
|
+
}
|
|
4110
4133
|
function categoryHeader(c) {
|
|
4111
4134
|
return c.charAt(0).toUpperCase() + c.slice(1);
|
|
4112
4135
|
}
|
|
4113
|
-
function printResults(checks) {
|
|
4136
|
+
function printResults(checks, redact) {
|
|
4114
4137
|
const byCategory = /* @__PURE__ */ new Map();
|
|
4115
4138
|
for (const c of checks) {
|
|
4116
4139
|
if (!byCategory.has(c.category)) byCategory.set(c.category, []);
|
|
@@ -4123,8 +4146,9 @@ function printResults(checks) {
|
|
|
4123
4146
|
section(categoryHeader(cat));
|
|
4124
4147
|
const w = Math.max(...items.map((c) => c.name.length));
|
|
4125
4148
|
for (const c of items) {
|
|
4126
|
-
|
|
4127
|
-
|
|
4149
|
+
const message = redact ? redactValue(c.message) : c.message;
|
|
4150
|
+
line(` ${icon(c.severity)} ${BOLD}${c.name.padEnd(w)}${RESET} ${message}`);
|
|
4151
|
+
if (c.details) line(` ${DIM}${redact ? redactValue(c.details) : c.details}${RESET}`);
|
|
4128
4152
|
}
|
|
4129
4153
|
}
|
|
4130
4154
|
}
|
|
@@ -4159,7 +4183,7 @@ async function runDoctor(options2) {
|
|
|
4159
4183
|
process.stdout.write(JSON.stringify({ channel, summary, checks }, null, 2) + "\n");
|
|
4160
4184
|
} else {
|
|
4161
4185
|
section(`Verify (${channel})`);
|
|
4162
|
-
printResults(checks);
|
|
4186
|
+
printResults(checks, options2.redact === true);
|
|
4163
4187
|
line();
|
|
4164
4188
|
const parts = [
|
|
4165
4189
|
`${GREEN}${summary.ok} ok${RESET}`,
|
|
@@ -5499,7 +5523,7 @@ async function liveCheckEas() {
|
|
|
5499
5523
|
}
|
|
5500
5524
|
async function liveCheckAscLink() {
|
|
5501
5525
|
try {
|
|
5502
|
-
const { ascStatus: ascStatus2 } = await import('./eas-integrations-
|
|
5526
|
+
const { ascStatus: ascStatus2 } = await import('./eas-integrations-ZULIUD4T.js');
|
|
5503
5527
|
const status = await ascStatus2();
|
|
5504
5528
|
return status.status === "connected";
|
|
5505
5529
|
} catch {
|
|
@@ -6440,7 +6464,7 @@ program.command("rebrand").description("Replace template defaults with your fork
|
|
|
6440
6464
|
program.command("review-account").description("Seed the App Review demo account on Convex.").option("--email <email>", "override demo email").option("--password <password>", "override demo password").option("--name <name>", "override demo display name", "App Review").option("--username <username>", "optional username").action((options2) => exitWith(runReviewAccount(options2)));
|
|
6441
6465
|
program.command("doctor").description(
|
|
6442
6466
|
"Cross-source drift detection. Auth-checks every credential, confirms IDs match across `.env.local`, Convex env, EAS env, `app.config.ts`. No eas-cli equivalent."
|
|
6443
|
-
).option("--channel <channel>", "dev | prod", "dev").option("--json", "machine-readable output", false).option("--strict", "exit non-zero on any warn", false).action((options2) => {
|
|
6467
|
+
).option("--channel <channel>", "dev | prod", "dev").option("--json", "machine-readable output", false).option("--strict", "exit non-zero on any warn", false).option("--redact", "mask identifying values (for screenshots and issue reports)", false).action((options2) => {
|
|
6444
6468
|
exitWith(runDoctor(options2));
|
|
6445
6469
|
});
|
|
6446
6470
|
program.command("adopt").description(
|
package/package.json
CHANGED
package/dist/proc-QPMIGTW6.js
DELETED