@miosa/cli 1.0.86 → 1.0.88

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.
@@ -104,8 +104,9 @@ export function register(program) {
104
104
  console.log(JSON.stringify(data, null, 2));
105
105
  return;
106
106
  }
107
- const raw = unwrap(await client().apiGet(apiPath(`/sandboxes/${enc(id)}`)));
108
- const sb = (raw ?? {});
107
+ const sb = opts.port != null
108
+ ? await showSandboxWithPreview(id, opts.port, opts.probePath)
109
+ : (unwrap(await client().apiGet(apiPath(`/sandboxes/${enc(id)}`))) ?? {});
109
110
  printBanner({ subtitle: "Sandbox" });
110
111
  const rows = [
111
112
  { label: "ID", value: chalk.bold(str(sb["id"])), icon: icon.info },
@@ -142,6 +143,23 @@ export function register(program) {
142
143
  value: chalk.cyan(str(sb["public_url"])),
143
144
  });
144
145
  }
146
+ const preview = asRecord(sb["preview"]);
147
+ if (preview?.["url"]) {
148
+ rows.push({
149
+ label: "Preview URL",
150
+ value: chalk.cyan(str(preview["url"])),
151
+ });
152
+ rows.push({
153
+ label: "URL class",
154
+ value: str(preview["url_class"] ?? "temporary_preview"),
155
+ });
156
+ rows.push({
157
+ label: "Embeddable",
158
+ value: preview["stable_for_embedding"] === true
159
+ ? chalk.green("yes")
160
+ : chalk.yellow("temporary"),
161
+ });
162
+ }
145
163
  if (sb["created_at"]) {
146
164
  rows.push({
147
165
  label: "Created",
@@ -733,6 +751,7 @@ export function register(program) {
733
751
  return;
734
752
  }
735
753
  console.log(result.url);
754
+ printPreviewContractHint(result);
736
755
  if (!result.ready) {
737
756
  console.error(chalk.yellow(`Preview route created but not verified yet (${result.error ?? result.status ?? "pending"}).`));
738
757
  }
@@ -1810,6 +1829,9 @@ async function showSandboxWithPreview(sandboxId, port, probePath) {
1810
1829
  catch (err) {
1811
1830
  preview = {
1812
1831
  url: "",
1832
+ url_class: "temporary_preview",
1833
+ stable_for_embedding: false,
1834
+ recommended_next_action: "create_alias_or_publish",
1813
1835
  ready: false,
1814
1836
  status: null,
1815
1837
  latency_ms: null,
@@ -1822,6 +1844,10 @@ async function showSandboxWithPreview(sandboxId, port, probePath) {
1822
1844
  preview: {
1823
1845
  url: preview?.url || null,
1824
1846
  port,
1847
+ url_info: preview?.url_info ?? null,
1848
+ url_class: preview?.url_class ?? "temporary_preview",
1849
+ stable_for_embedding: preview?.stable_for_embedding ?? false,
1850
+ recommended_next_action: preview?.recommended_next_action ?? "create_alias_or_publish",
1825
1851
  route_ready: Boolean(preview?.url),
1826
1852
  tls_ready: preview?.ready ?? false,
1827
1853
  last_status: preview?.status ?? null,
@@ -1844,12 +1870,28 @@ async function previewSandbox(sandboxId, port, opts) {
1844
1870
  : await probePublicPreview(url, opts.probePath);
1845
1871
  return {
1846
1872
  url,
1873
+ url_class: stringField(exposed, "url_class") ??
1874
+ stringField(exposed, "class") ??
1875
+ "temporary_preview",
1876
+ stable_for_embedding: booleanField(exposed, "stable_for_embedding") ?? false,
1877
+ recommended_next_action: stringField(exposed, "recommended_next_action") ??
1878
+ "create_alias_or_publish",
1879
+ url_info: objectField(exposed, "url_info") ?? undefined,
1847
1880
  ready: edge.ok,
1848
1881
  status: edge.status,
1849
1882
  latency_ms: edge.latency_ms ?? null,
1850
1883
  error: edge.error,
1851
1884
  };
1852
1885
  }
1886
+ function printPreviewContractHint(result) {
1887
+ const urlClass = result.url_class ?? "temporary_preview";
1888
+ if (result.stable_for_embedding === true) {
1889
+ console.error(chalk.dim(`URL class: ${urlClass}, stable for embedding.`));
1890
+ return;
1891
+ }
1892
+ console.error(chalk.yellow(`URL class: ${urlClass}, temporary preview.`));
1893
+ console.error(chalk.dim(`For durable client use, next action: ${result.recommended_next_action ?? "create_alias_or_publish"}.`));
1894
+ }
1853
1895
  async function waitSandboxReady(sandboxId, port, probePath, timeoutSec) {
1854
1896
  const c = client();
1855
1897
  await waitForSandboxRunning(c, sandboxId, Math.min(timeoutSec, 120));
@@ -2006,10 +2048,18 @@ async function deploySandbox(localDir, opts) {
2006
2048
  const internal = await waitForInternalHttp(c, sandboxId, resolvedPort, resolvedProbePath, Math.min(opts.timeout, 60));
2007
2049
  deployStep(opts, "Creating public preview route");
2008
2050
  const exposed = await c.apiPost(apiPath(`/sandboxes/${enc(sandboxId)}/expose`), { port: resolvedPort, title: "app preview" });
2009
- const previewUrl = extractUrl(unwrap(exposed));
2051
+ const exposeData = unwrap(exposed);
2052
+ const previewUrl = extractUrl(exposeData);
2010
2053
  if (!previewUrl) {
2011
2054
  throw new UserError("Sandbox expose did not return a preview URL.");
2012
2055
  }
2056
+ const previewUrlInfo = objectField(exposeData, "url_info") ?? undefined;
2057
+ const previewUrlClass = stringField(exposeData, "url_class") ??
2058
+ stringField(exposeData, "class") ??
2059
+ "temporary_preview";
2060
+ const stableForEmbedding = booleanField(exposeData, "stable_for_embedding") ?? false;
2061
+ const recommendedNextAction = stringField(exposeData, "recommended_next_action") ??
2062
+ "create_alias_or_publish";
2013
2063
  if (opts.wait)
2014
2064
  deployStep(opts, "Checking public preview readiness");
2015
2065
  const edge = opts.wait
@@ -2037,6 +2087,10 @@ async function deploySandbox(localDir, opts) {
2037
2087
  sandbox_id: sandboxId,
2038
2088
  port: resolvedPort,
2039
2089
  preview_url: previewUrl,
2090
+ preview_url_info: previewUrlInfo,
2091
+ preview_url_class: previewUrlClass,
2092
+ stable_for_embedding: stableForEmbedding,
2093
+ recommended_next_action: recommendedNextAction,
2040
2094
  preview_ready: edge.ok,
2041
2095
  persistent: true,
2042
2096
  always_on: Boolean(opts.alwaysOn),
@@ -2149,6 +2203,25 @@ async function publishSandbox(sandboxId, opts) {
2149
2203
  extractUrl(deployment) ??
2150
2204
  stringField(data, "url") ??
2151
2205
  null;
2206
+ let urlInfo = objectField(response, "url_info") ??
2207
+ objectField(deployment, "url_info") ??
2208
+ objectField(data, "url_info") ??
2209
+ null;
2210
+ let urlClass = stringField(response, "url_class") ??
2211
+ stringField(response, "class") ??
2212
+ stringField(deployment, "url_class") ??
2213
+ stringField(deployment, "class") ??
2214
+ stringField(data, "url_class") ??
2215
+ stringField(data, "class") ??
2216
+ "durable_deployment";
2217
+ let stableForEmbedding = booleanField(response, "stable_for_embedding") ??
2218
+ booleanField(deployment, "stable_for_embedding") ??
2219
+ booleanField(data, "stable_for_embedding") ??
2220
+ true;
2221
+ let recommendedNextAction = stringField(response, "recommended_next_action") ??
2222
+ stringField(deployment, "recommended_next_action") ??
2223
+ stringField(data, "recommended_next_action") ??
2224
+ "attach_custom_domain";
2152
2225
  let deploymentProduct = stringField(response, "deployment_product") ??
2153
2226
  stringField(data, "deployment_product") ??
2154
2227
  stringField(deployment, "deployment_product") ??
@@ -2164,6 +2237,15 @@ async function publishSandbox(sandboxId, opts) {
2164
2237
  const waited = await waitForDeploymentReady(c, deploymentId, opts.timeout);
2165
2238
  state = stringField(waited, "state") ?? state;
2166
2239
  url = extractUrl(waited) ?? url;
2240
+ urlInfo = objectField(waited, "url_info") ?? urlInfo;
2241
+ urlClass =
2242
+ stringField(waited, "url_class") ??
2243
+ stringField(waited, "class") ??
2244
+ urlClass;
2245
+ stableForEmbedding =
2246
+ booleanField(waited, "stable_for_embedding") ?? stableForEmbedding;
2247
+ recommendedNextAction =
2248
+ stringField(waited, "recommended_next_action") ?? recommendedNextAction;
2167
2249
  deploymentProduct =
2168
2250
  stringField(waited, "deployment_product") ??
2169
2251
  stringField(asRecord(waited["metadata"]), "deployment_product") ??
@@ -2175,6 +2257,11 @@ async function publishSandbox(sandboxId, opts) {
2175
2257
  response["state"] = state;
2176
2258
  if (url)
2177
2259
  response["url"] = url;
2260
+ if (urlInfo)
2261
+ response["url_info"] = urlInfo;
2262
+ response["url_class"] = urlClass;
2263
+ response["stable_for_embedding"] = stableForEmbedding;
2264
+ response["recommended_next_action"] = recommendedNextAction;
2178
2265
  data["deployment"] = waited;
2179
2266
  data["promotion_pending"] = false;
2180
2267
  data["app_consistency_pending"] = false;
@@ -2196,6 +2283,10 @@ async function publishSandbox(sandboxId, opts) {
2196
2283
  release_id: releaseId,
2197
2284
  version_id: versionId,
2198
2285
  url,
2286
+ url_info: urlInfo ?? undefined,
2287
+ url_class: urlClass,
2288
+ stable_for_embedding: stableForEmbedding,
2289
+ recommended_next_action: recommendedNextAction,
2199
2290
  state,
2200
2291
  deployment_product: deploymentProduct,
2201
2292
  docker_deploy_host_id: dockerDeployHostId,
@@ -2220,7 +2311,7 @@ async function waitForDeploymentReady(c, deploymentId, timeoutSec) {
2220
2311
  await sleep(2000);
2221
2312
  }
2222
2313
  const lastState = last ? String(last["state"] ?? "unknown") : "unknown";
2223
- throw new UserError(`Deployment still building after ${timeoutSec}s — it may still finish. Re-check with \`miosa sandbox show ${deploymentId}\` or \`miosa deploy logs\`.`, `Last state: ${lastState}`);
2314
+ throw new UserError(`Deployment still building after ${timeoutSec}s — it may still finish. Re-check with \`miosa deploy show ${deploymentId}\` or \`miosa deploy logs ${deploymentId}\`.`, `Last state: ${lastState}`);
2224
2315
  }
2225
2316
  function parsePublishDatabase(value) {
2226
2317
  if (!value)
@@ -2258,6 +2349,12 @@ async function doctorSandbox(sandboxId, port, probePath) {
2258
2349
  exposeData = { error: err instanceof Error ? err.message : String(err) };
2259
2350
  }
2260
2351
  const previewUrl = extractUrl(exposeData);
2352
+ const urlClass = stringField(exposeData, "url_class") ??
2353
+ stringField(exposeData, "class") ??
2354
+ "temporary_preview";
2355
+ const stableForEmbedding = booleanField(exposeData, "stable_for_embedding") ?? false;
2356
+ const recommendedNextAction = stringField(exposeData, "recommended_next_action") ??
2357
+ "create_alias_or_publish";
2261
2358
  const edge = previewUrl
2262
2359
  ? await probePublicPreview(previewUrl, probePath)
2263
2360
  : { ok: false, status: null, error: "No preview URL returned" };
@@ -2275,6 +2372,10 @@ async function doctorSandbox(sandboxId, port, probePath) {
2275
2372
  edge_probe: edge,
2276
2373
  preview_ready: edge.ok,
2277
2374
  preview_url: previewUrl,
2375
+ url_info: objectField(exposeData, "url_info") ?? null,
2376
+ url_class: urlClass,
2377
+ stable_for_embedding: stableForEmbedding,
2378
+ recommended_next_action: recommendedNextAction,
2278
2379
  expose: exposeData,
2279
2380
  };
2280
2381
  }
@@ -2290,6 +2391,8 @@ function renderDoctorReport(report) {
2290
2391
  console.log(` ${chalk.bold("Preview ready")} ${report["preview_ready"] ? chalk.green("yes") : chalk.red("no")}`);
2291
2392
  if (report["preview_url"]) {
2292
2393
  console.log(` ${chalk.bold("Preview URL")} ${chalk.cyan(String(report["preview_url"]))}`);
2394
+ console.log(` ${chalk.bold("URL class")} ${report["url_class"]}`);
2395
+ console.log(` ${chalk.bold("Embeddable")} ${report["stable_for_embedding"] === true ? chalk.green("yes") : chalk.yellow("temporary")}`);
2293
2396
  }
2294
2397
  console.log();
2295
2398
  if (!report["preview_ready"]) {
@@ -3146,6 +3249,13 @@ function stringField(row, key) {
3146
3249
  const value = row?.[key];
3147
3250
  return typeof value === "string" && value.length > 0 ? value : null;
3148
3251
  }
3252
+ function booleanField(row, key) {
3253
+ const value = row?.[key];
3254
+ return typeof value === "boolean" ? value : null;
3255
+ }
3256
+ function objectField(row, key) {
3257
+ return asRecord(row?.[key]);
3258
+ }
3149
3259
  function isSandboxTarget(value) {
3150
3260
  const idx = value.indexOf(":");
3151
3261
  if (idx <= 0)