@tapi-dev/sdk 0.1.24 → 0.1.25

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
@@ -114,6 +114,11 @@ export declare function validateStudioManifest(input: unknown): StudioReleaseMan
114
114
  export declare function validateServiceReleaseManifest(input: unknown): ServiceReleaseManifest;
115
115
  export declare function compareVersions(left: string, right: string): number;
116
116
  export declare function memoizeStudioInstallToken(options: StudioCliOptions, installToken?: string): string;
117
+ export declare function tryOpenExistingPortableStudioServer(options: StudioCliOptions, manifest: StudioReleaseManifest, fetchImpl?: FetchLike, openBrowserImpl?: (url: string) => void): Promise<{
118
+ opened: boolean;
119
+ baseUrl?: string;
120
+ reason?: string;
121
+ }>;
117
122
  export declare function findPortablePlaywrightBrowsersDir(exePath: string): string | undefined;
118
123
  export declare function waitForHttpOk(url: string, timeoutMs?: number, intervalMs?: number, fetchImpl?: FetchLike): Promise<void>;
119
124
  export declare function chooseStudioPort(preferred?: number, options?: {
package/dist/cli.js CHANGED
@@ -2126,6 +2126,10 @@ async function openStudio(options) {
2126
2126
  if (!options.exePath) {
2127
2127
  const portable = await ensurePortableStudioServer(options);
2128
2128
  if (portable) {
2129
+ const existing = await tryOpenExistingPortableStudioServer(options, portable.manifest);
2130
+ if (existing.opened) {
2131
+ return 0;
2132
+ }
2129
2133
  await launchPortableStudioServer(portable.exePath, options, portable.manifest);
2130
2134
  return 0;
2131
2135
  }
@@ -2160,6 +2164,34 @@ function findStudioExecutable(options) {
2160
2164
  }
2161
2165
  return getStudioExecutableCandidates().find((candidate) => existsSync(candidate));
2162
2166
  }
2167
+ export async function tryOpenExistingPortableStudioServer(options, manifest, fetchImpl = fetch, openBrowserImpl = openBrowser) {
2168
+ const record = await readStudioInstanceRecord(options);
2169
+ if (!record) {
2170
+ return { opened: false, reason: "instance_record_missing" };
2171
+ }
2172
+ if ((record.manifestVersion || "") !== manifest.version) {
2173
+ return { opened: false, reason: "manifest_version_mismatch" };
2174
+ }
2175
+ try {
2176
+ const identityResponse = await fetchWithTimeout(`${record.baseUrl.replace(/\/+$/, "")}/api/studio/control/identity`, { headers: { Accept: "application/json" } }, 1_000, fetchImpl);
2177
+ if (!identityResponse.ok) {
2178
+ await unlinkIfExists(studioInstanceRecordPathForOptions(options));
2179
+ return { opened: false, reason: `identity_http_${identityResponse.status}` };
2180
+ }
2181
+ const identity = await readJsonBody(identityResponse);
2182
+ if (!studioInstanceIdentityMatches(identity, options)) {
2183
+ return { opened: false, reason: "identity_mismatch" };
2184
+ }
2185
+ const launchUrl = studioLaunchUrl(record.baseUrl, options);
2186
+ openBrowserImpl(launchUrl);
2187
+ console.log(`Opened existing Tapi Studio ${record.manifestVersion || manifest.version}: ${launchUrl}`);
2188
+ return { opened: true, baseUrl: record.baseUrl };
2189
+ }
2190
+ catch (error) {
2191
+ await unlinkIfExists(studioInstanceRecordPathForOptions(options));
2192
+ return { opened: false, reason: formatError(error) };
2193
+ }
2194
+ }
2163
2195
  async function ensurePortableStudioServer(options) {
2164
2196
  const event = await createCliWideEvent("tapi_cli.studio_server_ensure", {
2165
2197
  sdk_version: sdkVersion,
@@ -2259,8 +2291,7 @@ async function launchPortableStudioServer(exePath, options, manifest) {
2259
2291
  env.PLAYWRIGHT_BROWSERS_PATH = playwrightBrowsersPath;
2260
2292
  }
2261
2293
  const url = `http://${host}:${port}`;
2262
- const launchQuery = options.launchUrlQuery ? options.launchUrlQuery.replace(/^\?+/, "") : "";
2263
- const launchUrl = launchQuery ? `${url}/?${launchQuery}` : url;
2294
+ const launchUrl = studioLaunchUrl(url, options);
2264
2295
  let childPid = 0;
2265
2296
  await withCliSpinner("Starting Tapi Studio", async () => {
2266
2297
  const child = spawn(exePath, [], {
@@ -2289,6 +2320,11 @@ async function launchPortableStudioServer(exePath, options, manifest) {
2289
2320
  openBrowser(launchUrl);
2290
2321
  console.log(`Opened Tapi Studio ${manifest.version}: ${launchUrl}`);
2291
2322
  }
2323
+ function studioLaunchUrl(baseUrl, options) {
2324
+ const normalizedBaseUrl = baseUrl.replace(/\/+$/, "");
2325
+ const launchQuery = options.launchUrlQuery ? options.launchUrlQuery.replace(/^\?+/, "") : "";
2326
+ return launchQuery ? `${normalizedBaseUrl}/?${launchQuery}` : normalizedBaseUrl;
2327
+ }
2292
2328
  export function findPortablePlaywrightBrowsersDir(exePath) {
2293
2329
  const exeDir = dirname(exePath);
2294
2330
  const releaseDir = basename(exeDir).toLowerCase() === "tapi-studio-server"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tapi-dev/sdk",
3
- "version": "0.1.24",
3
+ "version": "0.1.25",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",