@tapi-dev/sdk 0.1.30 → 0.1.31

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/cli.d.ts CHANGED
@@ -60,6 +60,7 @@ export interface StudioCliOptions {
60
60
  silent: boolean;
61
61
  exePath?: string;
62
62
  installToken?: string;
63
+ installTokenSource?: "option" | "env" | "minted";
63
64
  workspace?: TapiWorkspace;
64
65
  workspaceRoot?: string;
65
66
  projectId?: string;
@@ -113,7 +114,7 @@ export declare function getStudioExecutableCandidates(): string[];
113
114
  export declare function validateStudioManifest(input: unknown): StudioReleaseManifest;
114
115
  export declare function validateServiceReleaseManifest(input: unknown): ServiceReleaseManifest;
115
116
  export declare function compareVersions(left: string, right: string): number;
116
- export declare function memoizeStudioInstallToken(options: StudioCliOptions, installToken?: string): string;
117
+ export declare function memoizeStudioInstallToken(options: StudioCliOptions, installToken?: string, source?: StudioCliOptions["installTokenSource"]): string;
117
118
  export declare function closeExistingPortableStudioServersForFreshLaunch(stopProcesses?: () => Promise<number>): Promise<{
118
119
  stopped: number;
119
120
  recordsRemoved: number;
package/dist/cli.js CHANGED
@@ -344,6 +344,8 @@ export function parseStudioOptions(args) {
344
344
  : `${downloadsBaseUrl.replace(/\/+$/, "")}/studio/channels/${channel}/latest.json`;
345
345
  const projectId = raw.projectId ?? envString("TAPI_PROJECT_ID") ?? workspace?.projectId;
346
346
  const projectSlug = raw.projectSlug ?? envString("TAPI_PROJECT_SLUG") ?? workspace?.projectSlug;
347
+ const envInstallToken = envString("TAPI_STUDIO_INSTALL_TOKEN");
348
+ const installToken = raw.installToken ?? envInstallToken;
347
349
  return {
348
350
  channel,
349
351
  apiBaseUrl,
@@ -354,7 +356,8 @@ export function parseStudioOptions(args) {
354
356
  downloadOnly: raw.downloadOnly ?? false,
355
357
  silent: raw.silent ?? false,
356
358
  exePath: raw.exePath ?? envString("TAPI_STUDIO_EXE"),
357
- installToken: raw.installToken ?? envString("TAPI_STUDIO_INSTALL_TOKEN"),
359
+ installToken,
360
+ installTokenSource: raw.installToken ? "option" : installToken ? "env" : undefined,
358
361
  workspace,
359
362
  workspaceRoot: workspace?.root,
360
363
  projectId,
@@ -1967,12 +1970,7 @@ async function installStudio(options) {
1967
1970
  throw new Error("Direct Studio manifest overrides are no longer supported for install. "
1968
1971
  + "Use --channel with the protected install flow instead.");
1969
1972
  }
1970
- const installToken = await ensureStudioInstallTokenForRun(options, event, "Checking Studio install authorization");
1971
- await event.phase("manifest.fetch.start", {
1972
- apiBaseUrl: options.apiBaseUrl,
1973
- channel: options.channel,
1974
- });
1975
- const manifest = await withCliSpinner(`Fetching Tapi Studio ${options.channel} manifest`, () => fetchProtectedStudioManifest(options.apiBaseUrl, options.channel, installToken));
1973
+ const manifest = await fetchStudioManifestForRun(options, event, "Checking Studio install authorization");
1976
1974
  await event.phase("manifest.fetch.success", {
1977
1975
  manifest: manifestEventSummary(manifest),
1978
1976
  });
@@ -2086,7 +2084,7 @@ async function obtainStudioInstallToken(options, event) {
2086
2084
  const issued = await requestStudioInstallToken(options.apiBaseUrl, options.channel, firebaseCreds.idToken);
2087
2085
  return issued.installToken;
2088
2086
  }
2089
- export function memoizeStudioInstallToken(options, installToken) {
2087
+ export function memoizeStudioInstallToken(options, installToken, source = "minted") {
2090
2088
  const existing = options.installToken?.trim();
2091
2089
  if (existing) {
2092
2090
  options.installToken = existing;
@@ -2095,9 +2093,14 @@ export function memoizeStudioInstallToken(options, installToken) {
2095
2093
  const normalized = installToken?.trim() ?? "";
2096
2094
  if (normalized) {
2097
2095
  options.installToken = normalized;
2096
+ options.installTokenSource = source;
2098
2097
  }
2099
2098
  return normalized;
2100
2099
  }
2100
+ function clearStudioInstallTokenForRun(options) {
2101
+ options.installToken = undefined;
2102
+ options.installTokenSource = undefined;
2103
+ }
2101
2104
  async function ensureStudioInstallTokenForRun(options, event, message) {
2102
2105
  const existing = memoizeStudioInstallToken(options);
2103
2106
  if (existing) {
@@ -2111,7 +2114,7 @@ async function ensureStudioInstallTokenForRun(options, event, message) {
2111
2114
  apiBaseUrl: options.apiBaseUrl,
2112
2115
  channel: options.channel,
2113
2116
  });
2114
- const installToken = memoizeStudioInstallToken(options, await withCliSpinner(message, () => obtainStudioInstallToken(options, event)));
2117
+ const installToken = memoizeStudioInstallToken(options, await withCliSpinner(message, () => obtainStudioInstallToken(options, event)), "minted");
2115
2118
  await event.phase("auth.install_token.request.success", {
2116
2119
  apiBaseUrl: options.apiBaseUrl,
2117
2120
  channel: options.channel,
@@ -2119,6 +2122,39 @@ async function ensureStudioInstallTokenForRun(options, event, message) {
2119
2122
  });
2120
2123
  return installToken;
2121
2124
  }
2125
+ async function fetchStudioManifestForRun(options, event, authMessage) {
2126
+ const installToken = await ensureStudioInstallTokenForRun(options, event, authMessage);
2127
+ await event.phase("manifest.fetch.start", {
2128
+ apiBaseUrl: options.apiBaseUrl,
2129
+ channel: options.channel,
2130
+ });
2131
+ try {
2132
+ return await withCliSpinner(`Fetching Tapi Studio ${options.channel} manifest`, () => fetchProtectedStudioManifest(options.apiBaseUrl, options.channel, installToken));
2133
+ }
2134
+ catch (error) {
2135
+ if (!isExpiredStudioInstallTokenError(error) || options.installTokenSource === "option") {
2136
+ throw error;
2137
+ }
2138
+ await event.phase("auth.install_token.expired", {
2139
+ apiBaseUrl: options.apiBaseUrl,
2140
+ channel: options.channel,
2141
+ tokenSource: options.installTokenSource ?? "unknown",
2142
+ error: errorDetails(error),
2143
+ });
2144
+ clearStudioInstallTokenForRun(options);
2145
+ const refreshedToken = await ensureStudioInstallTokenForRun(options, event, "Refreshing Studio install authorization");
2146
+ await event.phase("manifest.fetch.retry.start", {
2147
+ apiBaseUrl: options.apiBaseUrl,
2148
+ channel: options.channel,
2149
+ });
2150
+ return await withCliSpinner(`Retrying Tapi Studio ${options.channel} manifest`, () => fetchProtectedStudioManifest(options.apiBaseUrl, options.channel, refreshedToken));
2151
+ }
2152
+ }
2153
+ function isExpiredStudioInstallTokenError(error) {
2154
+ const message = formatError(error);
2155
+ return (message.includes("Failed to fetch protected Studio manifest: HTTP 401")
2156
+ && message.includes("Studio install token has expired"));
2157
+ }
2122
2158
  async function openStudio(options) {
2123
2159
  ensureWindowsHost();
2124
2160
  if (options.downloadOnly) {
@@ -2180,12 +2216,7 @@ async function ensurePortableStudioServer(options) {
2180
2216
  options: installEventOptions(options),
2181
2217
  });
2182
2218
  try {
2183
- const installToken = await ensureStudioInstallTokenForRun(options, event, "Checking Studio install authorization");
2184
- await event.phase("manifest.fetch.start", {
2185
- apiBaseUrl: options.apiBaseUrl,
2186
- channel: options.channel,
2187
- });
2188
- const manifest = await withCliSpinner(`Fetching Tapi Studio ${options.channel} manifest`, () => fetchProtectedStudioManifest(options.apiBaseUrl, options.channel, installToken));
2219
+ const manifest = await fetchStudioManifestForRun(options, event, "Checking Studio install authorization");
2189
2220
  ensureCompatibleManifest(manifest);
2190
2221
  await event.phase("manifest.fetch.success", {
2191
2222
  manifest: manifestEventSummary(manifest),
@@ -3416,6 +3447,7 @@ function installEventOptions(options) {
3416
3447
  silent: options.silent,
3417
3448
  exePath: options.exePath,
3418
3449
  installTokenProvided: Boolean(options.installToken),
3450
+ installTokenSource: options.installTokenSource,
3419
3451
  };
3420
3452
  }
3421
3453
  function serviceManifestEventSummary(manifest) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tapi-dev/sdk",
3
- "version": "0.1.30",
3
+ "version": "0.1.31",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",