@better-update/cli 0.13.0 → 0.14.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/dist/index.mjs +119 -31
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -8,7 +8,7 @@ import { NodeContext } from "@effect/platform-node";
|
|
|
8
8
|
import path, { join } from "node:path";
|
|
9
9
|
import process$1 from "node:process";
|
|
10
10
|
import AppleUtils from "@expo/apple-utils";
|
|
11
|
-
import { cancel, confirm, isCancel, multiselect, password, select, text } from "@clack/prompts";
|
|
11
|
+
import { autocomplete, cancel, confirm, isCancel, multiselect, password, select, text } from "@clack/prompts";
|
|
12
12
|
import { once } from "node:events";
|
|
13
13
|
import { createServer } from "node:http";
|
|
14
14
|
import { maxBy, uniqBy } from "es-toolkit";
|
|
@@ -28,7 +28,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
|
28
28
|
|
|
29
29
|
//#endregion
|
|
30
30
|
//#region package.json
|
|
31
|
-
var version = "0.
|
|
31
|
+
var version = "0.14.0";
|
|
32
32
|
|
|
33
33
|
//#endregion
|
|
34
34
|
//#region src/lib/interactive-mode.ts
|
|
@@ -1796,6 +1796,15 @@ const promptSelect = (message, options) => Effect.gen(function* () {
|
|
|
1796
1796
|
options: [...options]
|
|
1797
1797
|
})));
|
|
1798
1798
|
});
|
|
1799
|
+
const promptAutocomplete = (message, options, config) => Effect.gen(function* () {
|
|
1800
|
+
yield* ensureInteractive(message);
|
|
1801
|
+
return handleCancel(yield* Effect.promise(async () => autocomplete({
|
|
1802
|
+
message,
|
|
1803
|
+
options: [...options],
|
|
1804
|
+
...config?.placeholder === void 0 ? {} : { placeholder: config.placeholder },
|
|
1805
|
+
...config?.maxItems === void 0 ? {} : { maxItems: config.maxItems }
|
|
1806
|
+
})));
|
|
1807
|
+
});
|
|
1799
1808
|
const promptMultiSelect = (message, options, config) => Effect.gen(function* () {
|
|
1800
1809
|
yield* ensureInteractive(message);
|
|
1801
1810
|
return handleCancel(yield* Effect.promise(async () => multiselect({
|
|
@@ -1820,6 +1829,83 @@ const promptConfirm = (message, options) => Effect.gen(function* () {
|
|
|
1820
1829
|
})));
|
|
1821
1830
|
});
|
|
1822
1831
|
|
|
1832
|
+
//#endregion
|
|
1833
|
+
//#region src/lib/apple-auth.ts
|
|
1834
|
+
const APPLE_PROVIDER_ID_ENV = "APPLE_PROVIDER_ID";
|
|
1835
|
+
const readEnv = (name) => Effect.gen(function* () {
|
|
1836
|
+
return yield* (yield* CliRuntime).getEnv(name);
|
|
1837
|
+
});
|
|
1838
|
+
const parseProviderId = (raw) => {
|
|
1839
|
+
const id = Number(raw);
|
|
1840
|
+
return Number.isInteger(id) ? Effect.succeed(id) : Effect.fail(new AppleAuthError$1({ message: `${APPLE_PROVIDER_ID_ENV} must be a numeric provider ID, got "${raw}".` }));
|
|
1841
|
+
};
|
|
1842
|
+
const readEnvProviderId = Effect.gen(function* () {
|
|
1843
|
+
const raw = yield* readEnv(APPLE_PROVIDER_ID_ENV);
|
|
1844
|
+
if (!raw) return;
|
|
1845
|
+
return yield* parseProviderId(raw);
|
|
1846
|
+
});
|
|
1847
|
+
const switchSessionProvider = (appleUtils, providerId) => Effect.tryPromise({
|
|
1848
|
+
try: async () => appleUtils.Session.setSessionProviderIdAsync(providerId),
|
|
1849
|
+
catch: (error) => new AppleAuthError$1({ message: `Failed to switch App Store Connect provider (${providerId}): ${String(error)}` })
|
|
1850
|
+
}).pipe(Effect.asVoid);
|
|
1851
|
+
/**
|
|
1852
|
+
* Resolve App Store Connect provider for the current session.
|
|
1853
|
+
*
|
|
1854
|
+
* Selection order: APPLE_PROVIDER_ID env → single available provider →
|
|
1855
|
+
* interactive prompt (always, when multi-team + interactive) → fall back to
|
|
1856
|
+
* apple-utils' currentProviderId (non-interactive only).
|
|
1857
|
+
*
|
|
1858
|
+
* Multi-team users are always re-prompted in interactive mode so a wrong pick
|
|
1859
|
+
* from a previous run can be corrected — we do NOT cache the team choice.
|
|
1860
|
+
*
|
|
1861
|
+
* `switched` flags that the apple-utils cookie jar was mutated.
|
|
1862
|
+
*
|
|
1863
|
+
* Non-interactive (CI): env or single-team paths still work; multi-team falls
|
|
1864
|
+
* back to whatever apple-utils auto-resolved from cookies. Fails with
|
|
1865
|
+
* InteractiveProhibitedError when multi-team and no signal at all.
|
|
1866
|
+
*/
|
|
1867
|
+
const resolveProvider = (appleUtils, availableProviders, currentProviderId) => Effect.gen(function* () {
|
|
1868
|
+
let switched = false;
|
|
1869
|
+
const applyChoice = (picked) => Effect.gen(function* () {
|
|
1870
|
+
if (currentProviderId !== picked) {
|
|
1871
|
+
yield* switchSessionProvider(appleUtils, picked);
|
|
1872
|
+
switched = true;
|
|
1873
|
+
}
|
|
1874
|
+
return picked;
|
|
1875
|
+
});
|
|
1876
|
+
const envId = yield* readEnvProviderId;
|
|
1877
|
+
if (envId !== void 0) return {
|
|
1878
|
+
providerId: yield* applyChoice(envId),
|
|
1879
|
+
switched
|
|
1880
|
+
};
|
|
1881
|
+
if (availableProviders.length === 0) return {
|
|
1882
|
+
providerId: currentProviderId,
|
|
1883
|
+
switched
|
|
1884
|
+
};
|
|
1885
|
+
const [firstProvider] = availableProviders;
|
|
1886
|
+
if (availableProviders.length === 1 && firstProvider) return {
|
|
1887
|
+
providerId: yield* applyChoice(firstProvider.providerId),
|
|
1888
|
+
switched
|
|
1889
|
+
};
|
|
1890
|
+
if (!(yield* InteractiveMode).allow) {
|
|
1891
|
+
if (currentProviderId !== void 0) return {
|
|
1892
|
+
providerId: currentProviderId,
|
|
1893
|
+
switched
|
|
1894
|
+
};
|
|
1895
|
+
return yield* new InteractiveProhibitedError({ message: "Multiple App Store Connect providers are available but no APPLE_PROVIDER_ID is set; re-run interactively or set the env var." });
|
|
1896
|
+
}
|
|
1897
|
+
return {
|
|
1898
|
+
providerId: yield* applyChoice(yield* promptAutocomplete("Select App Store Connect provider:", availableProviders.map((provider) => ({
|
|
1899
|
+
value: provider.providerId,
|
|
1900
|
+
label: `${provider.name} [${provider.subType}] (${provider.providerId})`
|
|
1901
|
+
})), {
|
|
1902
|
+
placeholder: "Type to filter…",
|
|
1903
|
+
maxItems: 10
|
|
1904
|
+
})),
|
|
1905
|
+
switched
|
|
1906
|
+
};
|
|
1907
|
+
});
|
|
1908
|
+
|
|
1823
1909
|
//#endregion
|
|
1824
1910
|
//#region ../../packages/safe-json/src/index.ts
|
|
1825
1911
|
const parseJsonResult = (text) => {
|
|
@@ -1852,14 +1938,10 @@ const AppleSessionStoreLive = Layer.effect(AppleSessionStore, Effect.gen(functio
|
|
|
1852
1938
|
if (!content) return null;
|
|
1853
1939
|
const parsed = safeJsonParse(content);
|
|
1854
1940
|
if (!isRecord(parsed)) return null;
|
|
1855
|
-
if (typeof parsed["
|
|
1856
|
-
const providerIdRaw = parsed["providerId"];
|
|
1857
|
-
const hasProviderId = typeof providerIdRaw === "number" && Number.isInteger(providerIdRaw);
|
|
1941
|
+
if (typeof parsed["username"] !== "string" || !parsed["cookies"]) return null;
|
|
1858
1942
|
return {
|
|
1859
1943
|
cookies: parsed["cookies"],
|
|
1860
|
-
|
|
1861
|
-
username: parsed["username"],
|
|
1862
|
-
...hasProviderId ? { providerId: providerIdRaw } : {}
|
|
1944
|
+
username: parsed["username"]
|
|
1863
1945
|
};
|
|
1864
1946
|
}),
|
|
1865
1947
|
saveSession: (session) => Effect.gen(function* () {
|
|
@@ -1905,17 +1987,30 @@ const sessionFromInfo = (username, info) => ({
|
|
|
1905
1987
|
teamName: info.provider.name,
|
|
1906
1988
|
providerId: info.provider.providerId
|
|
1907
1989
|
});
|
|
1908
|
-
const
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
},
|
|
1990
|
+
const sessionFromProvider = (username, provider) => ({
|
|
1991
|
+
username,
|
|
1992
|
+
teamId: provider.publicProviderId,
|
|
1993
|
+
teamName: provider.name,
|
|
1994
|
+
providerId: provider.providerId
|
|
1995
|
+
});
|
|
1996
|
+
const restoreFromCookies = (appleUtils, cookies) => Effect.tryPromise({
|
|
1997
|
+
try: async () => appleUtils.Auth.loginWithCookiesAsync({ cookies }),
|
|
1917
1998
|
catch: (cause) => new AppleAuthError$1({ message: `Failed to restore Apple session: ${formatCause(cause)}` })
|
|
1918
1999
|
});
|
|
2000
|
+
/**
|
|
2001
|
+
* After a cookie restore or fresh credentials login, re-resolve the team via
|
|
2002
|
+
* {@link resolveProvider}. The cookies are accepted as-is (auth state) but the
|
|
2003
|
+
* team is treated as a per-run choice — we never trust a previously-cached team,
|
|
2004
|
+
* so a wrong pick can always be corrected on the next run.
|
|
2005
|
+
*/
|
|
2006
|
+
const resolveSessionTeam = (appleUtils, state) => Effect.gen(function* () {
|
|
2007
|
+
const { availableProviders } = state.session;
|
|
2008
|
+
const resolution = yield* resolveProvider(appleUtils, availableProviders, state.context.providerId ?? state.session.provider.providerId);
|
|
2009
|
+
if (!resolution.switched || resolution.providerId === void 0) return sessionFromAuthState(state);
|
|
2010
|
+
const picked = availableProviders.find((provider) => provider.providerId === resolution.providerId);
|
|
2011
|
+
if (picked === void 0) return yield* new AppleAuthError$1({ message: `Selected provider ${String(resolution.providerId)} not in available providers list.` });
|
|
2012
|
+
return sessionFromProvider(state.username, picked);
|
|
2013
|
+
});
|
|
1919
2014
|
const loginWithCredentials = (appleUtils, credentials) => Effect.tryPromise({
|
|
1920
2015
|
try: async () => appleUtils.Auth.loginWithUserCredentialsAsync(credentials, { autoResolveProvider: true }),
|
|
1921
2016
|
catch: (cause) => new AppleAuthError$1({ message: `Apple login failed: ${formatCause(cause)}` })
|
|
@@ -1942,12 +2037,10 @@ const interactiveLogin = (appleUtils, options, cachedUsername) => Effect.gen(fun
|
|
|
1942
2037
|
password
|
|
1943
2038
|
});
|
|
1944
2039
|
if (state === null) return yield* new AppleAuthError$1({ message: "Apple login returned no session (unexpected)." });
|
|
1945
|
-
const session =
|
|
2040
|
+
const session = yield* resolveSessionTeam(appleUtils, state);
|
|
1946
2041
|
yield* store.saveSession({
|
|
1947
2042
|
cookies: readJarCookies(appleUtils),
|
|
1948
|
-
username: session.username
|
|
1949
|
-
teamId: session.teamId,
|
|
1950
|
-
...session.providerId === void 0 ? {} : { providerId: session.providerId }
|
|
2043
|
+
username: session.username
|
|
1951
2044
|
});
|
|
1952
2045
|
yield* store.saveLastUsername(session.username);
|
|
1953
2046
|
return session;
|
|
@@ -1955,15 +2048,15 @@ const interactiveLogin = (appleUtils, options, cachedUsername) => Effect.gen(fun
|
|
|
1955
2048
|
const tryRestore = (appleUtils, store) => Effect.gen(function* () {
|
|
1956
2049
|
const stored = yield* store.loadSession;
|
|
1957
2050
|
if (stored === null) return null;
|
|
1958
|
-
const restored = yield* restoreFromCookies(appleUtils, stored.cookies
|
|
2051
|
+
const restored = yield* restoreFromCookies(appleUtils, stored.cookies).pipe(Effect.catchAll(() => Effect.succeed(null)));
|
|
1959
2052
|
if (restored === null) return null;
|
|
1960
|
-
return
|
|
2053
|
+
return yield* resolveSessionTeam(appleUtils, restored);
|
|
1961
2054
|
});
|
|
1962
2055
|
const makeAppleAuthLive = (appleUtils = defaultAppleUtils) => Layer.effect(AppleAuth, Effect.gen(function* () {
|
|
1963
2056
|
const store = yield* AppleSessionStore;
|
|
1964
2057
|
return {
|
|
1965
2058
|
ensureLoggedIn: (options = {}) => Effect.gen(function* () {
|
|
1966
|
-
const restored = yield* tryRestore(appleUtils, store)
|
|
2059
|
+
const restored = yield* tryRestore(appleUtils, store);
|
|
1967
2060
|
if (restored !== null) return restored;
|
|
1968
2061
|
return yield* interactiveLogin(appleUtils, options, yield* store.loadLastUsername).pipe(Effect.provideService(AppleSessionStore, store));
|
|
1969
2062
|
}),
|
|
@@ -1974,15 +2067,10 @@ const makeAppleAuthLive = (appleUtils = defaultAppleUtils) => Layer.effect(Apple
|
|
|
1974
2067
|
whoami: Effect.gen(function* () {
|
|
1975
2068
|
const stored = yield* store.loadSession;
|
|
1976
2069
|
if (stored === null) return null;
|
|
1977
|
-
const restored = yield* restoreFromCookies(appleUtils, stored.cookies
|
|
2070
|
+
const restored = yield* restoreFromCookies(appleUtils, stored.cookies).pipe(Effect.catchAll(() => Effect.succeed(null)));
|
|
1978
2071
|
if (restored !== null) return sessionFromAuthState(restored);
|
|
1979
2072
|
const info = appleUtils.Session.getAnySessionInfo();
|
|
1980
|
-
return info === null ?
|
|
1981
|
-
username: stored.username,
|
|
1982
|
-
teamId: stored.teamId,
|
|
1983
|
-
teamName: null,
|
|
1984
|
-
providerId: stored.providerId
|
|
1985
|
-
} : sessionFromInfo(stored.username, info);
|
|
2073
|
+
return info === null ? null : sessionFromInfo(stored.username, info);
|
|
1986
2074
|
}),
|
|
1987
2075
|
buildRequestContext: (session) => ({
|
|
1988
2076
|
teamId: session.teamId,
|