@kubb/studio 5.2.3 → 5.2.5

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.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { t as __name } from "./rolldown-runtime-CRm0XQPb.js";
2
- import { a as AgentPermissions, c as ClientInfo } from "./index-V3fjg2mj.js";
2
+ import { a as AgentPermissions, c as ClientInfo } from "./index-Dq2uq38g.js";
3
3
  import { Storage } from "unstorage";
4
4
  import { Config, Hookable, KubbHooks } from "@kubb/core";
5
5
  //#region src/api.d.ts
@@ -147,6 +147,11 @@ type StudioConnectedContext = {
147
147
  agent: string;
148
148
  };
149
149
  };
150
+ /**
151
+ * Fired once Studio confirms the `agent:connect` handshake was received and the session is fully
152
+ * registered. Distinct from `studio:connected`, which only means the socket is open.
153
+ */
154
+ type StudioReadyContext = Record<string, never>;
150
155
  type StudioDisconnectedContext = {
151
156
  /**
152
157
  * Why Studio ended the session.
@@ -187,6 +192,7 @@ declare global {
187
192
  interface KubbHooksRegistry {
188
193
  'studio:connecting': [ctx: StudioConnectingContext];
189
194
  'studio:connected': [ctx: StudioConnectedContext];
195
+ 'studio:ready': [ctx: StudioReadyContext];
190
196
  'studio:disconnected': [ctx: StudioDisconnectedContext];
191
197
  'studio:command:start': [ctx: StudioCommandStartContext];
192
198
  'studio:command:end': [ctx: StudioCommandEndContext];
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { t as __name } from "./rolldown-runtime-CRm0XQPb.js";
2
- import { isCommandMessage, isDisconnectMessage, isStudioPingMessage } from "./protocol.js";
2
+ import { isCommandMessage, isDisconnectMessage, isStudioPingMessage, isStudioReadyMessage } from "./protocol.js";
3
3
  import { createRequire } from "node:module";
4
4
  import { styleText } from "node:util";
5
5
  import { readFile, writeFile } from "node:fs/promises";
@@ -564,7 +564,7 @@ async function disconnect({ sessionId, token, studioUrl, slug }) {
564
564
  }
565
565
  //#endregion
566
566
  //#region package.json
567
- var version = "5.2.3";
567
+ var version = "5.2.5";
568
568
  //#endregion
569
569
  //#region src/hooks.ts
570
570
  /**
@@ -670,6 +670,20 @@ function toPluginName(packageName) {
670
670
  return packageName.split("/").pop() ?? packageName;
671
671
  }
672
672
  /**
673
+ * Adds the `@kubb/` scope a plugin's package carries but its `name` does not, the inverse of
674
+ * {@link toPluginName}. A name outside the `plugin-` convention is left alone, so a third-party
675
+ * plugin is not reported as one of Kubb's.
676
+ *
677
+ * @example
678
+ * ```ts
679
+ * toPackageName('plugin-ts') // '@kubb/plugin-ts'
680
+ * toPackageName('@acme/my-plugin') // '@acme/my-plugin'
681
+ * ```
682
+ */
683
+ function toPackageName(name) {
684
+ return name.startsWith("plugin-") ? `@kubb/${name}` : name;
685
+ }
686
+ /**
673
687
  * Derives the conventional named export for a `@kubb/*` plugin package from its package name.
674
688
  *
675
689
  * @example
@@ -1504,7 +1518,7 @@ const CONNECT_TIMEOUT_MS = 5e3;
1504
1518
  const eventSeqCounters = /* @__PURE__ */ new WeakMap();
1505
1519
  const require = createRequire(import.meta.url);
1506
1520
  async function resolvePeerDependencies(names) {
1507
- const uniqueNames = [...new Set(names)];
1521
+ const uniqueNames = [...new Set(names.map(toPackageName))];
1508
1522
  const peerDependencies = {};
1509
1523
  const missingDependencies = [];
1510
1524
  const versions = await Promise.all(uniqueNames.map(async (name) => {
@@ -1772,6 +1786,12 @@ function setupEventsStream(ws, hooks) {
1772
1786
  //#endregion
1773
1787
  //#region src/StudioSession.ts
1774
1788
  /**
1789
+ * How long the `agent:connect` handshake may go unacknowledged before `studio:ready` is given up
1790
+ * on for this open. A Studio that predates the ack never sends one, so this only ever produces a
1791
+ * warning, not a reconnect.
1792
+ */
1793
+ const READY_TIMEOUT_MS = 1e4;
1794
+ /**
1775
1795
  * Fills in a host's options: the hosted Studio URL, the current working directory, and every
1776
1796
  * permission off unless granted. Idempotent, so a reconnect can pass an already-resolved bag
1777
1797
  * back in.
@@ -1842,6 +1862,7 @@ var StudioSession = class {
1842
1862
  #disposed = false;
1843
1863
  #isGenerating = false;
1844
1864
  #heartbeatTimer;
1865
+ #readyTimer;
1845
1866
  #lastPongAt = Date.now();
1846
1867
  constructor(options) {
1847
1868
  this.#options = applyStudioDefaults(options);
@@ -1950,7 +1971,7 @@ var StudioSession = class {
1950
1971
  path: configPath,
1951
1972
  file: await this.#readConfigFileView(),
1952
1973
  plugins: config.plugins.map((plugin) => ({
1953
- name: `@kubb/${plugin.name}`,
1974
+ name: toPackageName(plugin.name),
1954
1975
  options: plugin.options ?? {}
1955
1976
  }))
1956
1977
  },
@@ -1975,10 +1996,24 @@ var StudioSession = class {
1975
1996
  });
1976
1997
  try {
1977
1998
  await this.#sendConnectedPayload();
1999
+ this.#waitForReady();
1978
2000
  } catch (error) {
1979
2001
  await this.#warn(`Failed to send the connect payload: ${getErrorMessage(error)}`);
1980
2002
  }
1981
2003
  }
2004
+ /**
2005
+ * Arms the timeout for Studio's `studio:ready` acknowledgement. Re-armed on every open, since a
2006
+ * command sent while the agent is not attached is lost either way (see `#sendConnectedPayload`),
2007
+ * so each reconnect needs its own fresh wait.
2008
+ */
2009
+ #waitForReady() {
2010
+ if (this.#disposed) return;
2011
+ clearTimeout(this.#readyTimer);
2012
+ this.#readyTimer = setTimeout(() => {
2013
+ this.#readyTimer = void 0;
2014
+ Promise.resolve(this.#warn(`Kubb Studio did not confirm the connection was ready within ${READY_TIMEOUT_MS}ms`)).catch(() => {});
2015
+ }, READY_TIMEOUT_MS);
2016
+ }
1982
2017
  #onOpen = () => void this.#handleOpen().catch(() => {});
1983
2018
  #onAbort = () => void this.#end({
1984
2019
  reason: "shutdown",
@@ -1998,6 +2033,8 @@ var StudioSession = class {
1998
2033
  dispose(reason = "cleanup") {
1999
2034
  clearInterval(this.#heartbeatTimer);
2000
2035
  this.#heartbeatTimer = void 0;
2036
+ clearTimeout(this.#readyTimer);
2037
+ this.#readyTimer = void 0;
2001
2038
  try {
2002
2039
  this.#ws?.close(1e3, reason);
2003
2040
  } catch {}
@@ -2032,6 +2069,12 @@ var StudioSession = class {
2032
2069
  this.#lastPongAt = Date.now();
2033
2070
  return;
2034
2071
  }
2072
+ if (isStudioReadyMessage(data)) {
2073
+ clearTimeout(this.#readyTimer);
2074
+ this.#readyTimer = void 0;
2075
+ await this.#hooks.callHook("studio:ready", {});
2076
+ return;
2077
+ }
2035
2078
  if (isDisconnectMessage(data)) {
2036
2079
  await this.#handleDisconnect(data.reason);
2037
2080
  return;