@expokit/cli 0.4.2 → 0.4.3
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 +6 -2
- package/bin/expo-kit.js +26 -3
- package/bin/lib.mjs +14 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -50,12 +50,16 @@ Everything else — live previews, props, installation, theming, Pro, AI / MCP s
|
|
|
50
50
|
|
|
51
51
|
## Security
|
|
52
52
|
|
|
53
|
-
- **No dependencies, no install scripts
|
|
53
|
+
- **No dependencies, no install scripts.**
|
|
54
|
+
- **Anonymous install counts only** — after a successful `add`, the CLI sends the item's name (`{"items":["button"]}`)
|
|
55
|
+
to expokit.in so the site can show how often each component is installed. No token, files, paths or machine details;
|
|
56
|
+
repeat adds count once a day. Turn it off with `DO_NOT_TRACK=1` or `EXPO_KIT_TELEMETRY=0`; it never runs in CI,
|
|
57
|
+
`--dry-run` or `update`.
|
|
54
58
|
- **Writes only inside your app** — `components.json`, the `@/*` alias in `tsconfig.json` and the component files.
|
|
55
59
|
`--dry-run` shows every change first; `add` never overwrites a file you changed unless you pass `--force`.
|
|
56
60
|
`paths` in `components.json` that point outside the app are refused. Symlinks inside the app are followed, not
|
|
57
61
|
checked, so a cloned repo that symlinks a folder elsewhere can still send writes there.
|
|
58
|
-
- **Free components need no network** — they ship inside this package. Pro components are downloaded over HTTPS from
|
|
62
|
+
- **Free components need no network to install** — they ship inside this package. Pro components are downloaded over HTTPS from
|
|
59
63
|
expokit.in; your token is stored readable only by you, sent only to that site and never through a redirect.
|
|
60
64
|
In scripts, pipe it to `login` or set `EXPO_KIT_TOKEN` (`--token` leaves it in your shell history).
|
|
61
65
|
- **Runs one command:** `npx expo install` for the packages a component needs — without `EXPO_KIT_TOKEN` in its
|
package/bin/expo-kit.js
CHANGED
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
retryDelayMs,
|
|
35
35
|
retryHint,
|
|
36
36
|
tabComponentName,
|
|
37
|
+
telemetryEnabled,
|
|
37
38
|
needsDevBuild,
|
|
38
39
|
pickMainExport,
|
|
39
40
|
} from './lib.mjs';
|
|
@@ -942,12 +943,33 @@ function cmdInit(cwd, flags, dir) {
|
|
|
942
943
|
log(`Done. Add items with: ${RUN} add <name>`);
|
|
943
944
|
}
|
|
944
945
|
|
|
945
|
-
|
|
946
|
+
/**
|
|
947
|
+
* After a successful add: tells the site which item was installed — just its name, no token or project
|
|
948
|
+
* data (README "Privacy"). Off with DO_NOT_TRACK=1 / EXPO_KIT_TELEMETRY=0 and in CI. Never fails the add.
|
|
949
|
+
*/
|
|
950
|
+
async function reportInstalled(name) {
|
|
951
|
+
if (!telemetryEnabled(process.env)) return;
|
|
952
|
+
try {
|
|
953
|
+
parseSiteUrl(SITE_URL);
|
|
954
|
+
const res = await fetch(`${SITE_URL}/api/cli/installed`, {
|
|
955
|
+
method: 'POST',
|
|
956
|
+
headers: { 'content-type': 'application/json' },
|
|
957
|
+
body: JSON.stringify({ items: [name] }),
|
|
958
|
+
signal: AbortSignal.timeout(1500),
|
|
959
|
+
});
|
|
960
|
+
await res.arrayBuffer();
|
|
961
|
+
} catch {
|
|
962
|
+
// offline, slow or blocked: the count just misses this one
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
/** `report: false` for re-adds that aren't new installs (`update --force`). */
|
|
967
|
+
async function cmdAdd(args, cwd, { report = true } = {}) {
|
|
946
968
|
const { flags, positional } = parseFlags(args);
|
|
947
969
|
// `add a b c` → add each in turn with the same flags.
|
|
948
970
|
if (positional.length > 1 && !positional.includes('--list')) {
|
|
949
971
|
const flagArgs = args.filter((a) => a.startsWith('--'));
|
|
950
|
-
for (const item of positional) await cmdAdd([item, ...flagArgs], cwd);
|
|
972
|
+
for (const item of positional) await cmdAdd([item, ...flagArgs], cwd, { report });
|
|
951
973
|
return;
|
|
952
974
|
}
|
|
953
975
|
const name = positional[0];
|
|
@@ -1049,6 +1071,7 @@ async function cmdAdd(args, cwd) {
|
|
|
1049
1071
|
const depsOk = runExpoInstall(projectRoot, meta.dependencies ?? [], false);
|
|
1050
1072
|
|
|
1051
1073
|
if (depsOk) markTemplateInstalled(projectRoot, config, resolved);
|
|
1074
|
+
if (report) await reportInstalled(resolved);
|
|
1052
1075
|
|
|
1053
1076
|
console.log('');
|
|
1054
1077
|
if (resolved === 'liquidglass-tab') {
|
|
@@ -1092,7 +1115,7 @@ async function cmdUpdate(args, cwd) {
|
|
|
1092
1115
|
if (flags.force) {
|
|
1093
1116
|
for (const resolved of targets) {
|
|
1094
1117
|
log(`Full overwrite ${resolved} (--force${flags.dryRun ? ', dry run' : ''})…\n`);
|
|
1095
|
-
await cmdAdd([resolved, '--force', ...(flags.dryRun ? ['--dry-run'] : [])], cwd);
|
|
1118
|
+
await cmdAdd([resolved, '--force', ...(flags.dryRun ? ['--dry-run'] : [])], cwd, { report: false });
|
|
1096
1119
|
}
|
|
1097
1120
|
return;
|
|
1098
1121
|
}
|
package/bin/lib.mjs
CHANGED
|
@@ -318,6 +318,7 @@ export function kitVersion(text) {
|
|
|
318
318
|
*/
|
|
319
319
|
export const EXPO_GO_PACKAGES = new Set([
|
|
320
320
|
'@expo/vector-icons',
|
|
321
|
+
'@react-native-async-storage/async-storage',
|
|
321
322
|
'@shopify/react-native-skia',
|
|
322
323
|
'expo-blur',
|
|
323
324
|
'expo-charts',
|
|
@@ -325,6 +326,7 @@ export const EXPO_GO_PACKAGES = new Set([
|
|
|
325
326
|
'expo-haptics',
|
|
326
327
|
'expo-router',
|
|
327
328
|
'expo-splash-screen',
|
|
329
|
+
'expo-status-bar',
|
|
328
330
|
'react-native-gesture-handler',
|
|
329
331
|
'react-native-reanimated',
|
|
330
332
|
'react-native-safe-area-context',
|
|
@@ -366,6 +368,18 @@ export function mergeDependencies(...lists) {
|
|
|
366
368
|
|
|
367
369
|
export const DEFAULT_SITE_URL = 'https://expokit.in';
|
|
368
370
|
|
|
371
|
+
const OFF = /^(0|false|off|no)$/i;
|
|
372
|
+
const set = (v) => v !== undefined && v !== '' && !OFF.test(v);
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Anonymous install counts (README "Privacy"): on unless DO_NOT_TRACK is set, EXPO_KIT_TELEMETRY is
|
|
376
|
+
* 0/false/off/no, or it's a CI run (builds re-adding items aren't new installs).
|
|
377
|
+
*/
|
|
378
|
+
export function telemetryEnabled(env) {
|
|
379
|
+
if (set(env.DO_NOT_TRACK) || set(env.CI)) return false;
|
|
380
|
+
return !(env.EXPO_KIT_TELEMETRY !== undefined && OFF.test(env.EXPO_KIT_TELEMETRY));
|
|
381
|
+
}
|
|
382
|
+
|
|
369
383
|
export function isLoopbackHost(hostname) {
|
|
370
384
|
return hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '[::1]' || hostname === '::1';
|
|
371
385
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@expokit/cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"mcpName": "io.github.Anshkaran7/expokit",
|
|
5
5
|
"description": "Animated UI components for Expo and React Native — a shadcn-style CLI that copies buttons, inputs, cards, charts and full screens into your app",
|
|
6
6
|
"license": "MIT",
|